Chromium is finally out!! This is the moment I've been waiting for. I can now share the details of the project I've been working on: The Chromium sandbox.
As you know, Chromium is open source, so is its sandbox. I welcome everyone to take a look at the code, contribute patches, suggest improvements, find security bugs and most importantly, USE IT. Yes, the sandbox is not tied to chromium; it can be easily reused by any projects in need of a sandboxing solution. In the next posts I will present different parts of the Chromium sandbox in details, and I will be talking more about how to integrate the sandbox with any application.
Before going into the details, you must understand the high level architecture of Chromium, and what part of it is running in the sandbox. The best way to learn about this is to read the comic book!
The official website also has a lot of good information on Chromium and the sandbox, like our design document.
This is it for now! Try Google Chrome!
I'll be back with more information about the sandbox soon!
Tuesday, September 2, 2008
Google Chrome and the Chromium Sandbox
Posted by nsylvain at 9:38 PM 0 comments
Sunday, January 20, 2008
Namedpipe Impersonation Attack
Privilege escalation through namedpipe impersonation attack was a real issue back in 2000 when a flaw in the service control manager allowed any user logged onto a machine to steal the identify of SYSTEM. We haven't heard a lot about this topic since then, is it still an issue?
First of all, let's talk about the problem.
When a process creates a namedpipe server, and a client connects to it, the server can impersonate the client. This is not really a problem, and is really useful when dealing with IPC. The problem arises when the client has more rights than the server. This scenario would create a privilege escalation. It turns out that it was pretty easy to accomplish.
For example, let's assume that we have 3 processes: server.exe, client.exe and attacker.exe. Server.exe and client.exe have more privileges than attacker.exe. Client.exe communicates with server.exe using a namedpipe. If attacker.exe manages to create the pipe server before server.exe does, then, as soon as client.exe connects to the pipe, attacker.exe can impersonate it and the game is over.
Fortunately, Microsoft implemented and recently documented some restrictions and tools to help you manage the risk.
First of all there are some flags buried in the CreateFile documentation to give control to the pipe client over what level of impersonation a server can perform. They are called the "Security Quality Of Service".
There are 4 flags to define the impersonation level allowed.
SECURITY_ANONYMOUS
The server process cannot obtain identification information about the client, and it cannot impersonate the client.
SECURITY_IDENTIFICATION
The server process can obtain information about the client, such as security identifiers and privileges, but it cannot impersonate the client. ImpersonateNamedpipeClient will succeed, but no resources can be acquired while impersonating the client. The token can be opened and the information it contains can be read.
SECURITY_IMPERSONATION - This is the default
The server process can impersonate the client's security context on its local system. The server cannot impersonate the client on remote systems.
SECURITY_DELEGATION
The server process can impersonate the client's security context on remote systems.
There are also 2 other flags:
SECURITY_CONTEXT_TRACKING
Specifies that any changes a client makes to its security context is reflected in a server that is impersonating it. If this option isn't specified, the server adopts the context of the client at the time of the impersonation and doesn't receive any changes. This option is honored only when the client and server process are on the same system.
SECURITY_EFFECTIVE_ONLY
Prevents a server from enabling or disabling a client's privilege or group while the server is impersonating.
Note: Since the MSDN documentation for these flags is really weak, I used the definition that can be found in the book "Microsoft® Windows® Internals, Fourth Edition" by Mark Russinovich and David Solomon.
Every time you create a pipe in client mode, you need to find out what the server needs to know about you and pass the right flags to CreateFile. And if you do, don't forget to also pass SECURITY_SQOS_PRESENT, otherwise the other flags will be ignored.
Unfortunately, you don't have access to the source code of all the software running on your machine. I bet there are dozen of software running on my machine right now opening pipes without using the SQOS flags. To "fix" that, Microsoft implemented some restrictions about who a server can impersonate in order to minimize the chances of being exploited.
A server can impersonate a client only if one of the following is true.
- The caller has the SeImpersonatePrivilege privilege.
- The requested impersonation level is SecurityIdentification or SecurityAnonymous.
- The identity of the client is the same as the server.
- The token of the client was created using LogonUser from inside the same logon session as the server.
Only Administrators/System/SERVICES have the SeImpersonatePrivilege privilege. If the attacker is a member of these groups, you have much bigger problems.
The requested impersonation level in our case is SecurityImpersonation, so the second point does not apply.
That leaves us with the last two conditions. Should we worry about them? I think so. Here are some examples:
I'm on XP. I want to run an untrusted application. Since I read my old posts, I know that I can run the process using a stripped down version of my token. Unfortunately, my restricted token has the same identity as the normal token. It can then try to exploit all applications running on my desktop. This is bad.
My main account is not administrator on the machine. When I want to install software, I use RunAs. This brings up a new problem. RunAs uses LogonUser, and it is called from the same logon session! That means that my untrusted application using a restricted token derived from a standard user token can now try to exploit and impersonate a process running with administrator rights! This is worse.
But how real is all this?
This is hard to say. I don't have an idea about the percentage of applications using the SQOS flags. We must not forget that allowing impersonation is also required and desired in certain cases.
For fun I took the first application using namedpipes that came to my mind: Windbg. There is an option in Windbg to do kernel debugging and if the OS you are debugging is inside vmware, you can specify the namedpipe corresponding the COM1 port of the vmware image. By default it is "com_1". My untrusted application running with the restricted token was now listening on com_1, and, easy enough, as soon as I started windbg, the untrusted application was able to steal its token.
To be fair I have to say that vmware displayed an error message telling me that the com_1 port was "not configured as expected". I should not have started windbg knowing that. But, eh, who reads error messages? :)
What should we do now?
Well, it turns out that Microsoft implemented two new restrictions in windows Vista to fix these problems. I don't think they are documented yet.
- If the token of a server is restricted, it can impersonate only clients also running with a restricted token.
- The server cannot impersonate a client running at a higher integrity level.
These new restrictions are fixing both my issues. First of all my untrusted application can't be running with a restricted token anymore. Then, even if the untrusted application is running with my standard token, it won't be able to impersonate the processes that I start with the "Run As Administrator" elevation prompt because they are running with a High Integrity Level.
Now it is time to come back to the main question: Is it still an issue?
My answer is yes. Windows XP is still the most popular Windows version out there and there is no sign that Vista is going to catch up soon. But I have to admit that I'm relieved to see the light at the end of the tunnel!
--
Some technical details:
When you call ImpersonateNamedPipeClient and none of the conditions is met, the function still succeeds, but the impersonation level of the token is SecurityIdentification.
If you want to try for yourself, you can find the code to create a server pipe and a client pipe on my code page.
Related link:
Impersonation isn't dangerous by David Leblanc
Posted by nsylvain at 4:54 PM 5 comments
DuplicateHandle and Access Mask.
What happens if you ask for MAXIMUM_ALLOWED?
The function succeeds, but the handle created does not have any granted access. This is not really useful.
Not all object types support the same flags in an access mask, what happens if you specify a mask that contains invalid flags?
It depends...
The function fails if you use any of these flags:
0x00200000 = Unused standard right
0x00400000 = Unused standard right
0x00800000 = Unused standard right
0x01000000 = ACCESS_SYSTEM_SECURITY [You need a privilege]
0x04000000 = Reserved
0x08000000 = Reserved
But if you don't, any other invalid flags are ignored and the call succeeds. The granted access is the union of all the valid flags present in the mask. It also means that if you duplicate the handle using invalid flags only, the handle will be created without any granted access.
That said, in my previous post I talked about why you should not use PROCESS_ALL_ACCESS anymore on Windows XP. This is not true for the DuplicateHandle call, you can still use it since the new flag 0xF000 will be ignored on previous version of the OS.
Posted by nsylvain at 10:06 AM 1 comments
Saturday, January 12, 2008
WINVER Mayhem. The PROCESS_ALL_ACCESS problem.
Suppose that you want to use a something that is defined only when you have _WIN32_WINNT=0x600. What do you do?
There are 3 options:
1. Copy the definition manually to one of your file. This is not clean. I hope I won't have to do this.
2. Create one build per OS version. Each of them will define _WIN32_WINNT accordingly and you just have to be sure that the code specific to an OS version is inside an #IF _WIN32_WINNT >= VERSION. This makes sense, but this is a lot of troubles. Who wants to have multiple sets of exes and dlls and ship different binaries depending on the user configuration.
3. Define _WIN32_WINNT to the highest value (0x0600 for Vista in this case), and make sure that you don't use unsupported functions/structures on previous version. You need to use GetVersionEx to get the OS version and use GetProcAddress to get the address of the functions that are not defined in prior versions.
The third option is the one that I've seen most of the time. Unfortunately, changing the value of _WIN32_WINNT to 0x0600 is causing some unexpected problems.
One example is the define for PROCESS_ALL_ACCESS. It looks like this:
#if (NTDDI_VERSION >= NTDDI_LONGHORN)
#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
0xFFFF)
#else
#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
0xFFF)
#endif
They changed the mask on Vista to include 0xF000. 0xF000 contains 3 unused flags and the new PROCESS_QUERY_LIMITED_INFORMATION.
Why is this a problem?
Suppose that your code is doing this:
OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
This call is now going to fail on XP and 2000 because you are trying to open a process with 0xF000, and you don't have that access on the process.
You need to fix all PROCESS_ALL_ACCESS occurences in your code. The same problem exists with THREAD_ALL_ACCESS.
What would have been a better solution? I thought PROCESS_QUERY_LIMITED_INFORMATION was only a subset of PROCESS_QUERY_INFORMATION already present in the mask. Did they really need to add it? Could they have used GENERIC_ALL instead? As we saw in this earlier post, GENERIC_ALL can mean different things on different OS versions.
Posted by nsylvain at 11:17 AM 1 comments
Sunday, January 6, 2008
More GENERIC_MAPPING changes on vista
For reference, these are the changes:
TOKEN:
Windows XP Windows Vista
+-----------------+-------------------+---------------------------+
GENERIC_EXECUTE READ_CONTROL READ_CONTROL
ASSIGN_PRIMARY
IMPERSONATE
+-----------------+-------------------+---------------------------+
GENERIC_READ READ_QUERY READ_QUERY
READ_CONTROL READ_CONTROL
DUPLICATE
QUERY_SOURCE
+-----------------+-------------------+---------------------------+
GENERIC_WRITE ADJUST_PRIVILEGES ADJUST_PRIVILEGES
ADJUST_GROUPS ADJUST_GROUPS
ADJUST_DEFAULT ADJUST_DEFAULT
READ_CONTROL READ_CONTROL
ADJUST_SESSIONID
+-----------------+-------------------+---------------------------+
Note: The TOKEN_ prefix has been removed.
THREAD:
Windows XP Windows Vista
+-----------------+-------------------+---------------------------+
GENERIC_EXECUTE READ_CONTROL READ_CONTROL
SYNCHRONIZE SYNCHRONIZE
QUERY_LIMITED_INFORMATION
+-----------------+-------------------+---------------------------+
GENERIC_READ GET_CONTEXT GET_CONTEXT
QUERY_INFORMATION QUERY_INFORMATION
READ_CONTROL READ_CONTROL
+-----------------+-------------------+---------------------------+
GENERIC_WRITE TERMINATE TERMINATE
SUSPEND_RESUME SUSPEND_RESUME
SET_CONTEXT SET_CONTEXT
SET_INFORMATION SET_INFORMATION
READ_CONTROL READ_CONTROL
0x00000004 0x00000004
SET_LIMITED_INFORMATION
+-----------------+-------------------+---------------------------+
Note: The THREAD_ prefix has been removed.
KEY:
Windows XP Windows Vista
+-----------------+-------------------+---------------------------+
GENERIC_EXECUTE QUERY_VALUE QUERY_VALUE
ENUMERATE_SUB_KEYS ENUMERATE_SUB_KEYS
NOTIFY NOTIFY
READ_CONTROL READ_CONTROL
CREATE_LINK
+-----------------+-------------------+---------------------------+
GENERIC_READ QUERY_VALUE QUERY_VALUE
ENUMERATE_SUB_KEYS ENUMERATE_SUB_KEYS
NOTIFY NOTIFY
READ_CONTROL READ_CONTROL
+-----------------+-------------------+---------------------------+
GENERIC_WRITE SET_VALUE SET_VALUE
CREATE_SUB_KEY CREATE_SUB_KEY
READ_CONTROL READ_CONTROL
+-----------------+-------------------+---------------------------+
Note: The KEY_ prefix has been removed.
You want to dump the GENERIC_MAPPING structure for other object types? You can find the code on http://nsylvain.googlepages.com/.
Posted by nsylvain at 6:56 PM 0 comments
You can terminate a higher integrity process.
No-Execute-Up is not present though. What does it buy us?
If it was on Windows XP, then not much, but on Vista the Generic Mapping structures have changed. Let's take a look at them side by side for the "Process" object type on XP and Vista.
Windows XP Windows Vista
+-----------------+-------------------+---------------------------+
GENERIC_EXECUTE READ_CONTROL READ_CONTROL
SYNCHRONIZE SYNCHRONIZE
TERMINATE
QUERY_LIMITED_INFORMATION
+-----------------+-------------------+---------------------------+
GENERIC_READ VM_READ VM_READ
QUERY_INFORMATION QUERY_INFORMATION
READ_CONTROL READ_CONTROL
+-----------------+-------------------+---------------------------+
GENERIC_WRITE CREATE_THREAD CREATE_THREAD
VM_OPERATION VM_OPERATION
VM_WRITE VM_WRITE
DUP_HANDLE DUP_HANDLE
CREATE_PROCESS CREATE_PROCESS
SET_QUOTA SET_QUOTA
SET_INFORMATION SET_INFORMATION
SUSPEND_RESUME SUSPEND_RESUME
READ_CONTROL READ_CONTROL
TERMINATE
+-----------------+-------------------+---------------------------+
note: the prefix PROCESS_ has been removed.
http://msdn2.microsoft.com/en-us/library/ms684880(VS.85).aspx
As you can see GENERIC_EXECUTE has changed and now gives TERMINATE access. You can then kill processes with a higher integrity level!
For completeness, PROCESS_QUERY_LIMITED_INFORMATION allows you to query the full process image name.
Posted by nsylvain at 4:20 PM 0 comments
Saturday, January 5, 2008
The integrity drop - or - How to disable UIPI take 2
What if you don't want that? Maybe you already have another plan for UI protection? Running in a job for example.
There is the easy way: [From MSDN]
By specifying UIAccess=”true” in the requestedPrivileges attribute [of the application manifest], the application is stating a requirement to bypass UIPI restrictions on sending window messages across privilege levels. Windows Vista implements the following policy checks before starting an application with UIAccess privilege.
The application must have a digital signature that can be verified using a digital certificate that chains up to a trusted root in the local machine Trusted Root
Certification Authorities certificate store.
The application must be installed in a local folder application directory that is writeable only by administrators, such as the Program Files directory.
Unfortunately this is not going to work if you application can be installed by non-admin users.
Fortunately, there is another (not documented) way to "disable" UIPI.
Windows initializes UIPI during the process startup. If you create the process with a low integrity level, then UIPI will prevent it from accessing windows owned by medium/high integrity level processes.
But no one said that it was not possible to change the integrity level of a process AFTER it is started. If you own the process, and you trust that it's not going to run any potentially malicious piece of code before main(), you can add code at the beginning of your main() to drop the integrity level. From now on, the process is going to run with the new integrity level and UIPI won't be updated.
Dropping the integrity level is easy:
Get a handle to the process token using OpenProcessToken and call SetTokenInformation on it with the TokenIntegrityLevel information class to set the new integrity level.
But this is not all. If you only do this, your process won't be able to play sound. This is because when you play sound, audiodg.exe creates some objects on your behalf. At some point it will impersonate your token and open your process. Since your process was created with a medium integrity level token, the integrity/mandatory label on the process is Medium. When audiodg tries to open your process with your token, it does not have access and it fails.
What you must do is change the security label on the process to be low integrity level. The easy way to do this is to create a SDDL string for the integrity label and to follow the code in this example. You should use this SDDL string: "S:(ML;;NWNR;;;LW)" It means that it's a SDDL for a SACL (S:), with a Mandatory Label ace type (ML), the ace access is No-Write-Up and No-Read-Up (NWNR) and the integrity level is low (LW). The example is using NW instead of NWNR but for a process it's better to prevent lower privileges processes from being able to read it's process memory.
Posted by nsylvain at 10:06 AM 3 comments