今年もSECON BeginnersのOB(?)として、SECCON Beginners CTF 2019の作問とレビューに参加してました。
私が作ったのは MiscのDumpで、最終的には163チームに解いてもらい、138ptsの問題でした。
問題解いてくださったみなさま、ありがとうございます。
それでは、Dumpについて解説していきたいと思います。
Writeup
まずは file
コマンドを使用してファイルの種類を判別。
$ file fc23f13bcf6562e540ed81d1f47710af_dump fc23f13bcf6562e540ed81d1f47710af_dump: tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 262144)
みんな大好きpcapファイルなので、拡張子に .pcap
をつけて Wiresharkで中身を見てみましょう。
Wiresharkでpcapを解析
pcapファイルには2つのHTTPの通信が記録されている。
この2つの通信について、Wiresharkの Follow HTTP Stream
機能を実行してみる。
(Follow TCP Stream
を使ってTCPレベルでパケットをreassembleすると、HTTPレスポンスヘッダのTransfer-Encoding: chunked
を認識しないためchunkの長さを示すデータが入ってしまう)
1つ目のコネクション
GET /webshell.php?cmd=ls%20%2Dl%20%2Fhome%2Fctf4b%2Fflag HTTP/1.1 Host: 192.168.75.230 User-Agent: curl/7.54.0 Accept: */* HTTP/1.1 200 OK Date: Sun, 07 Apr 2019 11:55:16 GMT Server: Apache/2.4.18 (Ubuntu) Vary: Accept-Encoding Content-Length: 130 Content-Type: text/html; charset=UTF-8 <html> <head> <title>Web Shell</title> </head> <pre> -rw-r--r-- 1 ctf4b ctf4b 767400 Apr 7 19:46 /home/ctf4b/flag </pre> </html>
2つ目のコネクション
GET /webshell.php?cmd=hexdump%20%2De%20%2716%2F1%20%22%2502%2E3o%20%22%20%22%5Cn%22%27%20%2Fhome%2Fctf4b%2Fflag HTTP/1.1 Host: 192.168.75.230 User-Agent: curl/7.54.0 Accept: */* HTTP/1.1 200 OK Date: Sun, 07 Apr 2019 11:55:27 GMT Server: Apache/2.4.18 (Ubuntu) Vary: Accept-Encoding Transfer-Encoding: chunked Content-Type: text/html; charset=UTF-8 <html> <head> <title>Web Shell</title> </head> <pre> 037 213 010 000 012 325 251 134 000 003 354 375 007 124 023 133 327 007 214 117 350 115 272 110 047 012 212 122 223 320 022 252 164 220 052 275 051 204 044 100 050 011 044 024 101 120 274 166 244 010 010 050 315 002 110 023 024 244 012 330 005 351 012 012 322 024 245 011 202 205 242 202 212 337 204 216 242 357 175 336 …
これにより以下のことが推測できる。
webshell.php
というファイル名からWebShellを利用してコマンドを実行- パラメータ
cmd
で指定したコマンドの結果を、<pre>...</pre>
に表示 - 1つ目が
ls
コマンドの出力結果、2つ目がhexdump
コマンドの出力結果
また、cmd
パラメータはURLエンコードされていて、2つ目のHTTP通信の cmd
パラメータの値をURLデコードすると以下のような文字列となる。
hexdump -e '16/1 "%02.3o " "\n"' /home/ctf4b/flag
このサイトなどを参考にすると、-e
オプションで出力するフォーマットを指定していて、8進数で flag
ファイルのバイナリをdumpしていることがわかる。
よって、次のような方針で問題を解く。
- 2つ目の
<pre> ... </pre>
タブで囲まれた文字列を抽出 - 8進数でdumpされたデータを変換してバイナリファイルにする
solverを書く
pcapから <pre> ... </pre>
の部分を抜き出すのはWiresharkを使用しても良いが、WiresharkのCUI版であるtsharkを使用すると簡単に抽出できる。
$ tshark -r fc23f13bcf6562e540ed81d1f47710af_dump.pcap -q -z follow,http,ascii,1
このコマンドをプログラム中から実行し Follow HTTP Stream
の結果を加工、バイナリファイルとして保存するsolverを書く。
# -*- coding: utf-8 -*- import sys import subprocess import re # tsharkの出力結果を読み込み command = ["tshark","-r","fc23f13bcf6562e540ed81d1f47710af_dump.pcap","-q","-z","follow,http,ascii,1"] raw = subprocess.run(command, stdout=subprocess.PIPE, text=True) # 正規表現とstrip, repalace, split を使用してデータの整形 data = re.findall('<pre>((.|\s)*?)</pre>', raw.stdout)[0][0] data = data.strip().replace("\n"," ").split(" ") # 8進数の文字列からbyte型のデータへ変換 res = b"" for d in data: res += int(d,8).to_bytes(1,"little") # 変換したデータをファイルに書き込み with open("flag.bin","wb") as f: f.write(res)
出力したファイルの種類を調べる
file
コマンドで出力したファイルの種類を調べる。
$ file .flag.bin flag.bin: gzip compressed data, last modified: Sun Apr 7 10:46:34 2019, from Unix, original size 798720
tar.gz
形式のファイルなので、tar
コマンドを実行して展開。
$ tar xzvf flag.bin x ./._flag.jpg x flag.jpg
flag.jpgにFLAG
ctf4b{hexdump_is_very_userful}
ちなみに、これは今年の4月に上野公園で撮影した桜の写真です。
あとで気づいたのですが、撮影に使用したカメラやレンズ、現像ソフトウェアの情報を消し忘れたので、exiftool
等を使うと私の撮影環境ががわかります(誰得…
おわりに
この問題は、何らかの方法で攻撃者がWebサーバ上にWebShellを設置、そのWebShellを使って外部に情報を持ち出すというシナリオを想定して作りました。 ただ、実際の攻撃の通信は暗号化や難読化されていて、パケット解析とスクリプト作成で持ち出された情報を復元するのは一筋縄では行かないかもしれません。
近年のCTFではパケットを読むような問題はほとんど出ませんが、パケット解析スキルやスクリプト作成スキルはCTF(や、ITエンジニアのお仕事)をやる上で知っておいた方が良いベーシックスキルの一つだと思います。今回の問題が参加されたみなさまのパケット解析スキルやスクリプト作成スキルの向上に少しでもお役に立てていれば幸いです。