Stack Overflow Exploitation

Fundamentally, stack overflows in Alpha are no different from stack overflows on x86. We do have a major challenge, however; we are dealing with a non-executable stack. The Tru64 OS comes with, by default, a non-executable stack, meaning that we cannot execute code stored on the stack. This limitation complicates our typical stack overflow exploits quite a bit. Execution flow control is still easy with any stack overflow exploit, but we will need to store our shellcode somewhere in memory so that we can execute later. For local stack overflows the solution is pretty trivial; many libraries and the dynamic linker copy user -supplied options that have passed within environment variables to the heap (dynamically allocated memory). The heap is readable, writeable , and executable at anytime . Later, when the execution control is gained by using the stack overflow, execution will be directed to the controlled heap area.

Additionally, return to libc is a possible way of defeating the non-executable stack, and is briefly covered in the next section. Remote stack overflows that make use of the heap also work just as well, and almost all network applications store client-side supplied data into heap. It may not be the exact buffer that leads to a stack overflow, but rather some other user-supplied buffer, which can conveniently be used as a shellcode holder for the remote exploit. In the following sections we will develop a remote RPC exploit by locating our shellcode in the heap and jumping to it by using a trivial stack overflow. For example, say you encounter a stack overflow in the POST HTTP method. You should think about storing nop s and shellcode into heap space by using an HTTP request section that gets to be stored on the heap somewhere and stays there.

Defeating the Non-Executable Stack

This technique works only when there are no NULL- byte restrictions. We need to store a couple of pointers with their high-order two bytes equaling zero (only 48 bits are used to reference the address space of a typical user-mode program). We will cover this technique only briefly, because it is mostly application-specific and requires much disassembly work from the exploiter's behalf . The basic idea is to jump to a certain code location inside the library's or program's text, which have interesting instruction sequences (such as the following code) that can set up the registers for a further return into the system() function.

 (gdb) x/5i 0x3ff80212e40 0x3ff80212e40 <__tis_reinit+384>:       ldq     ra,0(sp) 0x3ff80212e44 <__tis_reinit+388>:       ldq     s0,8(sp) 0x3ff80212e48 <__tis_reinit+392>:       lda     sp,16(sp) 0x3ff80212e4c <__tis_reinit+396>:       unop 0x3ff80212e50 <__tis_reinit+400>:       ret 

This code segment is from libc (which is a somewhat reliable address to hardcode in exploits). Basically, this code loads the return address and the s0 register from the stack. It is followed by the ret instruction, which will take the code flow to the address just loaded to the ra register (the quadword on the stack).

By using this code fragment we can return to the system function in libc. We still have a major challenge in that the system function requires the incoming argument to be passed with the a0 register, which we do not control. This problem can be resolved by looking into the system function which, at a certain stage, moves the incoming argument a0 to the s0 register and uses the s0 register to reference the command string. In order to achieve control of execution, we will need to jump to this location inside the system function (remember we control s0 ). As you can see from the following disassembly, execution is directed to <system+144> with s0 holding the incoming argument (the command string).

 0x3ff800f3810 <system+48>:      mov     a0,s0 0x3ff800f3814 <system+52>:      bne     a0,0x3ff800f3870 <system+144>  0x3ff800f3818 <system+56>:      ldah    a0,-16382(gp) 

Remember from the previous assembly dump, we control the s0 register at <__tis_reinit+388> . It gets loaded from the overflowed stack, meaning we can make it point to an ASCII string within our overflowed buffer that will eventually get executed by the system function. There are thousands of interesting code sequences that might be used to prearrange the registers and stack for a successful return-into-libc condition. Play with the idea; it really is fun to be able to introduce new execution flows to the application.



The Shellcoder's Handbook. Discovering and Exploiting Security
Hacking Ubuntu: Serious Hacks Mods and Customizations (ExtremeTech)
ISBN: N/A
EAN: 2147483647
Year: 2003
Pages: 198
Authors: Neal Krawetz

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net