Software applications that consist of multiple components running with different privileges are susceptible to luring attacks. This attack consists on tricking the application into executing privileged actions on behalf of an attacker. The attacker commonly uses a less privileged component to lure a higher privileged component into executing the malicious instructions. Thus, this attack is a case of escalation of privileges.
Follow these steps to test for luring bugs:
- Step 1: Understand attack scenarios
- Step 2: Analyze causes and countermeasures
- Step 3: Start testing and exploring
Step 1: Understand Attack Scenarios
The first step in learning how to test for luring bugs is to understand the different types of luring attack scenarios:
- Exploiting delegation of scheduled tasks
- Exploiting impersonation
Scenario 1: Exploiting delegation of scheduled tasks
Many software applications allow for the creation of tasks that are scheduled to execute at a later time by a separate component of the application. In some cases, the separate component executes these tasks with higher privileges, which opens a window for luring attacks. In this scenario, an attacker uses the scheduled tasks functionality with the goal of having the application run tasks with higher privileges than what the attacker would normally have.
A good example of this luring scenario affecting Microsoft SQL Server was discovered by David Litchfield in 2002 [i]. Under some configurations, SQL Server executes two separate processes: one for the actual database server and one for the SQL Server Agent. The issue was due to the fact that remote users had access to an extended procedure named xp_runwebtask that could be used to insert tasks to be executed by the SQL Server Agent. Attackers were able to execute this stored procedure with low privileges, set up a malicious task that required higher privileges to execute, and then waited for the agent to pick up and execute the task. A similar bug, affecting the Symantec LiveUpdate client, was discovered in late 2004. The bug allowed low privileged clients to use the LiveUpdate GUI to set up a scheduled task. The maliciously set up tasks were later run by the LiveUpdate agent at higher privileges, resulting in a luring attack [ii].
Scenario 2: Exploiting impersonation
To reduce their privileged attack surface, software applications run with low privileges and impersonate higher privileged accounts only to perform certain tasks, and then revert to their lower privileges. In this scenario, the attacker tricks the application into creating certain tasks that will execute while the application is impersonating the higher privileged account.
Step 2: Analyze Causes and Countermeasures
Next, before executing test cases, it is necessary to understand what causes luring bugs and how to protect against them.
In most cases, applications are vulnerable to luring attacks due to insecure design choices rather than to incorrect implementation. Specifically, vulnerable applications allow a low privileged piece of code set up instructions or scheduled tasks to be executed later by the application. For instance, both the SQL Server and Symantec scenarios explained above happened because the application allowed configuring tasks by a user with low privileges while executing the actual tasks with a higher privileged account. To protect against this, architects and developers must look at the application’s implementation of delegation and task scheduling, and restrict the creation of any tasks that execute at high privileges to high privileged accounts only.
Another common cause of luring attacks is due to an application impersonating a higher privileged account and executing instructions or tasks that were created at a time when the application was running with low privileges -- thereby allowing low privileged users to create the tasks. To defend against this variation, developers must revise the application’s design and implementation so that all of the instructions that execute while impersonating a higher account are not allowed to be created or modified by users with low privileges.
Microsoft .NET applications
Microsoft .NET applications work by integrating different assemblies into a single process, each assembly having its own privilege levels and permissions. For instance, some assemblies may run with minimum privileges such as a “partially trusted assembly” and have restricted access to system resources, while others may have more privileges such as a “fully trusted assembly” and have unlimited access to system resources. The .NET framework protects against luring attacks from untrusted assemblies using implicit LinkDemands that walk the stack before executing privileged commands across assemblies, checking that all assemblies in the stack have the appropriate permissions. Therefore, when an attacker uses a malicious, non-trusted assembly hosted on a remote site to call a fully trusted assembly installed in a target client’s local machine to perform a privileged action, the runtime checks the stack, determines that the caller is non-trusted, and throws a security exception to protect the target.
The problem with implicit demands is that they generated deployment issues, since developers needed to have partially trusted assemblies calling fully trusted assemblies without actually assigning them full trust. The solution for this issue came with the assembly attribute named AllowPartiallyTrustedCallers (APTCA) in the Microsoft .NET Framework 1.1 release. By using this attribute, any fully trusted assembly could let partially trusted callers use it without throwing a security exception.
Nevertheless, even though APTCA mitigates the deployment problem, it reintroduces luring attacks to the .NET environment if improperly used. A developer that uses APTCA in an assembly without changing the assembly’s code is increasing its attack surface and the chances of a luring attack. To protect against this scenario, developers who use APTCA must take additional security measures by using explicit Demands before any high privileged instruction. By doing this, developers are able to mark trusted assemblies as APTCA while preventing non-trusted assemblies from executing luring attacks. [iii]
Step 3: Start Testing and Exploring
Now that you’ve learned all the theoretical aspects of luring attacks, it is necessary to execute test cases to test for them in your application.
Test for luring by modifying scheduled tasks store (local test)
Follow these steps to test for luring through scheduled tasks:
- Log in to the system as a high privileged user.
- Monitor the application to determine where it stores any scheduled tasks. For this step you can use a file system/registry monitoring tool such Process Monitor (from www.sysinternals.com).
- Check the access to scheduled task store. Continue with step 3 if access is allowed to a low privileged user. If access is limited to high privileged users, end test case.
- Log out from high privileged account and log back in as a low privileged user.
- Create a scheduled task by directly modifying the store (file, registry, database table, etc.).
- Wait for the application to pick up and execute task.
Expected results: The application is vulnerable if it executes the task created in step 5.
Test for luring by using application’s functionality to schedule a task (local test)
Follow these steps to test for luring through scheduled tasks:
- Log in to the system as a low privileged user.
- Monitor the application to determine how and when the application stores any scheduled tasks. For this step you can use a file system/registry monitoring tool such Process Monitor (from www.sysinternals.com). The goal here is to find an application functionality that allows low privileged users to create a task (similar to the SQL server agent and LiveUpdate scenarios mentioned previously).
- Create a task using the application’s functionality. Continue with step 4 if you were able to create a scheduled task. If you could not create a scheduled task, end test case.
- Wait for application to pick up and execute the task with higher privileges that the ones used during step 1.
Expected results: The application is vulnerable if it executes the task created in step 3 with higher privileges.
Test for luring through impersonation (local test)
Follow these steps to test for luring through impersonation:
- Log in to system as a high privileged user.
- Start debugging the application under test, setting breakpoints in all impersonation APIs.
- Use the application to see if it impersonates a higher privileged account. If it does impersonation, it will break into the debugger. If it doesn’t break into the debugger, end the test case.
- Check if there are any commands that execute while impersonating a higher privileged account. Continue with step 5 if these commands exist. If no such commands exist, end the test case.
- Modify a command found in step 4 to see if it gets executed with higher privileges.
Expected results: The application is vulnerable if it executes the privileged commands modified in step 5.
Test for luring from a remote assembly (Microsoft .NET test)
Follow these steps to test for luring through an assembly hosted in a remote site:
- Discover a local assembly that executes high privileged actions.
- Create an ASP .NET page/assembly that invokes the local assembly and calls into a function that executes a high privileged action.
- Create a malicious site to host the page developed in step 2.
- Log in to target machine.
- Open a browser and navigate to the page created in step 3.
Expected results: The application is vulnerable if it executes the privileged actions invoked in step 2.
Luring attacks consist of using a low privileged account to lure a vulnerable application into executing actions with high privileges. The two most noticeable scenarios consist of exploiting delegation of scheduled tasks and remotely invoking high privileged .NET classes/assemblies. These bugs occur primarily due to insecure design decisions such as storing tasks in insecure stores or allowing low privileged users to create tasks that will be delegated to higher privileged components. In .NET, these bugs exist due to an incorrect marking of assemblies, which allows partially trusted code to call them without taking the appropriate security measures.
Testing for luring bugs requires 1) investigating how the program interacts with its environment, including the file-system, registry, and database servers, to find out how tasks are delegated and stored; 2) investigating how the application under test performs any tasks while impersonating; 3) modifying any tasks that may be executed with higher privileges using a low privileged account. To test for .NET scenarios, it is necessary to develop an ASP application that calls into a fully trusted assembly to lure it into executing code at a higher privilege than it normally should.
[i] Microsoft SQL allows privilege escalation. Secunia. http://secunia.com/advisories/7325/
[ii] Symantec Windows LiveUpdate NetDetect Privilege Escalation. Secunia. http://secunia.com/advisories/13445/
[iii] Use of APTCA. MSDN Blogs - A Bull’s View of Life and Technology. http://blogs.msdn.com/ashishme/archive/2006/06/09/623840.aspx