First Exploit Q&A - kkli08/Buffer-Overflow GitHub Wiki
Writing the first Exploit
// overflow1.c
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
char large_string[128];
void main() {
char buffer[96];
int i;
long *long_ptr = (long *) large_string;
for (i = 0; i < 32; i++)
*(long_ptr + i) = (int) buffer;
for (i = 0; i < strlen(shellcode); i++)
large_string[i] = shellcode[i];
strcpy(buffer,large_string);
}
==========================================================
[aleph1]$ gcc -o overflow1 overflow1.c
[aleph1]$ ./overflow1
$ exit // successfully spawn a shell
exit
[aleph1]$
==========================================================
Q&A
large_string
?
Why we need duplicating the buffer's address in -
Pointer Assignment:
long_ptr
is used as a pointer tolarge_string
. The loop that follows writes the address ofbuffer
into each slot oflarge_string
. This is done by castinglarge_string
to along *
and then setting eachlong
sized chunk oflarge_string
to the address ofbuffer
.
-
Reason for Duplicating Buffer's Address:
- The duplication of the buffer's address 32 times in
large_string
is a part of setting up the buffer overflow. The goal is to ensure that whenlarge_string
is copied intobuffer
, it overflowsbuffer
and overwrites adjacent memory locations, which include the function's return address on the stack.
- The duplication of the buffer's address 32 times in
-
Shellcode Injection:
- The next step, where
large_string[i] = shellcode[i]
is executed, places the actual shellcode at the beginning oflarge_string
. This means that the start oflarge_string
(which is now being copied intobuffer
) contains the shellcode.
- The next step, where
-
Combining the Two Steps:
- The reason for initially filling
large_string
with the address ofbuffer
and then placing the shellcode at the beginning is to achieve two objectives:- Shellcode Placement: Ensure that the shellcode is at the beginning of the overflowed buffer (
buffer
). This is necessary for the shellcode to be executed. - Overwrite Return Address: By overflowing
buffer
withlarge_string
(which contains the buffer's address repeated many times), it aims to overwrite the return address on the stack with the address ofbuffer
(where the shellcode now resides).
- Shellcode Placement: Ensure that the shellcode is at the beginning of the overflowed buffer (
- The reason for initially filling
-
Execution Flow:
- When the function returns, if the return address on the stack has been successfully overwritten with the address pointing to the shellcode (now at the start of
buffer
), the execution will jump to the shellcode instead of returning to the original calling function.
- When the function returns, if the return address on the stack has been successfully overwritten with the address pointing to the shellcode (now at the start of
Key Point 1
- Partial Overwrite with Shellcode: The shellcode itself does not need to occupy the entire
large_string
. It only needs enough space at the beginning. The rest oflarge_string
(filled with the address ofbuffer
) ensures that when the overflow happens, the overwritten return address points to the location where the shellcode begins (which is now withinbuffer
).
Ideally the shellcode length should smaller than the length of the buffer, is that right?
Ideally, yes, the length of the shellcode should be smaller than the length of the buffer you are overflowing in a buffer overflow exploit. This is important for a few reasons:
-
Fit Within the Buffer: The shellcode needs to fit within the buffer before the buffer overflows. This allows the shellcode to be placed at the beginning of the buffer, ensuring it is in the right position when the overflow occurs.
-
Overwrite Return Address: The primary goal of a buffer overflow is to overwrite the return address on the stack. To do this, the buffer must overflow beyond its allocated space. If the shellcode is longer than the buffer, it would not leave enough space to fill the rest of the buffer (and the subsequent stack space) with the address that points to the shellcode (or a NOP sled leading to the shellcode).
-
Control Execution Flow: The exploit aims to control the execution flow by redirecting it to the shellcode. For this to work effectively, the shellcode must be precisely positioned so that the overwritten return address points to it.
-
Avoid Crashes and Detection: A shorter shellcode reduces the risk of crashing the program or the operating system and might help in avoiding detection by security mechanisms.
Practical Considerations
-
Buffer Size Limitation: In real-world scenarios, the buffer size you are exploiting is often fixed and can be relatively small, so efficiency in shellcode design is crucial.
-
Use of NOP Sleds: Sometimes, a NOP (No Operation) sled is used, which is a series of NOP instructions leading up to the shellcode. This can make it easier to hit the shellcode as the return address does not need to be as precise – any address landing in the NOP sled will slide down to the shellcode.
-
System and Architecture Constraints: The success of such an exploit depends on various factors, including system architecture, memory layout, and security mechanisms in place (like stack canaries, ASLR, DEP, etc.).