Position-Independent Download-and-Execute Shellcode
You are developing 32-bit Windows shellcode that downloads http://10.0.0.5/payload.exe and executes it. The shellcode will be injected via a stack overflow and executed after a ROP chain calls VirtualProtect on the stack. Constraints: the payload must be position-independent, must not contain null bytes or the bytes 0x0A, 0x0D, 0x20, and must be under 300 bytes. The target runs Windows 10 x86 with DEP and ASLR enabled. You cannot assume any specific DLL base. You have a test VM and a debugger. The shellcode must not rely on the stack being executable before the ROP chain runs; it will run after VirtualProtect. You have no imports available and cannot use a compiled stub; the shellcode must resolve everything at runtime. Your ROP chain will leave no useful register state beyond a valid stack pointer.
1. Explain how the shellcode can resolve `URLDownloadToFileA` and `WinExec` without hardcoded addresses, given ASLR.
Read the worked answer
Start by locating kernel32.dll without imports. On 32-bit Windows, the PEB is at fs:[0x30]; PEB->Ldr->InMemoryOrderModuleList links loaded modules. Walk the list, compare the BaseDllName or the module name hash for kernel32.dll, and recover its base. Parse the PE export directory: find GetProcAddress and LoadLibraryA by name hash. With LoadLibraryA, load urlmon.dll and kernel32.dll (already loaded). Use GetProcAddress to resolve URLDownloadToFileA from urlmon and WinExec (or CreateProcessA) from kernel32. This avoids any hardcoded addresses and survives ASLR. Use a simple hash (e.g., ROR13) to avoid storing API names as strings, which also helps with bad-byte constraints. Cache the resolved function pointers in registers or on the stack.
2. How do you handle the bad-byte constraints (0x00, 0x0A, 0x0D, 0x20) while keeping the shellcode under 300 bytes?
Read the worked answer
Write the shellcode normally, then encode it with a scheme that produces only allowed bytes. A simple XOR with a key that does not introduce bad bytes works, but the decoder stub itself must be bad-byte-free. A common approach is to use a single-byte XOR with a key like 0x99, then write a tiny decoder that uses xor byte ptr [edx+ecx], 0x99 in a loop. Ensure the decoder instructions do not contain 0x00, 0x0A, 0x0D, or 0x20. Alternatively, use an alphanumeric encoder (e.g., msfvenom's alpha_mixed) if the size budget allows. Because the shellcode is executed after VirtualProtect, you can place the encoded blob in the buffer and have the ROP chain jump to the decoder stub, which decodes in place and jumps to the decoded payload. Keep the decoder small (under 40 bytes) so the total stays under 300. Test the encoded payload in the debugger to confirm no bad bytes remain and the decode loop terminates correctly.
3. How would you test the shellcode in the debugger to ensure it works reliably before using it in the exploit?
Read the worked answer
Create a C harness that allocates RWX memory with VirtualAlloc, copies the shellcode, and calls it via a function pointer. Run it under WinDbg or x32dbg. Set breakpoints at the start of the shellcode and after each API resolution. Verify the PEB walk: check that fs:[0x30] points to a valid PEB, that the module list walk finds kernel32, and that the export parsing returns valid function pointers. Step through LoadLibraryA and GetProcAddress calls and confirm they return non-null. Test with a local HTTP server so the download succeeds. Also test on a clean VM with the same OS version and patch level, because PEB and export table layouts can vary. Finally, run the shellcode with DEP enabled and after a VirtualProtect call to mimic the real exploit environment; check that it does not rely on the stack being executable.