fmsctf勉強会 #11

6月末にfmsctf #03を開催することになりました

それに向けて、主にB1を対象に毎週土曜日に勉強会を行うことになり、その第1回目が6/6に行われました

atnd.org

なんだかんだでB1以外にも幾人か参加していたようで、最終的には10人ちょっといたような…?


特になにをやるか決めていなかったので、その場でアンケートを取ってやったんですが、Processing基礎文法→バイナリ解析入門みたいな感じでした

バイナリ解析をするといっても簡単なプログラムをCで書いて、それをデバッグして遊んでみるという感じでやったのですが、B1はHSPしかやったことがない人が殆どだったので、文法的にHSPより似ている部分があるし、これから授業でやるということで、Processingの基礎文法をサラーっとおさらいすることにしました

Processing基礎文法入門に関しては前年度末にやったときの資料をそのまま利用したので割愛しますが、ifとかforとか関数定義とか出来れば大丈夫でしょって感じ


バイナリ解析はFedora22でC書いてgccコンパイルしてgdbデバッグするような感じです

やった内容をテキトーに纏めておきます


まずこんな感じのコードを書きます

#include <stdio.h>

int main(){
	printf("AAAA");
	return 0;
}

コンパイルし、動作を確認し、gdbデバッグします

[fmsctf@arckty tmp]$ gcc ./b01.c -o b01
[fmsctf@arckty tmp]$ ./b01
AAAA[fmsctf@arckty tmp]$ gdb -q ./b01
Reading symbols from ./b01...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
   0x0804842b <+0>:	lea    ecx,[esp+0x4]
   0x0804842f <+4>:	and    esp,0xfffffff0
   0x08048432 <+7>:	push   DWORD PTR [ecx-0x4]
   0x08048435 <+10>:	push   ebp
   0x08048436 <+11>:	mov    ebp,esp
   0x08048438 <+13>:	push   ecx
   0x08048439 <+14>:	sub    esp,0x4
   0x0804843c <+17>:	sub    esp,0xc
   0x0804843f <+20>:	push   0x80484e4
   0x08048444 <+25>:	call   0x80482f0 <printf@plt>
   0x08048449 <+30>:	add    esp,0x10
   0x0804844c <+33>:	mov    eax,0x0
   0x08048451 <+38>:	mov    ecx,DWORD PTR [ebp-0x4]
   0x08048454 <+41>:	leave  
   0x08048455 <+42>:	lea    esp,[ecx-0x4]
   0x08048458 <+45>:	ret    
End of assembler dump.
(gdb) x/s 0x80484e4
0x80484e4:	"AAAA"

disasしてprintfをcallする直前にpushされているものを表示してみると

printf("AAAA");

であることが分かります


次にこんな感じのコードを書きます

#include <stdio.h>

int main(){
	int i = 16;
	printf("%d", i);
	return 0;
}

コンパイルし、動作を確認し、gdbデバッグしていきます

[fmsctf@arckty tmp]$ gcc ./b02.c -o b02
[fmsctf@arckty tmp]$ ./b02
16[fmsctf@arckty tmp]$ gdb -q ./b02
Reading symbols from ./b02...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
   0x0804842b <+0>:	lea    ecx,[esp+0x4]
   0x0804842f <+4>:	and    esp,0xfffffff0
   0x08048432 <+7>:	push   DWORD PTR [ecx-0x4]
   0x08048435 <+10>:	push   ebp
   0x08048436 <+11>:	mov    ebp,esp
   0x08048438 <+13>:	push   ecx
   0x08048439 <+14>:	sub    esp,0x14
   0x0804843c <+17>:	mov    DWORD PTR [ebp-0xc],0x10
   0x08048443 <+24>:	sub    esp,0x8
   0x08048446 <+27>:	push   DWORD PTR [ebp-0xc]
   0x08048449 <+30>:	push   0x80484f4
   0x0804844e <+35>:	call   0x80482f0 <printf@plt>
   0x08048453 <+40>:	add    esp,0x10
   0x08048456 <+43>:	mov    eax,0x0
   0x0804845b <+48>:	mov    ecx,DWORD PTR [ebp-0x4]
   0x0804845e <+51>:	leave  
   0x0804845f <+52>:	lea    esp,[ecx-0x4]
   0x08048462 <+55>:	ret    
End of assembler dump.

+17でebp-0xcに0x10をmovしてます

