Off By One & chunk_extend
Off By One
概念
单字节缓冲区溢出:
- 循环次数设置错误
- 字符串操作不合适
strlen
不考虑\x00
来计算长度,但是strcpy
会把\x00
一起复制if(strlen(buffer) == 24){ strcpy(arr,buffer); }
如果
arr
的大小是24,但是实际上会拷贝25个数据。
又叫栅栏错误。
是差一错误的一种。
应用
应用广泛(大概),这道题里用的他更改下一个chunk的size域,达到overlap的效果。
chunk_extend
如何获得各个chunk位置
在ptmalloc
中,chunk_header是定位前后chunk的重要依据。
- 获取下一chunk
当前指针加上header
中size
的大小。 - 获取前一chunk
当前指针减去header
中pre_size
的大小。
判断是否在使用
- 判断前一chunk是否在使用当中
size
中的pre_inuse
标志。 - 判断当前chunk是否在使用当中
查看下一个chunk的pre_inuse
标志。 - 判断下一chunk是否在使用当中
查看下下一个chunk的pre_inuse
标志。
原理
通过更改chunk_header的数据,可以让一个chunk中包含另一个chunk,从而实现跨越chunk的操作——overlapping。
trick
- 当需要malloc的长度(size)没有和
0x8
对齐时(64位),实际分配到的chunk大小将会是size & (~0xf)
。少的内存由相邻下一个chunk的pre_size
补上。
思路
流程
是一个常见的分配堆,释放堆的题目。
-
分配
首先malloc(0x10)
创建一个结构体,里面存储size
和指向content
的指针。此后的操作都是在这个结构体里面获得数据。然后用户指定大小分配内存存储
content
。 -
释放
会把结构体和
content
的内存释放,并将结构体的指针置空。 -
提供编辑和打印功能
漏洞
在删除函数中人为地创造了一个off_by_one
的漏洞。
利用
-
分配两个
content
,content_0
大小见trick,content_1
大小需要和结构体大小相同【原因见后】,程序会分配4个chunk。其中两个是结构体。
注意这里struct_1
和content_1
的大小和地址。 -
编辑
content_0
,使struct_1
的size
大小为struct_1
和content_1
的大小之和。
在更改了struct_1
的size
之后,gdb解析的heap中就没有content_1
了 -
delete(1)
fastbin
中的原有struct_1
被放进了0x40
的bin
中。 - 分配
0x30
大小的content
系统会先在fastbin
找有没有0x20
和0x40
大小的chunk来作为struct
和content
,于是原有struct_1
&content_1
就被分配给了新的struct
和content
。content_1
大小要和struct
相同的原因但是这两个实际大小都是
0x20
。
当向
content_2
写入数据,就可以覆盖到struct_2
。
【题目中编号仍为1,此处只为容易分辨】构造chunk如图。
-
打印
content_2
前面说到所有有关content
的操作都是根据struct
中存的数据来的。
打印是打印struct
中存的地址指向的位置。在此处改为free_got
计算后即可得到libc
基址。 - 编辑
content_2
其实已经成为改got
表的操作了。
将free
的got
表改为system
的地址。
调用free
的时候,参数是struct
的存的地址,也就是*(struct->addr)
。
所以我们可以在一开始构造content_0
的时候,就把内容改成/bin/sh\x00
,当delete(0)的时候就是system("/bin/sh");
。
exp
1 |
|
atoi
这里也可以改atoi
,在choice:
的时候限制4个字节,输入sh\x00
就可以了。
一个问题
- 为什么在glibc2.27里面跑的时候,fastbin里面是空的。但是getshell是可以的?