Schneider Electric EcoStruxure PME RCE 漏洞分析
漏洞信息
去年年底爆的洞。
漏洞链接:https://www.zerodayinitiative.com/advisories/ZDI-23-1795/
漏洞描述:The specific flaw exists within the GetFilteredSinkProvider method. The issue results from the lack of proper validation of user-supplied data, which can result in deserialization of untrusted data. An attacker can leverage this vulnerability to execute code in the context of LOCAL SERVICE.
环境: 注册之后能直接下载,https://ecoxpert.se.com
前置知识
移步https://xz.aliyun.com/t/9605
漏洞分析
根据漏洞描述漏洞出现在GetFilteredSinkProvider,一看这个函数应该是.net remoting出的问题。
可以看到这个函数是为了配置SinkProvider,使用的是原生的两种BinaryServerFormatterSinkProvider和SoapServerFormatterSinkProvider,并且TypeFilterLevel配置为Full。
查看其调用PowerMeasurement.IONServices.RemotingCommon#CreateChannel函数
public static IChannel CreateChannel(string protocol, int port, IDictionary additionalProperties)
{
bool flag = string.Compare(protocol, "tcp", true, CultureInfo.InvariantCulture) == 0;
IServerChannelSinkProvider filteredSinkProvider = RemotingCommon.GetFilteredSinkProvider(flag);
IDictionary dictionary = new Hashtable();
dictionary["port"] = port;
dictionary["timeout"] = 30000;
if (additionalProperties != null)
{
foreach (object obj in additionalProperties)
{
DictionaryEntry dictionaryEntry = (DictionaryEntry)obj;
dictionary[dictionaryEntry.Key] = dictionaryEntry.Value;
}
}
IChannel result;
if (!flag)
{
IChannel channel = new HttpChannel(dictionary, null, filteredSinkProvider);
result = channel;
}
else
{
IChannel channel = new TcpChannel(dictionary, null, filteredSinkProvider);
result = channel;
}
return result;
}
很明显这里就是创建一个channel,传入的协议是TCP,最后在ObjectRegistration类中注册的,主要代码如下
private static IChannel RegisterRemotingChannel(string node, out string protocol, out int port)
{
IChannel result = null;
IChannel remotingChannel = ObjectRegistration.GetRemotingChannel(node, out protocol, out port);
if (remotingChannel != null)
{
try
{
ChannelServices.RegisterChannel(remotingChannel, false);
result = remotingChannel;
}
catch (Exception ex)
{
HostUtilities.ReportChannelRegistrationFailure(remotingChannel, ex);
}
}
return result;
}
到这里看起来没有任何过滤(看到这之前原本猜测是绑定的服务有可以实现RCE的功能,没想到现在居然还有这种直接可利用的洞),继续找绑定的objecturi,全局搜RemotingConfiguration#RegisterWellKnownServiceType或RemotingServices#Marshal的调用点,最后在ObjectRegistration#ConfigureRemoting()方法中配置的
ObjectUri配置为IONServicesProviderFactory.soap,提供的服务是PowerMeasurement.IONServices.ProviderFactory(没什么危险功能)。
继续找创建channel绑定的端口
public static void GetRemotingChannelInfo(bool isPrimary, string node, out string protocol, out int port)
{
protocol = null;
port = -1;
RemotingCommon.GetProtocolAndPortFromNetworkConfigDB(isPrimary, node, ref protocol, ref port);
if (string.IsNullOrEmpty(protocol))
{
protocol = "Tcp";
}
if (port <= 0)
{
port = 57777;
}
}
默认是57777,
直接用ExploitRemotingService发送yso生成的反序列化数据就行。