In the basic software security experiment, buffer overflow is a basic and classic problem. The most basic buffer overflow is the reasonable construction of input data, so that the amount of input data exceeds the size of the original buffer, so as to overwrite data input buffer data, such as modifying the function return address and so on. But as the operating system and compiler introduce protection against buffer overflow problems, it is difficult for beginners to learn and practice the principle of buffer overflow by simply entering the complex. In the Linux environment, users can easily complete some simple buffer overflow experiments by setting up the compilation and system environment to remove some of the protective measures.
1. Turn off SSP (Stack smashing Protector)
Implementation principle
The SSP is a mechanism provided by GCC to provide checks against buffer overflows on the stack. A typical buffer overflow attack will overwrite the data outside the buffer by constructing the input data, and achieve some overflow effect, such as modifying function return address and so on. When the SSP mechanism is enabled, in the compiler-generated code, for those functions that have buffers, the function begins by stacking a random value (canary) in the corresponding stack frame, and when the function call finishes preparing to return, the compiler-generated code checks to see if the random value introduced above has changed. If a change occurs, a buffer overflow is present, and the control flow is transferred to the corresponding handler function.
Take the following code as an example to illustrate
char *src) { char buff[]; strcpy (buff, SRC); }
The above code simply copies the data in the buffer src into the buff array, without considering whether the amount of data in SRC exceeds the capacity of the buff array.
Use GDB to see the compilation of the Simplecopy.
In the GCC-generated code that opens the SSP mechanism, before the function begins data processing, the value at the gs:0x14 is stored at%ebp-12, and when the function returns, the value at%ebp-12 is checked, and if this value is not equal to the values at gs:0x14, the overwrite of the data exists and modifications, the program will be transferred to __stack_chk_fail execution. The result of calling the function through Simplecopy ("Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") is as shown. In the Simplecopy function above, the first address of the buffer buff is%ebp-22, and the introduced Canary is stored at%ebp-12, and when the buffer has a data overflow, the value of Canary is modified so that it is detected when the function returns.
Option settings
In the GCC compilation settings, the default setting of the SSP mechanism is a valid state, and users can disable the SSP mechanism by adding the-fno-stack-protector parameter at compile time.
-fstack-protector // enable SSP mechanism at compile time/ / disable SSP mechanism at compile time
2. Turn off DEP ( Data Execution Prevention )
In some stack buffer data overflow practices, the constructed machine instruction sequence is written through input to the input buffer on the stack, while the construction data overwrites the return address of a function call outside the data buffer, modifying its value to the address of a constructed machine instruction sequence in the buffer, so that when the function call returns, The program flow jumps to the sequence of construction instructions in the input buffer, enabling the modification and hijacking of the execution flow. In modern compilers, to prevent users from constructing data through buffers on the stack, a DEP mechanism, which restricts memory properties, makes some writable memory non-executable (such as a stack), or can perform memory not writable (such as a. Text segment), thus achieving a protective effect.
When compiling with GCC, you can use the-Z execstack parameter to allow the stack memory segment in the resulting program to have executable permissions.
-Z execstack // set stack memory segment with executable permissions
While the program is running, you can view the memory mapping of the process that the PID corresponds to by viewing the Cat/proc/pid/maps file, which includes a description of the properties of the segment of the process.
3. Close the ASLR (Address space layout randomization)
In the base stack buffer overflow practice, an important step is to locate the memory-mapped address of some targets, such as the simplest shellcode to locate the address of the sequence of constructs on the injection stack (thus modifying the function return address to point to the sequence of instructions), RET2LIBC method requires an attacker to locate the memory-mapped address of a standard library function located in memory. ASLR, the memory layout randomization mechanism, is implemented by the operating system, which is divided into such categories as Image randomization, stack randomization, and heap randomization, which are randomized for the program's load base address, stack base, and heap base addresses, respectively.
Design principle
The various segments of the program that have been compiled are fixed in memory, meaning that the memory mapping is fixed when the program runs, and the attacker can run the program multiple times to obtain the desired address. In the compiled ELF file, the section Header table describes the base address of each segment that the program needs to load into memory, which can be viewed by readelf-h filename. For running programs, you can view the memory mapping of the PID corresponding process through cat/proc/pid/maps, including the stack, the base address of the heap, and so on.
objdump-h Hello // View executable file Hello's section Header table cat /proc/pid/maps //pid is the process number, View the memory mapping of the PID corresponding process
(1) Viewing the ELF file via objdump-h hello. Text loading base address is 0x08048370, while the. Rodata section of the load base site is 0x08048558.
(2) View the shell memory mapping by CAT/PROC/$$/MAPS (64-bit Ubuntu), you can see the memory range of the shell process stack segment and its properties are readable writable but not executable, p indicates that the virtual memory segment is private (private), S Indicates that the virtual memory segment is shared.
In the past compilation environment, the data segments of the program include. Text,. BSS,. Rodata segments loaded into memory at compile time, the start address of the stack and heap in the process is always fixed, which makes it easier for an attacker to locate the address of the target in memory. To attempt the attack. After introducing the ALSR mechanism, for a particular segment (. text, Stack, heap) of a program, the operating system adds a random size "fill" from its original base address at load time, and the corresponding program data always starts after the "fill" area, because each use of the "fill" is not fixed, the memory layout changes when the same program runs multiple times, making it more difficult for an attacker to access the desired target through a fixed address.
option Settings
Users can view the current operation of the ALSR mechanism through cat/proc/sys/kernel/randomize_va_space. Where 0 means that the ALSR mechanism is not enabled, 1 means that the ALSR mechanism will randomize the starting base address of the stack, VDSO, and Mmap, and 2 indicates that the heap base site will be randomized in addition to randomization of the above targets. users can turn off ALSR by using echo 0 >/proc/sys/kernel/randomize_va_space settings.
cat /proc/sys/kernel/randomize_va_space // See how the ALSR mechanism works echo0 >/proc/sys/kernel/randomize_va_space // set shutdown ALSR mechanism, requires root user to operate
The above operation for/proc/sys/kernel/randomize_va_space is for the global settings of the system, requires root privileges and disadvantages, the user can use the following command to close the current terminal/bin/bash ALSR mechanism, then through the shell Running programs do not start the ALSR mechanism. The above settings expire after the terminal is closed.
Setarch 'uname -M '-r/bin/bash
4. Get the destination address via GDB
The underlying buffer overflow practice usually needs to determine certain addresses in the running state of the program, such as the need to determine the starting address of the input buffer to obtain the address of the machine instruction in the injected buffer. In the Linux environment, the program can be dynamically debugged through GDB to obtain information under the program's running state (the effect is better after closing the ALSR mechanism), and the underlying GDB operation can be found in the author's article Linux editing, compiling, debugging commands summary--GCC and GDB description. GDB is a convenient way to get the information in the dynamic state of the program, but information such as the starting address of the buffer obtained through GDB dynamic debugging may not be the same as the information that the program actually runs , which affects the effect of buffer overflow practice. As to the problem of ensuring that the address of local variables obtained by GDB Dynamic Debugger is consistent with the address of the directly running the program, the author also describes the solution of the local variable address and the inconsistency problem of the direct running program for GDB dynamic debugging under the Linux environment.
5. Summary
In order to complete the underlying buffer overflow practice, the user can turn off SSP protection through the GCC compilation option-fno-stack-protector, with the-z execstack option allowing the generated executable stack to be executed through setarch ' uname-m The '-r/bin/bash setting closes the ALSR mechanism for running programs in the current terminal and obtains information about some of the required program local variables through GDB dynamic debugging.
6. References
1.Stack smashing Protector-osdev Wiki
2.protect Against buffer overflow exploits
3.Address Space Layout Randomization-wiki
Configuration records for buffer overflow experiments using Linux