1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-10-29 18:07:27 +01:00

Patches from <anon>

git-svn-id: file:///home/svn/incoming/trunk@3310 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
HD Moore 2006-01-05 22:20:28 +00:00
parent d0c8775f56
commit 8049b32cbc
12 changed files with 213 additions and 60 deletions

View File

@ -69,6 +69,8 @@ module Common
end
def self.platform_icons(platform)
# nil?
return "" if (platform.nil?)
# If this module has no platforms, then we don't show any icons...
return "" if (platform.empty?)

View File

@ -157,12 +157,16 @@ protected
register_options(
[
OptString.new('URIPATH', [ false, "The URI to use for this exploit (default is random)"]),
], Exploit::Remote::HttpServer)
register_advanced_options(
[
OptBool.new('DisableGzip', [ false, "Disable the use of GZIP on HTTP responses", false ]),
], Exploit::Remote::HttpServer)
], Exploit::Remote::HttpServer
)
register_evasion_options(
[
OptBool.new('HTTP::gzip', [false, 'Enable compression of HTTP responses via "Content-Encoding: gzip"', 'false']),
OptBool.new('HTTP::chunked', [false, 'Enable chunking of HTTP responses via "Transfer-Encoding: chunked"', 'false']),
], Exploit::Remote::HttpServer
)
end
#
@ -171,8 +175,8 @@ protected
# set.
#
def use_gzip
if (!Rex::Text.gzip_present? and datastore['DisableGzip'] != true)
raise RuntimeError, "GZIP support was not detected, set the DisableGzip advanced option to use non-compressed HTTP responses"
if (!Rex::Text.gzip_present? and datastore['HTTP::gzip'] == true)
raise RuntimeError, "GZIP support was not detected, yet the HTTP::gzip option was set. WTF?"
end
end
@ -204,6 +208,8 @@ protected
self.service = Rex::ServiceManager.start(Rex::Proto::Http::Server,
opts['ServerPort'].to_i, opts['ServerHost'])
self.service.server_name = 'Apache'
# Default the procedure of the URI to on_request_uri if one isn't
# provided.
uopts = {
@ -259,35 +265,32 @@ protected
return Rex::Proto::Http::Response.new(code, message, proto);
end
#
# Transmits an HTML response to the supplied client.
#
def send_html_response(cli, body, headers = {})
response = create_response
#
# Transmits a response to the supplied client, default content-type is text/html
#
# Payload evasions are implemented here!
#
def send_response(cli, body, headers = {})
response = create_response
response['Content-Type'] = 'text/html'
response.body = body
response.body = body
if (datastore['HTTP::gzip'] == true)
self.use_gzip # make sure...
response.body = Rex::Text.gzip(response.body)
response['Content-Encoding'] = 'gzip'
end
if (datastore['HTTP::chunked'] == true)
response.auto_cl = false
response.transfer_chunked = true
end
headers.each_pair { |k,v| response[k] = v }
cli.send_response(response)
end
#
# Transmits an gzip-encoded HTML response to the supplied client.
#
def send_html_gzip_response(cli, body, headers = {})
# Just call the normal response method if gzip is disabled.
return send_html_response(cli, body, headers) if (datastore['DisableGzip'])
response = create_response
response['Content-Type'] = 'text/html'
response['Content-Encoding'] = 'gzip'
response.body = Rex::Text.gzip(body)
headers.each_pair { |k,v| response[k] = v }
cli.send_response(response)
end
end
#
# Sends a 302 redirect to the client

View File

@ -122,17 +122,47 @@ class Packet
return comp
end
#
# Build a 'Transfer-Encoding: chunked' payload with random chunk sizes
#
def chunk(str, min_size = 1, max_size = 1000)
chunked = ''
# min chunk size is 1 byte
if (min_size < 1); min_size = 1; end
# don't be dumb
if (max_size < min_size); max_size = min_size; end
while (str.size > 0)
chunk = str.slice!(0, rand(max_size - min_size) + min_size)
chunked += sprintf("%x", chunk.size) + "\r\n" + chunk + "\r\n"
end
chunked += "0\r\n\r\n"
end
#
# Converts the packet to a string.
#
def to_s
content = self.body.dup
# Update the content length field in the header with the body length.
if (self.body and self.auto_cl)
self.headers['Content-Length'] = self.body.length
if (content)
if (self.auto_cl == true && self.transfer_chunked == true)
raise RuntimeError, "'Content-Length' and 'Transfer-Encoding: chunked' are incompatable"
elsif self.auto_cl == true
self.headers['Content-Length'] = content.length
elsif self.transfer_chunked == true
if self.proto != '1.1'
raise RuntimeError, 'Chunked encoding is only available via 1.1'
end
self.headers['Transfer-Encoding'] = 'chunked'
content = self.chunk(content, self.chunk_min_size, self.chunk_max_size)
end
end
str = self.headers.to_s(cmd_string)
str += self.body || ''
str += content || ''
end
#
@ -164,7 +194,11 @@ class Packet
attr_accessor :body
attr_accessor :auto_cl
attr_accessor :max_data
attr_accessor :transfer_chunked
attr_reader :incomplete
attr_accessor :chunk_min_size
attr_accessor :chunk_max_size
protected
@ -172,7 +206,6 @@ protected
attr_writer :error
attr_writer :incomplete
attr_accessor :body_bytes_left
attr_accessor :transfer_chunked
attr_accessor :inside_chunk
##

View File

@ -33,13 +33,21 @@ class Rex::Proto::Http::Request::UnitTest < Test::Unit::TestCase
"Eat: Babies\r\n" +
"\r\n")
assert_equal('POST', h.method)
assert_equal('/foo', h.uri)
assert_equal('1.0', h.proto)
assert_equal("POST /foo HTTP/1.0\r\n", h.cmd_string)
assert_equal('POST', h.method, 'method')
assert_equal('/foo', h.uri, 'uri')
assert_equal('1.0', h.proto, 'proto')
assert_equal('Babies', h['Eat'], 'header')
assert_equal("POST /foo HTTP/1.0\r\n", h.cmd_string, 'cmd_string')
h.method = 'GET'
assert_equal("GET /foo HTTP/1.0\r\n", h.cmd_string)
assert_equal('Babies', h['Eat'])
assert_equal("GET /foo HTTP/1.0\r\n", h.cmd_string, 'set method')
h.uri = '/bar'
assert_equal("GET /bar HTTP/1.0\r\n", h.cmd_string, 'set uri')
h.proto = '1.2'
assert_equal("GET /bar HTTP/1.2\r\n", h.cmd_string, 'set proto')
end
end

