seccamp15 応募用紙 選択2
セキュリティキャンプの応募の時期であることを人伝に聞いたので書くことにした
結果、セキュリティキャンプ2015に参加することが出来たということもあり応募用紙を載せてみようと思う
その前にグダグダと前置きだけ
応募用紙の問題を見た第一印象、
「いや自分には厳しすぎるでしょ」
自分はWeb力は皆無なのでそれ関連の物はスルーとなった結果必然的にバイナリに焦点を向けることになった
バイナリとはいえ自分が出来ることはあまりなく...
今回の応募用紙を作成するにあたり、「某gle先生には極力尋ねない」という考えの下で問題に向き合った(今思うとほぼ何もできないのにおかしな話である)
後日ほかの参加者等の応募用紙をざっと見て、素晴らしい解答がたくさんあって「自分の解答はなんて低レベルなんだ!!!!」とさらに自分の弱さが身に染みた
後で時間が出来たときに今度はざっとではなく資料だと思って丁寧に読ませていただきます、そして勉強させていただきます
長すぎる前置きはここまでとして実際に提出した応募用紙の選択問題2を「そのまま」載せる
そのほかの問題はまた近いうちに載せる予定
■選択問題2 (左側の□について、回答した問題は■にしてください)
ある機械語をobjdumpにより逆アセンブルしたところ、以下の結果が得られました。このダンプに見られる問題点を指摘してください。
00000000 <.text>:
0: b8 de 07 00 00 mov $0x7de,%eax
5: 3d df 07 00 00 cmp $0x7df,%eax
a: 75 06 jne 0x12
c: 89 c0 mov %eax,%eax
e: ff e3 jmp *%ebx
10: 75 01 jne 0x13
12: e9 5b ba 0e 00 jmp 0xeba72
17: 00 00 add %al,(%eax)
19: b9 00 00 00 00 mov $0x0,%ecx
1e: bb 01 00 00 00 mov $0x1,%ebx
23: b8 04 00 00 00 mov $0x4,%eax
28: cd 80 int $0x80
2a: b8 01 00 00 00 mov $0x1,%eax
2f: cd 80 int $0x80
【以下に回答してください(行は適宜追加してください)】
(I)上からの流れで見ていく場合
読み進めていくと、0xa → 0x12にジャンプして0xeba72にジャンプしてから返ってきてそのまま1つ目のint 0x80命令を実行した後で2つ目のint 0x80命令に到達して終了すると予想
int 0x80はシステムコールを表しているので、各々のレジスタの状態を確認すると1回目eax = 0x4、2回目eax = 0x1なのでそれぞれwrite()関数、exit()関数であると断定。
exit()関数に関してはプログラムを終了させる働きをしていると考えることが出来る。
write()関数を見てみると、この時のebx = 0x1, ecx = 0x0しかなく、出力するバイト数を示す引数であるedxが見当たらない。
また、ecxの値が0x0であることからバッファ元がmov命令をしている0x0アドレスである。
以上の2点が気になったので以下の方法で実験をしてみた。
まず必要箇所を抜き出して以下のアセンブリコードを書いた。
test.s
main:
mov $0x7de,%eax
cmp $0x7df,%eax
mov $0x0,%ecx
mov $0x1,%ebx
mov $0x4,%eax
int $0x80
mov $0x1,eax
int $0x80
これを作成した後コンパイルして、このままでは”mov $0x7de,%eax”に相当するアドレスがずれてしまうのでobjdumpでアドレスの確認。
$ gcc –nostdlib –m32 test.s
$ objdump -d a.out
a.out: ファイル形式 elf32-i386
セクション .text の逆アセンブル:
08048098 <main>:
8048098: b8 de 07 00 00 mov $0x7de,%eax
804809d: 3d df 07 00 00 cmp $0x7df,%eax
80480a2: b9 00 00 00 00 mov $0x0,%ecx
80480a7: bb 01 00 00 00 mov $0x1,%ebx
80480ac: b8 04 00 00 00 mov $0x4,%eax
80480b1: cd 80 int $0x80
80480b3: b8 01 00 00 00 mov $0x1,%eax
80480b8: cd 80 int $0x80
以上より設問の0x0に相当するアドレスは0x08048098であると分かったので、ecxに対して、
“mov $0x08048098,%ecx”に書き変えて、gdbで見ていった(必要箇所以外は適宜中略した)。
$ gdb -q a.out
Reading symbols from a.out...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) start
Temporary breakpoint 1 at 0x8048098
Starting program: /a.out
Temporary breakpoint 1, 0x08048098 in main ()
(gdb) info registers
eax 0x0 0
ecx 0x0 0
edx 0x0 0
ebx 0x0 0
esp 0xffffd180 0xffffd180
(gdb) b *main+25
Breakpoint 2 at 0x80480b1
(gdb) b *main+27
Breakpoint 3 at 0x80480b3
(gdb) c
Continuing.
Breakpoint 2, 0x080480b1 in main ()
(gdb) disas
Dump of assembler code for function main:
0x08048098 <+0>: mov eax,0x7de
0x0804809d <+5>: cmp eax,0x7df
0x080480a2 <+10>: mov ecx,0x8048098
0x080480a7 <+15>: mov ebx,0x1
0x080480ac <+20>: mov eax,0x4
=> 0x080480b1 <+25>: int 0x80
0x080480b3 <+27>: mov eax,0x1
0x080480b8 <+32>: int 0x80
End of assembler dump.
(gdb) info registers
eax 0x4 4
ecx 0x8048098 134512792
edx 0x0 0
ebx 0x1 1
esp 0xffffd180 0xffffd180
(gdb) c
Continuing.
Breakpoint 3, 0x080480b3 in main ()
(gdb) disas
Dump of assembler code for function main:
0x08048098 <+0>: mov eax,0x7de
0x0804809d <+5>: cmp eax,0x7df
0x080480a2 <+10>: mov ecx,0x8048098
0x080480a7 <+15>: mov ebx,0x1
0x080480ac <+20>: mov eax,0x4
0x080480b1 <+25>: int 0x80
=> 0x080480b3 <+27>: mov eax,0x1
0x080480b8 <+32>: int 0x80
End of assembler dump.
(gdb) info registers
eax 0x0 0
ecx 0x8048098 134512792
edx 0x0 0
ebx 0x1 1
esp 0xffffd180 0xffffd180
(gdb) c
Continuing.
[Inferior 1 (process 3845) exited with code 01]
(gdb) q
このことから、1回目のシステムコールの前後でedxの値は0を取り続けていたので出力するバイト数は0となるので何も出力しないと分かった。
その証拠に返り値としてint 0x80の後でeaxの値が0になっていることが確認できる。
また、ecxが0x0であったことも気になるので試しに、もし0x12のジャンプ先である0xeba72でedxを設定することが出来て文字を出力をすることが出来たとしたら、と仮定して5バイト出力してもらうため新たに”mov 0x5,%edx”を追加して同様にしてみた(適宜中略してある)。
(gdb) disas
Dump of assembler code for function main:
=> 0x08048098 <+0>: mov eax,0x7de
0x0804809d <+5>: cmp eax,0x7df
0x080480a2 <+10>: mov edx,0x5 …追加した行
0x080480a7 <+15>: mov ecx,0x8048098
0x080480ac <+20>: mov ebx,0x1
0x080480b1 <+25>: mov eax,0x4
0x080480b6 <+30>: int 0x80
0x080480b8 <+32>: mov eax,0x1
0x080480bd <+37>: mov ebx,0x0
0x080480c2 <+42>: int 0x80
End of assembler dump.
(gdb) b *main+30
Breakpoint 2 at 0x80480b6
(gdb) b *main+32
Breakpoint 3 at 0x80480b8
(gdb) c
Continuing.
Breakpoint 2, 0x080480b6 in main ()
(gdb) disas
Dump of assembler code for function main:
0x08048098 <+0>: mov eax,0x7de
0x0804809d <+5>: cmp eax,0x7df
0x080480a2 <+10>: mov edx,0x5
0x080480a7 <+15>: mov ecx,0x8048098
0x080480ac <+20>: mov ebx,0x1
0x080480b1 <+25>: mov eax,0x4
=> 0x080480b6 <+30>: int 0x80
0x080480b8 <+32>: mov eax,0x1
0x080480bd <+37>: mov ebx,0x0
0x080480c2 <+42>: int 0x80
End of assembler dump.
(gdb) info registers
eax 0x4 4
ecx 0x8048098 134512792
edx 0x5 5
ebx 0x1 1
esp 0xffffd180 0xffffd180
(gdb) c
Continuing.
?? …(*)
Breakpoint 3, 0x080480b8 in main ()
(gdb) info registers
eax 0x5 5
ecx 0x8048098 134512792
edx 0x5 5
ebx 0x1 1
esp 0xffffd180 0xffffd180
(gdb) c
Continuing.
[Inferior 1 (process 3861) exited normally]
(gdb) q
結果、(*)の箇所で「??」が出力されていることが確認できた。
これはバッファのアドレスとして渡された0x08048098から5バイトの「b8 de 07 00 00」を出力させようとした結果であると考えられるので、仮にwrite関数が出力可能であったとしても設問でいうところの「0x0」アドレスから文字を出力しようとするのでよくわからない文字が出てきてしまう。
以上よりしたがって、write関数に出力させるバイト数が渡されていないので何も出力しない点と、仮に出力バイト数が1以上であっても出力させようとするアドレス元が命令している箇所なので文字化けしたものが出力されてしまう点が問題である。
(II)バイナリそのものを見ていった場合
アドレス0x10の”jne 0x13”が少し気になったので見てみる
0x13は5bを表していて、そのあとでba 0e 00 00 00 … と見て”ba 0e 00 00 00”の並びを見て下のmov命令と非常によく似ていることことに気が付いた
先ほどのtest.sを少し書き変えて本来はこのようになっていたのではないかと考えた(アドレス指定の都合で少しだけ違いが生じている)
$ objdump -d a.out
a.out: ファイル形式 elf32-i386
セクション .text の逆アセンブル:
08048098 <main>:
8048098: b8 de 07 00 00 mov $0x7de,%eax
804809d: 3d df 07 00 00 cmp $0x7df,%eax
80480a2: 0f 85 6a 7f fb f7 jne 12 <main-0x8048086>
80480a8: 89 c0 mov %eax,%eax
80480aa: ff e3 jmp *%ebx
80480ac: 0f 85 61 7f fb f7 jne 13 <main-0x8048085>
80480b2: 5b pop %ebx
80480b3: ba 0e 00 00 00 mov $0xe,%edx
80480b8: b9 98 80 04 08 mov $0x8048098,%ecx
80480bd: bb 01 00 00 00 mov $0x1,%ebx
80480c2: b8 04 00 00 00 mov $0x4,%eax
80480c7: cd 80 int $0x80
80480c9: b8 01 00 00 00 mov $0x1,%eax
80480ce: bb 00 00 00 00 mov $0x0,%ebx
80480d3: cd 80 int $0x80以上により、%edxに0xeをmovする命令が正しくダンプされていないことが問題点として考えられた
【回答ここまで】