细致解读2023年Hexacon会议上发表的 .NET 反序列化最新链路的白皮书,本次介绍 GetterSecurityException gadget,System.Security.SecurityException位于mscorlib.dll程序集,用于应用程序尝试执行需要特定权限的操作时,因权限不足或与CAS策略冲突时导致的异常错误信息。
SecurityException类的Method成员,对象访问器Getter调用了内部方法this.getMethod(),修改器Setter通过ObjectToByteArray方法转换为字节,如下图所示
通过反编译ObjectToByteArray得知,内部使用BinaryFormatter.Serialize将对象序列化成一个MemoryStream,并通过ToArray方法返回byte[]类型,如下图所示
因此访问SecurityException对象的Method属性时触发的getMethod()方法,一定是通过BinaryFormatter格式化器反序列化对象,打开后发现调用了ByteArrayToObject,如下图所示
从方法名知道ByteArrayToObject正好与Setter里的ObjectToByteArray相反,用于反序列化操作,如下图所示
因此攻击者控制Method属性通过setter赋值的方式添加BinaryFormatter攻击载荷,便能在调用getter时触发反序列化漏洞。
System.Windows.Forms.PropertyGrid 是Windows Forms中的一个控件,通常用于创建属性窗格,便于用户直观地查看和编辑对象的属性值。这个gadget是通过修改器setter设置SelectedObjects属性时触发的,该setter很复杂并且包含大量代码,重要的是Refresh()方法,Refresh方法触发RefreshProperties、UpdateSelection、CreateChildren这一系列的多个方法的调用,然后进入GridEntry.GetPropEntries,如下图所示
该方法内部迭代对象的成员,并通过PropertyDescriptor2.GetValue方法获取每个成员值,这个过程会调用每个成员的访问器getter,如下图所示
根据上述两条链路的原理性分析,我们可以尝试着构造用于恶意反序列化的攻击代码,结合Ysoserial.Net的代码实现如下
payload = @"{ '$type':'System.Windows.Forms.PropertyGrid, System.Windows.Forms, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089', 'SelectedObjects':[" + sePayload + @"]}";
PropertyGrid类 的SelectedObjects属性是一个数组,由包含了攻击载荷的变量sePayload 构建的,sePayload变量定义的代码如下
string sePayload = @"{ '$type':'System.Security.SecurityException', 'ClassName':'System.Security.SecurityException', 'Message':'Security error.', 'InnerException':null, 'HelpURL':null, 'StackTraceString':null, 'RemoteStackTraceString':null, 'RemoteStackIndex':0, 'ExceptionMethod':null, 'HResult':-2146233078, 'Source':null, 'Action':0, 'Method':'" + b64encoded + @"', 'Zone':0 }";
Method是一组进行Base64编码后基于BinaryFormatter生成的攻击载荷,原理前文已经分析过,此处不再赘述,调试时打印出完整的Payload,如下贴图所示
最后通过上面这段JSON.NET代码完成整条攻击链路的反序列化,成功启动本地计算器进程,如下图所示