View File

@ -48,6 +48,10 @@ class Response < Packet
# Default responses to auto content length on
self.auto_cl = true
# default chunk sizes (if chunked is used)
self.chunk_min_size = 1
self.chunk_max_size = 10
end
#

View File

@ -20,9 +20,75 @@ class Rex::Proto::Http::Response::UnitTest < Test::Unit::TestCase
"HTTP/1.1 200 OK\r\n" +
"Foo: Fishing\r\n" +
"Content-Length: 0\r\n" +
"Chicken: 47\r\n\r\n", h.to_s)
"Chicken: 47\r\n\r\n", h.to_s, 'to_s w/o body')
h.body = 'hi mom'
assert_equal(
"HTTP/1.1 200 OK\r\n" +
"Foo: Fishing\r\n" +
"Content-Length: 6\r\n" +
"Chicken: 47\r\n\r\nhi mom", h.to_s, 'to_s w/ body')
end
def test_chunked
h = Klass.new
h.headers['Foo'] = 'Fishing'
h.headers['Chicken'] = 47
h.auto_cl = false
h.transfer_chunked = true
assert_equal(
"HTTP/1.1 200 OK\r\n" +
"Transfer-Encoding: chunked\r\n" +
"Foo: Fishing\r\n" +
"Chicken: 47\r\n\r\n0\r\n\r\n", h.to_s, 'chunked w/o body'
)
srand(0)
h.body = Rex::Text.rand_text_alphanumeric(100)
assert_equal(
"HTTP/1.1 200 OK\r\n" +
"Transfer-Encoding: chunked\r\n" +
"Foo: Fishing\r\n" +
"Chicken: 47\r\n\r\n" +
"5\r\nsv1AD\r\n7\r\n7DnJTVy\r\n5\r\nkXGYY\r\n5\r\nM6Bmn\r\n4\r\nXuYR\r\n5\r\nlZNIJ\r\n5\r\nUzQzF\r\n9\r\nPvASjYxzd\r\n5\r\nTTOng\r\n4\r\nBJ5g\r\n8\r\nfK0XjLy3\r\n6\r\nciAAk1\r\n6\r\nFmo0RP\r\n1\r\nE\r\n2\r\npq\r\n6\r\n6f4BBn\r\n4\r\np5jm\r\n1\r\n3\r\n6\r\nLuSbAO\r\n1\r\nj\r\n2\r\n1M\r\n3\r\n5qU\r\n0\r\n\r\n",
h.to_s, 'random chunk sizes'
)
h.chunk_max_size = 1
h.body = 'hi mom'
assert_equal(
"HTTP/1.1 200 OK\r\n" +
"Transfer-Encoding: chunked\r\n" +
"Foo: Fishing\r\n" +
"Chicken: 47\r\n\r\n" +
"1\r\nh\r\n1\r\ni\r\n1\r\n \r\n1\r\nm\r\n1\r\no\r\n1\r\nm\r\n0\r\n\r\n",
h.to_s, '1 byte chunks'
)
h.chunk_min_size = 2
assert_equal(
"HTTP/1.1 200 OK\r\n" +
"Transfer-Encoding: chunked\r\n" +
"Foo: Fishing\r\n" +
"Chicken: 47\r\n\r\n" +
"2\r\nhi\r\n2\r\n m\r\n2\r\nom\r\n0\r\n\r\n",
h.to_s, '2 byte chunks'
)
h = Klass.new(200, 'OK', '1.0')
h.body = 'hi mom'
h.auto_cl = false
h.transfer_chunked = true
assert_raise(Rex::RuntimeError, 'chunked encoding via 1.0') {
h.to_s
}
end
def test_from_s
h = Klass.new

