刚开始接触堆,将解决的不懂的记录一下,后续会继续更正之前错误的认识。
指向堆的指针的问题
程序存在一个结构体,存在三个变量1
2
3
4
5
6
7
8
9.bss:00000000006016C0 ; __int64 qword_6016C0[]
.bss:00000000006016C0 qword_6016C0 dq ? ; DATA XREF: main+38↑o
.bss:00000000006016C0 ; .text:0000000000400A90↑o ...
.bss:00000000006016C8 ; __int64 qword_6016C8[]
.bss:00000000006016C8 qword_6016C8 dq ? ; DATA XREF: sub_400B40+B5↑w
.bss:00000000006016C8 ; sub_400CE0+79↑w
.bss:00000000006016D0 ; __int64 qword_6016D0[]
.bss:00000000006016D0 qword_6016D0 dq ? ; DATA XREF: sub_400B40+BC↑w
.bss:00000000006016D0 ; sub_400C30+73↑r ...
申请了3个大小均为0xa0的chunk后,堆布局如下:1
2
3
4
5
6
7
8gef➤ heap chunks
Chunk(addr=0x1592010, size=0xb0, flags=PREV_INUSE)
[0x0000000001592010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa]
Chunk(addr=0x15920c0, size=0xb0, flags=PREV_INUSE)
[0x00000000015920c0 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 bbbbbbbbbbbbbbbb]
Chunk(addr=0x1592170, size=0xb0, flags=PREV_INUSE)
[0x0000000001592170 2f 62 69 6e 2f 73 68 3b 63 63 63 63 63 63 63 63 /bin/sh;cccccccc]
Chunk(addr=0x1592220, size=0x20df0, flags=PREV_INUSE) ← top chunk
查看这个结构体,可以看到结构体的第一个变量表示是否正在使用,第二个变量表示申请的堆大小,第三个变量是一个指向堆的指针,0x6016d0是一个指针
,这个指针指向堆上的一个地址0x1592010,这个地址也是malloc返回的地址。1
2
3
4
5
6gef➤ x/9gx 0x6016c0
0x6016c0: 0x0000000000000001 0x00000000000000a0
0x6016d0: 0x0000000001592010 0x0000000000000001
0x6016e0: 0x00000000000000a0 0x00000000015920c0
0x6016f0: 0x0000000000000001 0x00000000000000a0
0x601700: 0x0000000001592170
堆大小的问题
程序malloc(0xa0)申请了0xa0大小的chunk,查看堆布局发现在size字段中,大小为0xb0。
所以申请了0xa0的chunk,该chunk真正的大小为0xa0+8+8=0xb01
2
3gef➤ heap chunks
Chunk(addr=0x1592010, size=0xb0, flags=PREV_INUSE)
[0x0000000001592010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaaaaaaaaaa]
如下所示,多了16字节的数据,分别是0x00和0x10。有一个疑问,在被释放的chunk中0x1592000中的数据应该是prev_size,在正被使用的chunk中,这部分数据全是0。而0x1592008中的数据就是当前chunk的大小和前一个chunk是否被使用的标志位。1
2
3
4
5
6gef➤ x/10gx 0x1592000
0x1592000: 0x0000000000000000 0x00000000000000b1
0x1592010: 0x6161616161616161 0x6161616161616161
0x1592020: 0x6161616161616161 0x6161616161616161
0x1592030: 0x6161616161616161 0x6161616161616161
0x1592040: 0x6161616161616161 0x6161616161616161
system(chunk2中的内容)为什么会执行shell
调试发现,程序在执行call 0x400620 <free@plt>
时会将chunk中的内容存放到rdi寄存器中1
2
3
4
5free@plt (
rdi = 0x00000000012410c0 → "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb[...]",
rsi = 0x0000000000000001,
rdx = 0x0000000000000000
)
所以/bin/sh;被存放到rdi寄存器,执行system函数时,就调用了shell。
程序
程序edit部分未能和原长度进行判断,导致出现堆溢出漏洞。第一次edit,free是为了获取一个原指向堆的可控指针0x6016d0 -> 0x6016b8
。第二次edit,将该指针0x6016d0
指向free@got,然后通过list获取free@got的地址,计算libc的基址,通过偏移计算出system的地址。第三次edit将system的地址写入free@got指向的地址,free函数就被替换成system函数了,释放chunk2后,即获取shell。
EXP
1 | #!/usr/bin/env python |
REF
http://www.ms509.com/2016/01/22/glibc-heap-ctf-writeup
http://www.cnblogs.com/shangye/p/6261606.html