+35でprintfをcallしてるんですが、その直前で2つpushしていて、それがprintfの引数になっています

引数にebp-0xcが渡されていて、それはつまり0x10ですね

こんな感じで

int i = 16;
printf("%d", i);

となっているのが分かります


次にこんな感じのプログラムを書いてみます

#include <stdio.h>

int main(){
	int i = 16;
	int j = 32;
	
	int k = i + j;
	printf("%d", k);
	
	return 0;
}

コンパイルし、動作を確認し、gdbデバッグしていきます
まずdisasしてみると

[fmsctf@arckty tmp]$ gcc ./b03.c -o b03
[fmsctf@arckty tmp]$ ./b03
48[fmsctf@arckty tmp]$ gdb -q ./b03
Reading symbols from ./b03...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
   0x0804842b <+0>:	lea    ecx,[esp+0x4]
   0x0804842f <+4>:	and    esp,0xfffffff0
   0x08048432 <+7>:	push   DWORD PTR [ecx-0x4]
   0x08048435 <+10>:	push   ebp
   0x08048436 <+11>:	mov    ebp,esp
   0x08048438 <+13>:	push   ecx
   0x08048439 <+14>:	sub    esp,0x14
   0x0804843c <+17>:	mov    DWORD PTR [ebp-0xc],0x10
   0x08048443 <+24>:	mov    DWORD PTR [ebp-0x10],0x20
   0x0804844a <+31>:	mov    edx,DWORD PTR [ebp-0xc]
   0x0804844d <+34>:	mov    eax,DWORD PTR [ebp-0x10]
   0x08048450 <+37>:	add    eax,edx
   0x08048452 <+39>:	mov    DWORD PTR [ebp-0x14],eax
   0x08048455 <+42>:	sub    esp,0x8
   0x08048458 <+45>:	push   DWORD PTR [ebp-0x14]
   0x0804845b <+48>:	push   0x8048504
   0x08048460 <+53>:	call   0x80482f0 <printf@plt>
   0x08048465 <+58>:	add    esp,0x10
   0x08048468 <+61>:	mov    eax,0x0
   0x0804846d <+66>:	mov    ecx,DWORD PTR [ebp-0x4]
   0x08048470 <+69>:	leave  
   0x08048471 <+70>:	lea    esp,[ecx-0x4]
   0x08048474 <+73>:	ret    
End of assembler dump.

こんな感じになっていて、+31でedxに0x10、+34でeaxに0x20がmovされ、+37でeax+=edxを計算しています

試しに+39にブレークポイントを仕掛け、演算結果を書き換えてみると

(gdb) b *main+39
Breakpoint 1 at 0x8048452
(gdb) run
Starting program: /tmp/b03 
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.21-5.fc22.i686

Breakpoint 1, 0x08048452 in main ()
(gdb) i r eax
eax            0x30	48
(gdb) set $eax = 0x40
(gdb) i r eax
eax            0x40	64
(gdb) c
Continuing.
64[Inferior 1 (process 3233) exited normally]

こんな感じで出力される値を書き換えることが出来ます


同じような感じでif文で遊んでみましょう

こんな感じのコードを書いてみます

#include <stdio.h>

int main(){
	int i = 16;
	int j = 32;
	
	if(i == j){
		printf("ok");
	}else{
		printf("no");
	}
	
	return 0;
}

これをコンパイルし、実行すると当然「no」と表示されます

[fmsctf@arckty tmp]$ gcc ./b04.c -o b04
[fmsctf@arckty tmp]$ ./b04
no

okと表示させるにはどうすれば良いでしょうか?

取り敢えずdisasしてみます