View File

@ -103,6 +103,7 @@ class Server
self.listen_host = listen_host
self.listen_port = port
self.listener = nil
self.server_name = DefaultServer
self.resources = {}
end
@ -195,7 +196,7 @@ class Server
# Adds Server headers and stuff.
#
def add_response_headers(resp)
resp['Server'] = DefaultServer
resp['Server'] = self.server_name
end
#
@ -233,6 +234,11 @@ class Server
end
attr_accessor :listen_port, :listen_host
#
# Server name used by this servier instance
#
attr_accessor :server_name
protected
@ -329,6 +335,7 @@ protected
close_client(cli)
end
end
end

View File

@ -348,13 +348,27 @@ module Text
#
# Compresses a string using gzip
#
def self.gzip(str)
def self.gzip(str, level = 9)
raise RuntimeError, "Gzip support is not present." if (!gzip_present?)
raise RuntimeError, "Invalid gzip compression level" if (level < 1 or level > 9)
s = ""
gz = Zlib::GzipWriter.new(StringIO.new(s), level)
gz << str
gz.close
return s
end
#
# Uncompresses a string using gzip
#
def self.ungzip(str)
raise RuntimeError, "Gzip support is not present." if (!gzip_present?)
s = ""
w = Zlib::GzipWriter.new(StringIO.new(s))
w << str
w.close
gz = Zlib::GzipReader.new(StringIO.new(str))
s << gz.read
gz.close
return s
end
@ -409,7 +423,5 @@ protected
buf
end
end
end

View File

@ -75,7 +75,7 @@ class Exploits::Windows::Browser::AimGoaway < Msf::Exploit::Remote
print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport}...")
# Transmit the response to the client
send_html_response(cli, content)
send_response(cli, content)
end
end

View File

@ -72,7 +72,7 @@ class Exploits::Windows::Browser::MetafileAbortProc < Msf::Exploit::Remote
get_resource + '/' +
Rex::Text.rand_text_alphanumeric(rand(256)+16) +
".#{ext}'><body>One second please...</body></html>"
send_html_gzip_response(cli, html)
send_response(cli, html)
return
end
@ -80,7 +80,7 @@ class Exploits::Windows::Browser::MetafileAbortProc < Msf::Exploit::Remote
return if ((p = regenerate_payload(cli)) == nil)
# Transmit the compressed response to the client
send_html_gzip_response(cli, generate_metafile(p), { 'Content-Type' => 'text/plain' })
send_response(cli, generate_metafile(p), { 'Content-Type' => 'text/plain' })
handler(cli)
end

View File

@ -63,8 +63,7 @@ class Exploits::Windows::Browser::MS03_020_Ie_ObjectType < Msf::Exploit::Remote
else
print_status("Sending 404 to user agent: #{request['User-Agent']}")
cli.send_response(
create_response(404, 'File not found'))
cli.send_response(create_response(404, 'File not found'))
return
end
@ -90,7 +89,7 @@ class Exploits::Windows::Browser::MS03_020_Ie_ObjectType < Msf::Exploit::Remote
print_status("Sending exploit to #{cli.peerhost}:#{cli.peerport}...")
# Transmit the response to the client
send_html_response(cli, content)
send_response(cli, content)
end
end

25
msfcli
View File

@ -16,7 +16,7 @@ Indent = ' '
# Initialize the simplified framework instance.
$framework = Msf::Simple::Framework.create
if (ARGV.length <= 1)
if (ARGV.length < 1)
tbl = Rex::Ui::Text::Table.new(
'Header' => 'Exploits',
'Indent' => 4,
@ -42,13 +42,31 @@ end
# Initialize the user interface
exploit.init_ui($stdout, $stdin)
# Evalulate the command
mode = ARGV.pop.downcase
# Evalulate the command (default to "help")
mode = ARGV.pop || 'h'
# Import options
exploit.datastore.import_options_from_s(ARGV.join(' '))
case mode.downcase
when 'h'
tbl = Rex::Ui::Text::Table.new(
'Header' => "Usage: #{$0} #{exploit_name} <option=value> [mode]",
'Indent' => 4,
'Columns' => ['Mode', 'Description']
)
tbl << ['(H)elp', "you're looking at it baby!"]
tbl << ['(S)ummary', 'show information about this module']
tbl << ['(O)ptions', 'show available options for this module']
tbl << ['(A)dvanced', 'show available advanced options for this module']
tbl << ['(I)ds Evasion', 'show available ids evasion options for this module']
tbl << ['(P)ayloads', 'show available payloads for this module']
tbl << ['(T)argets', 'show available targets for this module']
tbl << ['(C)heck', 'Attempt to check if the target is vulnerable']
tbl << ['(E)xploit', 'Attempt to exploit the target']
$stdout.puts tbl.to_s
when "s"
$stdout.puts("\n" + Msf::Serializer::ReadableText.dump_module(exploit, Indent))
when "o"
@ -102,4 +120,5 @@ case mode.downcase
end
end
$stdout.puts