引言
在现代的操作系统中,针对内存破坏方面的漏洞,提供了一系列的阻碍措施,类似DEP、CFG以及EMET。浏览器Exploit中,通过UAF/Double Free 乃至 堆溢出都能实现对内存的一定程度读写,但是碍于内存不可执行,浏览器利用中常常需要精确堆喷射结合ROP,前提是获取二进制文件(ELF/COFF)在内存中load的确切地址(地址泄漏)。文本暂时不讨论堆利用本身,会分别讨论两个浏览器漏洞,利用漏洞实现了OOB之后,如何在开启ASLR的情况下完成地址泄漏,帮助读者完成Exploit的最后一公里。
Linux下检查是否开始ASLR
ASLR 技术在 2005 年的 kernel 2.6.12 中被引入到 Linux 系统,Linux 平台上的 ASLR 分为三级,由内核参数 randomize_va_space 进行等级控制。它们对应的效果如下:
0:没有随机化。即关闭 ASLR。
1:保留的随机化。共享库、栈、mmap() 以及 VDSO 将被随机化。
2:完全的随机化。在 1 的基础上,通过 brk() 分配的内存空间也将被随机化。
$ cat /proc/sys/kernel/randomize_va_space
2
需要注意的是Linux下的ASLR默认不对代码段以及数据段(data段和bss段)进行随机化,于是gcc在编译时候加-pie参数,开启PIE机制的程序会对代码段和数据段也进行随机化。不过由于PIE是编译选项,PIE是否真正的开启是基于系统的ASLR是否开启。
Windows下检查是否开启ASLR
Windows在vista之后是默认开启ASLR的,并且Windows的ASLR同样会对代码段和数据段进行随机化,简单来说Windows的ASLR基本等于Linux下的ASLR加PIE。
绕过ASLR
利用未启用ASLR的模块绕过这部分的研究价值不高,和没有开ASLR的难度差别不大,所以这个方案就暂时不做演示。如果要寻找哪些模块没有开启ASLR,可以使用mona插件可以的mod命令查看。常见的例子,如java6的msvcr71.dll编译时时默认不支持ASLR的,所以很多exploit都使用这个模块构造ROP链来实现攻击。
泄露基地址绕过ASLR是最经典的绕过技术,也是CTF中最常见的绕过技术,这个技术在2010年左右兴起,用于对抗当时已经有较大市场份额的WIN7。这也是本文会着重分析的技术,重点会在漏洞利用。例如下文案例,IE浏览器利用中通过虚函数表获取mshtml.dll的基地址构造ROP链。
yuange的天人模式袁哥在97年就发布的DVE数据虚拟执行技术,一项技术几乎能绕过DEP+ASLR+CFG+页堆保护等多项防护技术,并且在2014年在贴吧公布了技术细节。本文作者对这个技术知之甚少,依然在探究中,希望有朝一日能够掌握该技术的原理。
本次案例的两个漏洞,产生的原因并不相同(堆溢出和数组越界),但是在地址泄漏方面的方式是相同的。通过构造如下的结构,来读取虚函数表的地址,以达到任意地址泄漏。当然后者数组越界,可以进一步实现任意地址读写,利用到方式更加多样。
前置知识
BSTR是一种Pascal-Style字符串(明确标示字符串长度)和C-Style字符串(以结尾)的混合物,一般用于COM中,是Unicode字符串,即标示字符串长度,最后还有一个值为字节。BSTR的存储结构
字符串头 —-4字节 存储了包好字节(Byte)的个数
字符串内容 —-以unicode方式存储,每个字符两字节(w_char – 2byte)
结束符 —-结束符null, 2字节
QArrayData是QT中定义的数组结构,头部包含一个24字节的数据结构。结构体定义如下。
struct Q_CORE_EXPORT QArrayData
{
QtPrivate::RefCount ref;//引用计数
int size; //大小
uint alloc : 31; //分配的个数
uint capacityReserved : 1;//适应模式
qptrdiff offset; // in bytes from beginning of header 定位指针
void *data()
{
Q_ASSERT(size == 0
|| offset < 0 || size_t(offset) >= sizeof(QArrayData));
return reinterpret_cast(this) + offset;
}
const void *data() const
{
Q_ASSERT(size == 0
|| offset < 0 || size_t(offset) >= sizeof(QArrayData));
return reinterpret_cast(this) + offset;
}
// This refers to array data mutability, not "header data" represented by
// data members in QArrayData. Shared data (array and header) must still
// follow COW principles.
bool isMutable() const
{
return alloc != 0;
}
enum AllocationOption { //5种模式 分配模式 使用shared_null[0] 使用shared_null[1] 可以增长 默认
CapacityReserved = 0x1,
#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
Unsharable = 0x2,
#endif
RawData = 0x4,
Grow = 0x8,
Default = 0
};
Q_DECLARE_FLAGS(AllocationOptions, AllocationOption)
size_t detachCapacity(size_t newSize) const
{
if (capacityReserved && newSize < alloc)
return alloc;
return newSize;
}
AllocationOptions detachFlags() const
{
AllocationOptions result;
if (capacityReserved)
result |= CapacityReserved;
return result;
}
AllocationOptions cloneFlags() const
{
AllocationOptions result;
if (capacityReserved)
result |= CapacityReserved;
return result;
}
static QArrayData *allocate(size_t objectSize, size_t alignment, //分配内存返回一个适配的 QArrayData指针
size_t capacity, AllocationOptions options = Default)
Q_DECL_NOTHROW Q_REQUIRED_RESULT;
static void deallocate(QArrayData *data, size_t objectSize, //释放内存
size_t alignment) Q_DECL_NOTHROW;
static const QArrayData shared_null[2]; // 静态的全局对象两个,在分配内存时可以使用Unsharable 和 RawData来指定使用这个两个对象来管理分配的内存
static QArrayData *sharedNull() Q_DECL_NOTHROW { return const_cast(shared_null); }
};
从堆溢出到地址泄漏
漏洞编号:CVE-2012-1876
程序
软件版本
WIN7
SP1(x86)
IE8
8.0.7601.17514
CVE-2012-1876是法国安全团队Vupen在Pwn2Own2012上攻破Win7下IE9的两个漏洞之一,利用了
poc
function over_trigger() {
var obj_col = document.getElementById("132");
obj_col.width = "42765";
obj_col.span = 1000;
}
setTimeo