[fmsctf@arckty tmp]$ gdb -q ./b04
Reading symbols from ./b04...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
   0x0804842b <+0>:	lea    ecx,[esp+0x4]
   0x0804842f <+4>:	and    esp,0xfffffff0
   0x08048432 <+7>:	push   DWORD PTR [ecx-0x4]
   0x08048435 <+10>:	push   ebp
   0x08048436 <+11>:	mov    ebp,esp
   0x08048438 <+13>:	push   ecx
   0x08048439 <+14>:	sub    esp,0x14
   0x0804843c <+17>:	mov    DWORD PTR [ebp-0xc],0x10
   0x08048443 <+24>:	mov    DWORD PTR [ebp-0x10],0x20
   0x0804844a <+31>:	mov    eax,DWORD PTR [ebp-0xc]
   0x0804844d <+34>:	cmp    eax,DWORD PTR [ebp-0x10]
   0x08048450 <+37>:	jne    0x8048464 <main+57>
   0x08048452 <+39>:	sub    esp,0xc
   0x08048455 <+42>:	push   0x8048514
   0x0804845a <+47>:	call   0x80482f0 <printf@plt>
   0x0804845f <+52>:	add    esp,0x10
   0x08048462 <+55>:	jmp    0x8048474 <main+73>
   0x08048464 <+57>:	sub    esp,0xc
   0x08048467 <+60>:	push   0x8048517
   0x0804846c <+65>:	call   0x80482f0 <printf@plt>
   0x08048471 <+70>:	add    esp,0x10
   0x08048474 <+73>:	mov    eax,0x0
   0x08048479 <+78>:	mov    ecx,DWORD PTR [ebp-0x4]
   0x0804847c <+81>:	leave  
   0x0804847d <+82>:	lea    esp,[ecx-0x4]
   0x08048480 <+85>:	ret    
End of assembler dump.

ボーっと見てみるとこの辺が怪しい感じ…

0x0804844d <+34>:	cmp    eax,DWORD PTR [ebp-0x10]
0x08048450 <+37>:	jne    0x8048464 <main+57>
...
0x08048462 <+55>:	jmp    0x8048474 <main+73>

どうやらcmpで値を比較し、ジャンプさせることで処理を分岐させているようです

このページなどを見れば分かりやすいんですが、cmpは結果をeflagsというものに格納します
もう一度基礎からC言語 第10回 制御構造と変数(6)~if、for、whileをアセンブリ言語で 値を調べ処理を切り替える

jneは比較されたものと比較したものが等しくなければジャンプするという命令で、eflagsで判断しています

eflagsについてはこのページなどを見ると分かりやすいかも
X86アセンブラ/x86アーキテクチャ - Wikibooks

通常の処理を追ってみましょう
+37でジャンプする直前で処理を停止し、ZFが立っているかどうか見てみると

(gdb) b *main+37
Breakpoint 1 at 0x8048450
(gdb) run
Starting program: /tmp/b04 
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.21-5.fc22.i686

Breakpoint 1, 0x08048450 in main ()
(gdb) i r eflags
eflags         0x287	[ CF PF SF IF ]

このようにZFが立っておらず、CFが立っています
つまり比較結果として、値は同じではなかったということですね

ここでCFをOFFにして、ZFを立ててみます

(gdb) set $eflags = 0x246
(gdb) i r eflags
eflags         0x246	[ PF ZF IF ]

これで最後まで処理を進行させてみると

(gdb) c
Continuing.
ok[Inferior 1 (process 3438) exited normally]

このようにokが出力されます


こんな感じでif文をゴニョゴニョすることが可能です

でもこんな面倒なことしなくても

0x0804844d <+34>:	cmp    eax,DWORD PTR [ebp-0x10]

この部分でeaxとebp-0x10を比較していることが分かっているので

(gdb) b *main+34
Breakpoint 1 at 0x804844d
(gdb) run
Starting program: /tmp/b04 
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.21-5.fc22.i686

Breakpoint 1, 0x0804844d in main ()
(gdb) i r eax
eax            0x10	16
(gdb) x/x $ebp-0x10
0xbffff068:	0x00000020
(gdb) x/d $ebp-0x10
0xbffff068:	32
(gdb) set $eax = 32
(gdb) c
Continuing.
ok[Inferior 1 (process 3467) exited normally]

こんな感じで値を同じにしてあげれば当然条件文はtrueになります


簡単にですが、実行可能ファイルをデバッグし、処理を変更させることが出来たりすることが分かったでしょうか?

このあと勉強会ではWindows環境でアンチデバッグ技術としてIsDebuggerPresent()を紹介し、IsDebuggerPresent()がどうやって動作しているのかデモをしました

加えて遊びですが、書式文字列攻撃がどんな感じでやってるのかとか、その辺もテキトーにやったり…


勉強会に関しては以上です



勉強会後、みんなで🍕を食べました

B2が🍕を取りに行ってる間にB1がProcessingで🍕を作ったり…



3846先輩も便乗して発表したり…

猫も書いてたり…


こんな感じでワイワイやりました



次の土曜日もfmsctf勉強会 #100をやる予定です
何かリクエストがない限りはサーバやWebに関することをやろうかなーって
興味のある人は是非参加して下さい!!