0x00 Preface
---
In actual penetration testing scenarios, we encounter various environments, such as obtaining file read/write permissions on an Exchange server but being unable to execute commands.
This article will provide an implementation method, analyze exploitation approaches, detail script development, and offer defense recommendations.
0x01 Introduction
---
This article will cover the following topics:
- Solution Approach
- Exploitation Methods
- Program Implementation
- Defense Recommendations
0x02 Solution Approach
---
1. Conventional Solution Approach
(1) Writing Webshell
Typically choose the following two locations:
- %ExchangeInstallPath%\FrontEnd\HttpProxy\owa\auth
- %ExchangeInstallPath%\FrontEnd\HttpProxy\ecp\auth
The advantage of choosing these two locations is that the webshell can be accessed directly.
Other locations can also be chosen, such as %ExchangeInstallPath%\ClientAccess\ecp\, but there are restrictions on the file name; the naming rules can be referenced from %ExchangeInstallPath%\ClientAccess\ecp\web.config.
Note:
Accessing a webshell under %ExchangeInstallPath%\ClientAccess\ requires adding a valid user's login cookie.
In summary, the method of writing a webshell is relatively straightforward, but the Exchange server may have disabled command execution permissions or blocked system function calls, still preventing command execution.
(2) Writing PE Files
Writing an exe file, you can choose the following two startup folders:
- System startup folder location: %ProgramData%\Microsoft\Windows\Start Menu\Programs\Startup
- User startup folder location: %USERPROFILE%\Appdata\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
Writing a dll file, you can choose common system dll hijacking locations, such as c:\Windows\System32\fxsst.dll. For more details, refer to: an open-source project.
In summary, the method of writing PE files is relatively passive, requiring the system to load them, and cannot achieve real-time command execution.
2. Effective Solution Approach
Modify Exchange configuration, set MachineKey, achieve command execution via .NET deserialization
Learning resources:
http://www.zcgonvh.com/post/weaponizing_CVE-2020-0688_and_about_dotnet_deserialize_vulnerability.html
https://blog.knownsec.com/2020/11/net-%e5%8f%8d%e5%ba%8f%e5%88%97%e5%8c%96%e4%b9%8b-viewstate-%e5%88%a9%e7%94%a8/
In simple terms, by setting the MachineKey, we can achieve the same effect as CVE-2020-0688. That is, after setting the MachineKey to the default value, we can directly use CVE-2020-0688 exploitation tools to achieve command execution.
0x03 Exploitation Method
---
1. Modify %ExchangeInstallPath%\ClientAccess\ecp\web.config
Change to
If this attribute does not exist, add under system.web
After that, you can directly use CVE-2020-0688 exploitation tools. A mature tool to choose is: https://github.com/zcgonvh/CVE-2020-0688/. Compared to other open-source exploitation tools, this tool can obtain command execution results in real-time and also supports loading shellcode functionality. The technical details are worth in-depth study.
Note:
Most CVE-2020-0688 exploitation tools rely on ysoserial.net's TextFormattingRunProperties to achieve command execution, but cannot obtain command execution results in real-time.
ysoserial.net-1.32's ActivitySurrogateSelectorFromFile can load .NET assemblies via Assembly.Load to return command execution results, but its compatibility is insufficient and does not support all versions of the .NET environment.
zcgonvh's open-source CVE-2020-0688 exploitation tool resolves the ActivitySurrogateSelectorFromFile compatibility issue in ysoserial.net-1.32, while also implementing AES encryption for communication data.
ysoserial.net-1.33 fixes the ActivitySurrogateSelectorFromFile compatibility bug, which was resolved by zcgonvh.
We know that exploiting CVE-2020-0688 requires obtaining credentials of a legitimate user. However, we only have file read/write permissions on the Exchange server and cannot immediately obtain legitimate user credentials. The following two methods can be used to bypass this restriction.
(1) Modify %ExchangeInstallPath%\FrontEnd\HttpProxy\owa\web.config
Change to
Here, validationKey and decryptionKey can be arbitrarily specified, with characters ranging from hexadecimal (0~F).
The following algorithms can also be selected:
- MD5
- AES
- HMACSHA256
- HMACSHA384
- HMACSHA512
Key length must meet algorithm requirements. Reference material:
https://devblogs.microsoft.com/aspnet/cryptographic-improvements-in-asp-net-4-5-pt-1/
(2) Modify %ExchangeInstallPath%\FrontEnd\HttpProxy\ecp\web.config
Same as above
For the .Net deserialization command execution at these two locations, legitimate user credentials are no longer required, so the exploit program also needs to be modified. The following details three implementations of the exploit program.
0x04 Implementation Details
---
1. Two Methods to Calculate VIEWSTATEGENERATOR
Exchange's .Net deserialization uses ViewState, where the essential parameter is VIEWSTATEGENERATOR. For example, the default VIEWSTATEGENERATOR used in the Python exploit tool for CVE-2020-0688 is B97B4E27, representing the page ecp/default.aspx, corresponding to the ysoserial.net parameter --path="/ecp/default.aspx" --apppath="/ecp/".
The following introduces two methods to calculate VIEWSTATEGENERATOR:
The C# implementation code is as follows:
using System; |
The result is B97B4E27
Note:
Code from http://www.zcgonvh.com/post/weaponizing_CVE-2020-0688_and_about_dotnet_deserialize_vulnerability.html
It can also be calculated automatically via webpage, method as follows:
In the actual test environment, modify the content of ecp/default.aspx as follows:
|
Access the page via browser, the __VIEWSTATEGENERATOR in the returned result is the computed value
2. Three deserializer implementations that do not require valid user credentials
(1) Python code for command execution using ysoserial.net's TextFormattingRunProperties
The parameter format corresponding to ysoserial.net in CVE-2020-0688 is as follows:
ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "{command}" --validationalg="SHA1" --validationkey="CB2721ABDAF8E9DC516D621D8B8BF13A2C9E8689A25303BF" --generator="{generator}" --viewstateuserkey="{}" |
Since our exploitation does not require valid user credentials, the new ysoserial.net parameter format is:
ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "{command}" --validationalg="SHA1" --validationkey="{key}" --generator="{generator}" |
The parameter descriptions are as follows:
- {command} corresponds to the command we want to execute
- {key} corresponds to the validationKey we set
- {generator} corresponds to the VIEWSTATEGENERATOR of the page to be accessed
After generating the final VIEWSTATE data using ysoserial.net's TextFormattingRunProperties, concatenate it into the following format:
https://{url}?__VIEWSTATEGENERATOR={generator}&__VIEWSTATE={out_payload} |
Send a GET request packet
The following is an example for illustration:
Select the default error page for Exchange: %ExchangeInstallPath%\FrontEnd\HttpProxy\owa\auth\errorFE.aspx
The VIEWSTATEGENERATOR corresponding to owa\auth\errorFE.aspx is 042A94E8
Generate the final VIEWSTATE data using ysoserial.net's TextFormattingRunProperties
The final accessed URL is: https:///owa/auth/errorFE.aspx?__VIEWSTATEGENERATOR=042A94E8&__VIEWSTATE={out_payload}
The complete implementation code has been uploaded to GitHub, with the address as follows:
An open-source project
The code supports deserialization execution at two locations: the default existing file %ExchangeInstallPath%\FrontEnd\HttpProxy\owa\auth\errorFE.aspx and %ExchangeInstallPath%\FrontEnd\HttpProxy\ecp\auth\TimeoutLogout.aspx
Note:
Since we have obtained file read and write permissions on the Exchange server, the code results can be output to a specified file for viewing. Example command: net user /domain >c:\test.txt
(2) Python code that uses ysoserial.net's ActivitySurrogateSelectorFromFile to execute commands and return results
The version of ysoserial.net used here must be higher than 1.32 to avoid compatibility bugs with ActivitySurrogateSelectorFromFile
Create a new file ExploitClass.cs with the following content:
class E |
Note:
Code referenced from https://devco.re/blog/2020/03/11/play-with-dotnet-viewstate-exploit-and-create-fileless-webshell/
For more usage, refer to https://github.com/pwntester/ysoserial.net/blob/master/ExploitClass/ExploitClass.cs
The parameter format for ysoserial.net is as follows:
ysoserial.exe -p ViewState -g ActivitySurrogateSelectorFromFile -c "ExploitClass.cs;System.Web.dll;System.dll;" --validationalg="SHA1" --validationkey="{key}" --generator="{generator}" |
After generating the final VIEWSTATE data using ysoserial.net's ActivitySurrogateSelectorFromFile, construct a POST data packet, add a parameter named cmd with the value being the command to execute
Higher versions of .NET Framework will block ActivitySurrogateSelector, which can be bypassed using ysoserial.net's ActivitySurrogateDisableTypeCheck. The corresponding parameter format is as follows:
ysoserial.exe -p ViewState -g ActivitySurrogateDisableTypeCheck -c "ignore" --validationalg="SHA1" --validationkey="{key}" --generator="{generator}" |
The complete implementation code has been uploaded to GitHub at the following address:
An open-source project
The code supports deserialization execution at two locations: the default existing files %ExchangeInstallPath%\FrontEnd\HttpProxy\owa\auth\errorFE.aspx and %ExchangeInstallPath%\FrontEnd\HttpProxy\ecp\auth\TimeoutLogout.aspx
The code can execute commands and obtain command execution results. Data is sent via POST with the parameter __Value, and communication data is encrypted using character-by-character XOR encryption.
(3) C# code for credentialless exploitation based on https://github.com/zcgonvh/CVE-2020-0688/
The VIEWSTATE data generation process remains consistent with https://github.com/zcgonvh/CVE-2020-0688/, requiring only the validationkey to be passed as a variable.
Both %ExchangeInstallPath%\FrontEnd\HttpProxy\owa\web.config and %ExchangeInstallPath%\FrontEnd\HttpProxy\ecp\web.config do not restrict POST requests, so exploitation no longer requires writing empty files. The final VIEWSTATE data can be generated directly and sent via POST.
The complete implementation code has been uploaded to GitHub at the following address:
An open-source project
The code supports deserialization execution at two locations: the default existing files %ExchangeInstallPath%\FrontEnd\HttpProxy\owa\auth\errorFE.aspx and %ExchangeInstallPath%\FrontEnd\HttpProxy\ecp\auth\TimeoutLogout.aspx
The supported features remain consistent with https://github.com/zcgonvh/CVE-2020-0688/
0x05 Defense and Detection
---
After an Exchange server is compromised, it is necessary not only to scan for suspicious webshells but also to determine whether the machineKey in web.config has been modified.
0x06 Summary
---
This article presents a method for achieving command execution from Exchange file read/write permissions, analyzes the exploitation approach, details the development of three exploitation scripts, and provides defense recommendations.