setodaNote CTF Writeup (Network)
この記事は setodaNote CTFのNetworkジャンルのWriteup記事です。
- Host (30pts, 296solves)
- tkys_never_die (50pts, 344solves)
- echo_request (120pts, 249solves)
- stay_in_touch (150pts, 160solves)
- yes_you_can (150pts, 68solves)
- digdig (200pts, 121solves)
- Logger (250pts, 115solves)
- tkys_not_enough (250pts, 80solves)
Host (30pts, 296solves)
問題ファイルは pcapファイル。
Wiresharkで開くと一つのHTTP通信だけが記録されていることがわかる。リクエストヘッダの Host:
がFLAG
flag{ctf.setodanote.net}
tkys_never_die (50pts, 344solves)
問題ファイルは pcapファイル。
Wiresharkで開くと、/flag.html
と/flag.png
にアクセスしているHTTPリクエストが記録されている。
flag.html
にはFLAGはなく、flag.png
にFLAGがありそう。
PNGをダウンロードしているHTTPレスポンスの "Portable Network Graphics" を右クリックして、"Export Packet Bytes" をクリックして、PNGをflag.pngというファイル名でエクスポートする。
エクスポートされた画像にFLAG
flag{a_treasure_trove}
echo_request (120pts, 249solves)
問題ファイルは pcapファイル。
echo requestといえばICMPなので、Wiresharkで開いてicmp
でフィルタしてみる
98bytesのICMP通信と60bytesのICMP通信がある。それぞれのICMPのデータ部を見ると、98bytesの通信はpingコマンドを実行したときに発生する通信と同じだが、60bytesの通信を見ると1byteしかデータがなく不審である。60bytesの通信のデータ部のHex dumpを見ていくと f,l,a… と変化しているので、これを取り出せば良さそう。
Wiresharkでこのデータ部を一つずつ目で見ていくのは非効率なので、tsharkの-T fields -e
を用いてデータを出力する。
$ tshark -r echo_request.pcap -Y 'icmp and frame.len == 60' -T fields -e data.data 2e 2e 2e 2e 2e 66 6c 61 ...
あとは出力されたデータをCyberChefなどで改行を消してASCIIに変換すれば良いが、LinuxだとOneLinerで取り出せるので楽。
$ tshark -r echo_request.pcap -Y 'icmp and frame.len == 60' -T fields -e data.data | tr -d '\n' | xxd -r -p .....flag{ICMP_Tunneling_T1095}.....
stay_in_touch (150pts, 160solves)
問題ファイルは pcapファイル。
SMTPとIMAPの通信が記録されているため、メールのやり取りを記録したキャプチャファイルだと思われる。SMTPはメール転送の部分は暗号化されており中身が見れないが、IMAPは平文で流れており中身が見れる。
適当なIMAPパケットを右クリックし、"Follow" -> "TCP Stream" を起動。メールのやり取りがUTF-8で行われているためデフォルトの状態だとASCIIでデコードするため読める状態ではないが、"Show data as" の部分を "UTF-8" に変えるとメールの中身が読めるようになる。
Follow TCP Stream画面左下の "Stream" の番号を変化させて他のメールを読んでいくと、Stream 12のメールにZIPファイルが添付されている。
CyberChefなどでBase64をデコードすると、直前の Content-Type
にも書かれているようにZIPファイルが復元できる。
ZIPファイルにはパスワードがかかっているが、ファイルが添付されているメールの本文に「パスワードは別に送ります。」と書いてあり、Steram 14にパスワードが書いてある。
このパスワードを使うとZIPが解凍出来てFLAG
flag{SoNtOkIhAmOuKaTaHoUmOtSuMuRuNoSa;)}
いわゆるPPAPを行うリスクを身を持って感じられる問題だったと思います。
yes_you_can (150pts, 68solves)
問題ファイルはpcapファイル、ではなくテキストのログファイル。
(1628245600.155918) vcan0 095#800007F400000017 (1628245600.157006) vcan0 1A4#000000080000003E (1628245600.157018) vcan0 1AA#7FFF00000000673F (1628245600.157020) vcan0 1B0#000F0000000175 (1628245600.157023) vcan0 1D0#000000000000000A (1628245600.158095) vcan0 166#D0320027 (1628245600.160232) vcan0 158#0000000000000028 (1628245600.160243) vcan0 161#000005500108002B (1628245600.160245) vcan0 191#010010A141001A (1628245600.160247) vcan0 133#00000000B6 ...
昨年のHoliday Hack ChallengeでCAN (Car Area Network) のログを解析する問題が出題されて、その時と同じフォーマットだったので、(問題名的にも)すぐにCANのログであることには気づけた。
ただ、ログをただ見ててもどこにFLAGがあるか見当がつかずアイディアもなかったので、ここでだいぶ時間を食った。
いろいろ考えて、とりあえずログを読み込んでリプレイ出来ないか試してみることにした。リプレイ出来る方法を探したところ @shutingrz 氏の以下のブログにとてもわかりやすくまとめられていた。
https://www.shutingrz.com/post/can-training-first/
ここにまとめられてる手順に沿ってCANのシミュレーション環境をKali Linux上に構築。シミュレータを起動し、CANのログをリプレイする。
./icsim vcan0 canplayer -I dump.log
ここでシミュレータを見ると速度の情報が変化してるので、速度情報で何かを伝えようとしているのでは?と推測した。
本来であればログの中からICSimの速度情報をしながら調べるのだろうが、これも@shutingrz 氏がブログにまとめてくれており、ID(ログ上では#
の前の値)が0x244
のログが速度情報のデータであることがわかる。
そこで、IDが 0x244
のログをgrepで抽出してみる。
$ grep -E "244#0000" ... (1628245605.005261) vcan0 244#0000006600 (1628245605.020564) vcan0 244#0000006600 (1628245605.035802) vcan0 244#0000006600 (1628245605.051115) vcan0 244#0000006600 (1628245605.061376) vcan0 244#0000006600 (1628245605.076673) vcan0 244#0000006600 (1628245605.091981) vcan0 244#0000006600 (1628245605.102269) vcan0 244#0000006600 ...
データ部が5bytesで、1-3byte目、5byte目が 00
のデータにASCIIぽい数字が入っている。この特徴のデータ抽出し、重複を取ってみる。0x66がf、0x6CがlなのでASCIIぽい。
$ grep -E " 244#000000[0-9A-Fa-f]{2}00" dump.log | cut -d'#' -f2 | uniq 0000000100 0000006600 0000006C00 0000006100 0000006700 0000007B00 0000006300 0000006100 0000006E00 0000005F00 0000006200 0000007500 0000007300 0000005F00 0000006800 0000006100 0000006300 0000006b00 0000006900 0000006E00 0000006700 0000007D00 0000000100
あとは4byte目だけ抜き取って、xxdでASCIIに戻せばFLAGが得られた。
$ grep -E " 244#000000[0-9A-Fa-f]{2}00" dump.log | cut -d'#' -f2 | uniq | sed -r 's/000000([0-9A-Fa-f]{2})00/\1/' | tr -d '\n' | xxd -r -p flag{can_bus_hacking}
digdig (200pts, 121solves)
問題ファイルはpcapファイル。
開くとDNS通信が記録されている。
3番目のパケットを見ると、00500000LFI2358AA31.setodanote.net
を名前解決しようとしている通信が見つかる。この名前解決の結果を見ると、103.101.116.102
となっている。
一見すると正常なアドレスを返しているように見えるが、Packet BytesでHex Dumpを見ると getf
となっており、何かのデータを送っているように見える。次のパケットも同様に確認してみるとHexの部分が lag
となっており、getflag
と送っているのがわかる。
このように、長いサブドメインの名前解決やレスポンスに意味のあるデータが含まれているのはDNSトンネリングで使われる手法である。名前解決AレコードとAAAAレコードで行われているが、今回の問題ファイルにはAAAAレコードの名前解決のレスポンスには特に意味のあるデータが含まれてないので、dns.qry.type == 1
でフィルタする。
フィルタ後、改めて名前解決しているドメインを見ると、005aa0
で始まるドメインの名前解決を大量に行っている。これらのサブドメインは毎回微妙に異なっているため、何かのデータを送っていると推測できる。
tsharkでこの名前解決を行っているドメインを引っこ抜いて、サブドメインの部分を抽出してみる。
$ tshark -r digdig.pcap -Y "ip.addr == 192.168.224.20 and dns.qry.type == 1 and dns.a == 172.16.107.128" -T fields -e dns.resp.name | cut -d'.' -f1 005aa002735f69735f44414d 005aa00663655f7472795f53 005aa0034d595f464c41477d 005aa0085f746861747d2066 005aa00a6c61677b444e535f 005aa00b5333637572313779 005aa0076f7272795f666f72 005aa00420666c6167206973 005aa0096c61672069732066 005aa00c5f5431303731217d 005aa011797d323232323232 005aa00d20666c6167206973 005aa00f335f6b33795f3135 005aa00e20666c61677b3768 005aa001666c61677b546869 005aa0105f35336375723137 005aa000666c616720697320 005aa00520666c61677b4e69
出力結果をCyberChefに入れて、Hexdumpを見てみる
flagのようなデータが見えるが正しい順番になってなさそう。
Hexをよく見ると4byte目が0x00~0x11のデータになっているので、この番号順にデータを並び替えてみる。(ここは手動で頑張った
flag is flag{This_is_DAMMY_FLAG} flag is flag{Nice_try_Sorry_for_that} flag is flag{DNS_S3cur17y_T1071!} flag is flag{7h3_k3y_15_53cur17y}222222
いくつかdummyのFLAGがあるが、flag{DNS_S3cur17y_T1071!}
がFLAGだった。
flag{DNS_S3cur17y_T1071!}
flag{}
がFLAGのフォーマットですって言っておいて、flag{}
のフォーマットのdummyを混ぜるのは如何なものかと思った。。
Logger (250pts, 115solves)
問題ファイルはpcapファイル。
Wiresharkで開くと、USBとのデータのやり取りが記録されていることがわかる。
USBの通信データというと、PCとUSBメモリのデータをやり取りやマウスやキーボードのやり取りが記録されていることが考えられるが、大きな通信データをやり取りはしてないので、キーボードやマウスのやり取りであると考えられる。
キーボードやマウスなどのUSBデバイスは、デバイスからデータを送信するので、2.1.1(USBデバイスのアドレス)からhostへ送られているデータを見てみる。Leftover Capture Data
の1byte目と3byte目が変化しており、これはUSBキーボードでキーを打った時のデータである。
ちなみに自分の著書である「セキュリティコンテストのためのCTF問題集」で紹介している問題の類題だったので、見た瞬間すぐにわかった(宣伝)
今回は本で紹介したsolverを流用して問題を解いた。(solverがなぜこうなるかは、本を読んでもらうか、他のサイトを見てもらいたい…
本に載ってるsolverはPython 2系で動くように書いたいたので、Python 3系で動くように修正して使用した。
#! /usr/bin/env python3 #! -*- coding: utf-8 -*- from scapy.all import * keymap = { 0x04: ('a', 'A'), 0x05: ('b', 'B'), 0x06: ('c', 'C'), 0x07: ('d', 'D'), 0x08: ('e', 'E'), 0x09: ('f', 'F'), 0x0a: ('g', 'G'), 0x0b: ('h', 'H'), 0x0c: ('i', 'I'), 0x0d: ('j', 'J'), 0x0e: ('k', 'K'), 0x0f: ('l', 'L'), 0x10: ('m', 'M'), 0x11: ('n', 'N'), 0x12: ('o', 'O'), 0x13: ('p', 'P'), 0x14: ('q', 'Q'), 0x15: ('r', 'R'), 0x16: ('s', 'S'), 0x17: ('t', 'T'), 0x18: ('u', 'U'), 0x19: ('v', 'V'), 0x1a: ('w', 'W'), 0x1b: ('x', 'X'), 0x1c: ('y', 'Y'), 0x1d: ('z', 'Z'), 0x1e: ('1', '!'), 0x1f: ('2', '@'), 0x20: ('3', '#'), 0x21: ('4', '$'), 0x22: ('5', '%'), 0x23: ('6', '^'), 0x24: ('7', '&'), 0x25: ('8', '*'), 0x26: ('9', '('), 0x27: ('0', ')'), 0x28: ('\x0a', '\x0a'), 0x29: ('\x1b', '\x1b'), 0x2a: ('\x08', '\x08'), 0x2b: ('\x09', '\x09'), 0x2c: ('\x20', '\x20'), 0x2d: ('-', '_'), 0x2e: ('=', '+'), 0x2f: ('[', '{'), 0x30: (']', '}'), 0x31: ('\\', '|'), 0x33: (';', ':'), 0x34: ("\'", '\"'), 0x35: ('`', '~'), 0x36: (',', '<'), 0x37: ('.', '>'), 0x38: ('/', '?') } def read_usbdata_from_pcap(): pcap = rdpcap("logger.pcap") usb_data = [] for pkt in pcap: buf = pkt['Raw'].load if buf[22] == 1: usb_data.append(buf[27:]) return usb_data def analyze_usb_data(usb_data): flag = "" for d in usb_data: if len(d) == 0: continue if d[2] == 0 or not(0 in d[3:8]): # No Event continue if d[0] == 2 or d[0] == 32: # press shift-key # binary -> int c = keymap[ord(chr(d[2]))][1] flag += c else: # Not press shift-key # binary -> int c = keymap[ord(chr(d[2]))][0] flag += c print(flag) def main(): data = read_usbdata_from_pcap() analyze_usb_data(data) if __name__ == '__main__': main()
solverを動かすと以下のような文字を打っていることが復元でき、FLAGがわかる。
One popular bbut unverified explanatioon for the QWERTY arrangement is that it wwas designed to reduce the likelihood of flag{QWE_keyb0ard_RTY} internal clashhing of typebars by placing commonly ussed combinatiioons of letters farther froom each oher inside the machine.
FLAG
flag{QWE_keyb0ard_RTY}
tkys_not_enough (250pts, 80solves)
問題ファイルはpcapファイル、と思いきやWiresharkで開いてみると「Wiresharkで開けるフォーマットで無い」と怒られる。
fileコマンドでファイルの種類を見てみる。よくわからないフォーマット。
$ file tkys_not_enough.pcap tkys_not_enough.pcap: dBase III DBT, version number 0, next free block index 524288, 1st item "e"
次にバイナリエディタで見てみる。少し見ていくと、マルチバイトで文字が記録されており、Windowsのpathのようなものが見えるので、Windows環境で取得したデータでないかと予測がつく。
ここで、「そういえば、WindowsでWiresharkが入ってなくてもパケットキャプチャする方法があったなぁ」というのを思い出す。具体的には netsh trace start capture=yes
とコマンドを実行することで、ETL形式で保存される。
https://www.vwnet.jp/Windows/WS16/2017013001/PacketCapture.htm
ETL形式のファイルはMicrosoftがGitHubで公開している変換ツールを使用することで、Wiresharkで開くことができるpcapngに変換できる。
https://github.com/microsoft/etl2pcapng
> etl2pcapng.exe tkys_not_enough.etl tkys_not_enough.pcapng IF: medium=eth ID=0 IfIndex=15 Converted 58 frames
Wiresharkで開いてみると、500/tcpへの通信がいくつか記録されている。IPsecで使用されるISAKMPプロトコルとして認識され、いくつかのパケットはMalformed Packetとなっているが、画面下部のPacket Bytesでバイナリを見ると実際はHTTP通信であることがわかる。
これはWiresharkが本来500/tcpを使用するISAKMPとして誤って解析している結果である。該当のパケットを右クリックして、"Decode As…" を選択、正しいプロトコルとして認識させてあげる。
以上のような設定にすると、Wiresharkが正しくHTTPとして認識してくれてパケットを読むことができる。
あとは、正しく読めるようになったHTTPパケットを読んでいくと、FLAGを見つけることができる。(普通に平文でFLAGが置いてあるように見えるが、gzipで圧縮されていたのでstringsでは超能力者じゃない限りは見つけることができない。
FLAG
flag{netw0rk_shell_2000}
パケットキャプチャというと pcapフォーマットが使われていることが多いのでpcapのイメージが強いと思うが、このように他にも通信を記録するフォーマット(手段)があるというのは非常に勉強になる問題だったと思う。