chroot("/home/hibari")

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

【SECCON 2018】おそらく普通でないSpecial InstructionsのWriteup

SECCON 2018 online CTF 予選お疲れ様でした.

今年も予選に参加させていただきまして,自分はRevの2問(Special Instructions, Special Device)を解きました.

 

その中でもSpecial Instructionsについては,非常に頭悪く解いたためにWriteup書かなくてもいいかなどと考えていましたが,解けた時の謎の達成感があったため,書きたくなりました.

書いていきます.

 

Special Instruction

きっと他のプロの方達が丁寧でわかりやすいWriteupを書いてくださっていると思うので,事細かな詳細についてはそちらをご覧ください.

ものすごくざっくりと書くと,

バイナリが渡されるのだが,*unknown arch 0xdf* な実行ファイルであるためネイティブに実行させることはほぼ無理でしょうねーというもの.

そのためまずこれがなんのアーキテクチャの実行ファイルなのかを特定することから始まります.

結論から言うとMoxieアーキテクチャの実行ファイルでした.

そうと分かればあとはそれ用のobjdumpにかけてバイナリを読めば雰囲気は掴めるはず!

これまたざっくり書くとSEEDをxorshift32にかけた値とrandval, そしてflagの値をXORしたものを1byteずつ書き込んでフラグを作っているみたいです.

よーーーしエミュレートさせたら勝ちなんじゃないの!とやったのですが,Illegal Instructionで落ちます.

set_random_seedやget_random_value関数がそれぞれ0x16, 0x17という特殊な(架空の)命令で実装されているらしいです.

つまりこの命令が再現できるようにしないとフラグが取れないわけです.

というわけで,

 

そうと決まれば!!!!この命令を再現しよう!!!!

 

 

中で!!!!!!!

 

 

 

今思えば普通にCなりPythonなりで実装すればよかったと後悔していなくもないですが,やってしまったものは仕方ない.楽しいし?

なにをやったかと言えば,ひとことで言うと「0x16,0x17を再現するバイナリを直接書いた」です.

どこに書いたかというと,main関数の中でやたら文字列出そうとたくさん命令を吐いている部分があります.そこです.この部分はフラグ取得の演算とは全く関係ないので無慈悲に上書きしましょう.

 

解析しつつバイナリ書いたりしつつで分かったのですが,Moxieバイナリはとても書きやすいです.

命令部は全て1byteに固定されていますし,オペランドとなるレジスタ指定も4bitが2つで簡単に決められるため簡単な暗算でバイトコードが記述できます.

細かい違いはありますが,主な命令体系は以下の2タイプ

 

1.XX AB

2.XX Ax ii ii ii ii 

 

xxで1byteを表しています.

Xは命令,A,Bはそれぞれレジスタ,iは即値,xはdon't careとなっています.

レジスタ指定について,レジスタは$fp, $sp, $r0, $1, ..., $13の16個あります.そしてこの順番で設定されています.つまり,A = 0x2であれば$r0,A = 0xaであれば$r8といった具合です.

 

 

内部の実装

これでみんなMoxieの簡単なバイトコードが読める / 書けるようになったと思うので実装編行きましょう.

内部の実装は0x17命令(つまりxorshift32をしてくれる関数)をmainに図々しく上書きするだけです.

いきなりバイトコードで書くとしんどい思いしそうなので,まずはやりたいことをアセンブリ言語で記述します.簡単に書くと以下のようになりました.

ldi.l $r2, 0x1640
ld.l $r0, ($r2)
mov $r3, $r0
ldi.l $r4, 0xd
ashl $r3, $r4
xor $r0, $r3
mov $r3, $r0
ldi.l $r4, 0x11
lshr $r3, $r4
xor $r0, $r3
mov $r3, $r0
ldi.l $r4, 0xf
ashl $r3, $r4
xor $r0, $r3
st.l ($r2), $r0
ret

 

あとはこれに則ったバイトコードを記述して,前後関係をよしなにしてあげるだけです.この部分だけの出来上がったバイトコードは以下です.

01 40 00 00 16 40 0a 24 02 52 01 60 00 00 00 0d 28 56 2e 25 02 52 01 60 00 00 00 11 27 56 2e 25 02 52 01 60 00 00 00 0f 28 56 2e 25 0b 42 04 00

この通りとても簡単に関数が実装できます.前後関係をよしなにするために他にもバイナリを書き換えていますが,実装の心臓部は上のコードだけです.

最後に実行結果の写真を載せます.

Illegal Instructionで落ちないぞ!flagが出てくるバイナリができたぞ!

というわけでSECCON{MakeSpecialInstructions}がフラグです.

実際にSpecial InstructionをMakeしているから,出題者の意図は汲んでいるよね????

 

f:id:lcstmarck:20181030001155j:plain

 

というわけで簡単にはなりましたが以上になりますー,お疲れ様でした!