Long time no see!
Today I will writeup two vulnerabilities:
Before reading, I think you need to know some concepts: Microsoft Exchange, Microsoft Sharepoint, ASP.NET Web Forms, VIEWSTATE.
- Microsoft Exchange is the webmail server of Microsoft
- Microsoft Sharepoint is a web-based, collaborative platform for creating portal, managing document, … You can read more here: Sharepoint
- What is ASP.NET Webform? It is a web framework of Microsoft. I know two popular web frameworks of Microsoft: ASP.NET Web Forms and ASP.NET Web MVC . Microsoft Exchange and Microsoft Sharepoint mainly code in ASP.NET Web Forms, I think.
- If you used to code C# and ASP.NET, you would know the concept – VIEWSTATE. You can read one of the best explaination here: what-is-view-state-and-how-it-works-in-Asp-Net
1. Introduce case study
Last year, I was given a task of pentesting a customer (PR a little bit about my company, it is Viettel Information Security Center). As you know, we need to do all recon stuff frst: network scanning, subdomain scanning, website scanning, google searching.
But the only two things I found here were some Sharepoint servers (including homepage) and a webmail server.
Their homepage used a Microsoft Sharepoint portal (news website with many domains). Webmail is a Mail Exchange instance.
Mail Exchange always needs authentication but I didn’t have any accounts. So I focused on their Microsoft Sharepoint portal, particularly their homepage.
I fed all requests and responses of portal through Burpsuite proxy. I easily found the its version: 126.96.36.19962 . This version is Sharepoint 2010 (no update, no service pack).
After searching in Google, reading Microsoft advisory, I checked all CVEs of Sharepoint 2010.
Most of them were about XSS, some CVEs was page content RCE vulnerability but it sadly needed authentication.
But then there was an interesting CVE here: https://technet.microsoft.com/en-us/library/security/ms13-067.aspx. – a Remote code execute vulnerability.
I searched for the PoC in Google, after many hours of searching, I found none. No way! I felt disappointed.
I came back Microsoft advisory MS13-067, read carefully the detail of this vulnerability .
They told that MAC was disabled.
What does MAC stand for?.
Again, I continued searching google and reading all stuffs related to “MAC disabled” on the internet. I found that they told about ASP.NET VIEWSTATE MAC disabled (As before, Microsoft Sharepoint is developed in ASP.NET Web Forms. ).
You can read VIEWSTATE concept here: what-is-view-state-and-how-it-works-in-Asp-Net53
And finally, I found this presentation: asfws-2014-slides-why-net-needs-macs-and-other-serialization-talesv20.
Thanks to Alexandre Herzog, and actually he is the guy who reported MS-067 🙂 🙂 🙂
Finally I understood clearly this vulnerability. I will summary it for you. ( sorry if I cannot explain well ).
“HTTP is stateless protocol. How to save state of controls in ASP.NET Web Forms? When you request an ASP.NET page, it loads state of controls. Before the request is finished, ASP.NET serializes all state of controls (object) into string. And then it puts this string to a hidden input named __VIEWSTATE.
When user clicks some buttons for posting a request, before handling request by developer, in core of ASP.NET Web Forms framework, it reads __VIEWSTATE parameter and deserializes string into an object (actually a hash table which contains many key-value pairs). Developer can use this as VIEWSTATE variable. By default, __VIEWSTATE is protected by MAC. ASP.NET uses machineKey configuration in web.config for MAC key. But sadly, MAC checking is optional. We can turn off it globally or locally in each aspx page. And Sharepoint do it. Sharepoint turns off MAC checking in their webpage. So without MAC, user can send arbitrary __VIEWSTATE, ASP.NET will deserialize arbitrary input stream. That’s exactly vulnerability we have”.
2. .NET arbitrary deserializing vulnerability
I need to know how to turn an arbitrary deserialization into RCE. I am sure that you heard about PHP Object injection or Python Pickle or Java arbitrary deserialization. .NET counterpart is less famous. I use the paper of James Forshaw in Blackhat US 12 ( BH_US_12_Forshaw_Are_You_My_Type_Slides.pdf ) to study.
Here is the main idea:
__VIEWSTATE in ASP.NET use ObjectStateFomatter, then ObjectStateFormatter use BinaryFormatter internally. if MAC checking is disabled, we can deserialize arbitrary BinaryFormatter input stream.
When you deserialize a string into object by BinaryFormatter, sometimes in the deserialization process, some callbacks or special methods will be called.
For example, OnDeserialization callback will be called in the middle of process if your class implement IDeserializationCallback
Furthermore, deserialization constructor will be call in the early of process (Pay attention to special parameter type: SerializeInfo and StreamingContext).
Finally ( maybe, I’m not sure ), destructor ~TempFileCollection will be called when object is destroy.
Those are some typical cases, you can refer to James Forshaw’s paper for more cases. So we need to inspect all .Net framework classes or ASP.net framework classes, check every classes for finding a special class with special methods: OnDeserialization, serialize constructor, destructor. And you need to read their source code, understand the code flow to verify whether vulnerability exists. We call such vulnerability class as gadget, same concept as Java deserialize counterpart.
James Forshaw found many interesting class:
- System.CodeDom.Compiler.TempFileCollection for deleteing arbitrary file
- System.IO.FileSystemInfo for UNC request combined with PyResponder for NTLM hash grabbing.
- System.Management.IWbemClassObjectFreeThreaded for arbitrary COM object unmarshaling.
However, no gaget exists for RCE. I was very tired for checking and reading source code of so many classes in .NET framework. It seemed too difficult to me to find one. I did continue searching gadgets or blog, paper, …, anything related to .NET deserialization in about two days.
And boom! This tweet caught my eye:
OMG!, right time right place. That was exactly thing I need.
3. RCE .NET arbitrary deserialization
I will summary the content of Florian’s blog. He improved gadget System.Management.IWbemClassObjectFreeThreaded for arbitrary COM object unmarshalling. When you deserialize a IWbemClassObjectFreeThreaded object. The property flatWbemClassObject of that object will be read. It is a byte array. And then the function CoUnmarshalInterface will be called with that array. Something like that CoUnmarshalInterface(byte IWbemClassObjectFreeThreaded.flatWbemClassObject). Imagine that you control __VIEWSTATE, so you manipulate object IwbemClassObjectFreeThreaded, lead to control property flatWbemClassObject. Finally you control parameter of function CoUnmarshalInterface. By reversing and fuzzing format of that parameter, Florian found a POC allow to crash asp.net worker process w3wp.exe and control register RDI and RSI. However, I don’t understand the root cause of crash. Fortunately, it’s not necessary to turn this crash to fully remote code execution.
When we control the RDI and RSI, we can control flow of program from crash point. Florian found that he could control RIP when RDI point to a special structure :
How to find this structure in memory?
That’s difficult. But there is an exploit technique well-known in browser exploit: HEAP SPRAY.
By serializing 1.000.000 image contains that structure and put them into __VIEWSTATE. When asp.net deserializes this VIEWSTATE, we can make ASP.NET create 1.000.000 Bitmap in memory. So we can control a large part memory with arbitrary value. In fact, when I test this technique, I can control range memory from 0x20202020 – 0x50505050 with arbitrary value. So by pointing RDI to somewhere in range 0x20202020 – 0x50505050, we can control value of RIP.
However, what I can do when I can control RIP? Where should RIP point to?
Florian said he needed to control RSP register too. So he changed structure a little bit for controlling both RIP and RSP registers. I actually didn’t understand his structure. I just reused his structure and debug for rechecking result.
At this moment, we can control both RIP and RSP. Next, we will use ROPCHAIN technique for bypassing ASLR+DEP. Florian figured out that w3wp.exe load a non-ASLR dll whenever exception happening (diasymreader.dll). He also found a ropchain (VirtualMalloc + memcpy shellcode + execute shellcode).
We use HEAP SPRAY again to put ropchain in address range: 0x60606060 – 0x90909090 and shellcode in range 0xa0a0a0a0-0xc0c0c0c0. We point RIP and RSP to ropchain address. After all, exploit worked as expected.
5. Improving exploit in real world
For real world exploit, I changed the exploit to add some functions:
- Run exploit to kill process w3wp.exe first. System will restart w3wp.exe. Heap memory will be in determined state. So HEAP SPRAY will be more accuracy. We only need to point RIP to ExitProcesss.
- Next, run exploit to make an exception. So w3wp.exe will load diasymreader.dll.
- Finally , run exploit RCE and remember, run at midnight when nobody access webpage.
- Use a tiny shellcode to write file. We will write a webshell in this folder “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\isapi\anonsvc”. This folder don’t need authentication any way. So webshell is always accessible.
- Test many versions to understand HEAP SPRAY address range, so I can choose address better: Sharepoint 2010 (no SP, SP1, SP2), Exchange 2010 (no SP, SP1) in Windows 2008 R2, Windows 2008 R2 SP1.
6. Timeline (aproxiately, not exactly correct)
- 1st day, learn .NET deserialize and all related stuff.
- 2nd day, install Sharepoint, Exchange (version 2010, 2013, SP and no SP). Buy new 8GB Ram for running Sharepoint efficiently.
- 3rd day, test basic VIEWSTATE deserialize (arbitrary delete file gadget, UNC request gadget, XXE gadget)
- 4th day – 7th day: test crash, test heapspray, test RCE
- 8th day: improving exploit chains: kill process first
- 9th day: waiting midnight at 12PM, and exploit target. Got webshell !!!!
This is my exploit code: Exploit.py
If you cannot run exploit code, don’t worry because of even me can’t understand it anymore.
Note: Over the year, many gadgets have been found by some good guys. And now I have a more reliable exploit – no need crash, control register, heapspray, ropchain, always work. I will blog it in the future.
By the way, this is still my favorite exploit because I learned so much things from it. And I guess the following advisories have same .NET deserialization issue, but other attack vectors: MS13-100, MS13-105, MS14-022, Ms14-024, MS15-047