For the few last days people talk about the somewhat innovative idea of Google - every displayed tab (webpage) is handled by a different process. As I wrote before, personally I like the idea, so I decided to use the open-sourceness of Chrome and see what's inside. It looks like every renderer (the tab handling process) works with very restricted privileges. As one can read in the design document linked above, there are four Windows features in use (didn't have time yet to look inside Chrome for other OSes):
Tokens: Only to tokens remain accessible - Logon SID (Mandatory) and NULL SID (S-1-0-0, Mandatory, Restricted). The rest of SIDs has 'Deny' set. Also all the privileges are removed (Se*).
Job objects: I think just everything possible was limited - there are limits for the Desktop, Display Settings, Exit Windows, Global Atoms, USER Handles, Read/Write Clipboard, System Parameters and Administrator Access.
Alternate desktops: Additionally the new process is attached to a newly created desktop. Thanks to that, the process cannot send messages to other user processes (because a process cannot send messages to an outside desktop, where all the other processes exist).
Integrity levels: This is available only on Vista (and 2008 ofc) - the renderers work with lower integrity set.
Additionally to that, the guys at Google created some hook mechanism, which they user to hook some functions from ntdll.dll and kernel32.dll. The hooks are created for the following functions:
(NT) NtCreateFile
(NT) NtOpenFile
(NT) NtQueryAttributesFile
(NT) NtQueryFullAttributesFile
(NT) NtSetInformationFile
(NT) NtOpenThread
(NT) NtOpenProcess
(NT) NtOpenProcessToken
(NT) NtSetInformationThread
(NT) NtOpenThreadToken
(NT) NtOpenProcessTokenEx
(NT) NtOpenThreadTokenEx
(NT) NtCreateKey
(NT) NtOpenKey
(EAT) CreateNamedPipeW
(EAT) CreateProcessW
(EAT) CreateProcessA
(EAT) CreateEventW
(EAT) OpenEventW
(NT) NtMapViewOfSection
(NT) NtUnmapViefOfSection
The hooks that I marked with NT are inline-patches set just before the SYSENTER is called. An example patch looks like this:
; A set hook
7C90DD7B > B8 7A000000 MOV EAX,7A ; Syscall number
7C90DD80 BA A5011500 MOV EDX,1501A5 ; Handler wrapper address
7C90DD85 FFE2 JMP EDX ; Jump to 1501A5
7C90DD87 C2 1000 RETN 10 ; This won't happen
; Handler wrapper
001501A5 83EC 08 SUB ESP,8
001501A8 52 PUSH EDX
001501A9 8B5424 0C MOV EDX,DWORD PTR SS:[ESP+C]
001501AD 895424 08 MOV DWORD PTR SS:[ESP+8],EDX
001501B1 C74424 0C 900115>MOV DWORD PTR SS:[ESP+C],150190 ; Original code address
001501B9 C74424 04 600D44>MOV DWORD PTR SS:[ESP+4],440D60 ; Handler function address
001501C1 5A POP EDX
001501C2 C3 RETN
; Archived original code
00150190 B8 7A000000 MOV EAX,7A
00150195 BA 0003FE7F MOV EDX,7FFE0300
0015019A FF12 CALL DWORD PTR DS:[EDX]
0015019C C2 1000 RETN 10
The wrapper and the original code is placed in a dynamically allocated memory (with a non constant address). The handler itself is written in C++, an in the source it's name has 'Target' prefix (i.e. TargetNtCreateFile). In the moment EIP is 'caught' by the hook, a messaged goes from the renderer to the browser with a question 'can a given operation take place' (like opening a file or sth). If the browser agrees, the operation take places, otherwise an Access Denied (or similar) error is returned.
The above mechanism targets to create another security layer, just to make an attackers life harder (or the attackers shellcodes life). But what can I say, the placement of the mechanism (user mode) is so bad, that it won't really make a difference for a potential attacker. An attacker can either use syscalls directly (the Google coders noted this possibility in the Chrome docs), or just take the hook off. Below there is a PoC code that takes the hook of a given function (it was made for XP SP2, and it's just a PoC):
void RemoveNtIntercept(LPCSTR FunctionName, BYTE Retn)
{
HINSTANCE NtDll = LoadLibraryA("ntdll.dll");
DWORD OldPriv;
DWORD FuncAddr = (DWORD)GetProcAddress(NtDll, FunctionName);
if(FuncAddr == 0) return;
FuncAddr += 6; // Skip 6 bytes (MOV EAX, SYSCALL_NUMBER + first byte of MOV EDX, SYSCALL_HANDLER)
VirtualProtect((LPVOID)FuncAddr, 10, PAGE_EXECUTE_READWRITE, &OldPriv);
*((DWORD*)(FuncAddr)) = 0x7FFE0300; // Restore original handler
*((DWORD*)(FuncAddr+4)) = 0xC212FF | (((DWORD)Retn << 24) & 0xFF000000) ; // call + retn
*((BYTE* )(FuncAddr+8)) = 0x00; // retn cd.
FreeLibrary(NtDll);
}
An example usage looks like this:
RemoveNtIntercept(output, "NtCreateFile", 0x2C);
Well, the code isn't too long, is it? It's also not elegant, but it deals with hooks rather good. To tell you the truth I like the hook idea (btw take the look at the hooking source code, it's nicely written, and it's on a BSD license ;>), but on the other hand, the mechanism is Vulnerable By Design.
I recommend playing with the Sandbox. The sandbox_poc is easy to compile, and it allows to play with the sandbox without the need of compiling the whooole big Chrome.
Before I'll end this post, I'll share with a few interesting things I've found while looking inside Chrome. The first thing are the names of some hooked functions in chromium\src\sandbox\src\interception_unittest.cc:
interceptions.AddToPatchedFunctions(L"kernel32.dll", "SomeFileEx",
INTERCEPTION_SMART_SIDESTEP, function);
interceptions.AddToPatchedFunctions(L"b.dll",
"TheIncredibleCallToSaveTheWorld", INTERCEPTION_EAT, function);
interceptions.AddToPatchedFunctions(L"a.dll", "BIsLame",
INTERCEPTION_EAT, function);
interceptions.AddToPatchedFunctions(L"a.dll", "ARules",
INTERCEPTION_EAT, function);
The other thing is the fact that Chrome uses WinAPI to deal with FTP, so when You logon via FTP, the following credentials are sent:
USER anonymous
PASS IEUser@
Huh, almost like IE ;>
Btw, I've saw that there was some FTP (file time) related crash fixed today. Was it another remote DoS?
OK. Thats it for today.
UPDATE: The article became a little incorect once I get to know a few new facts. Please check this post.
Comments:
"Emulation is not security: Emulation and virtual machine solutions do not by themselves provide security. The sandbox should not rely on code emulation, code translation, or patching to provide security."
As for the interceptions, I think they are for security, because they limit access to files, registry keys, and some functionality. Please note that they do not provide virtual file system / registry functionality, nor do they provide emulation or virtualizing code. They provide additional limitation in accessing files, registry, and other functionality, which is normally considered as security.
So imho, they are there for security, and I can't find any other reason for them to be there (if I am missing something, please point it out ;>).
As for the "patching" - As I have noted in the post, the authors of the Sandbox are well aware of the weakness of the interceptions, and it is only one of several methods used. So it's OK to say that the Sandbox does not rely on it, however it still uses it, because it still provides some security.
As for the quote. One thing is interesting - the Google guys say that "Emulation and virtual machine solutions do not by themselves provide security". On the other hand, the VM in Quake 3 according to some sources was developed to "limit the damage a rogue or malicious QVM program can wreak" (direct quote from http://icculus.org/~phaethon/q3mc/q3vm_specs.html), which is in fact a security reason. Of course a mistake is to compare a browser and a game. Or is it? ;>
"The interceptions (also known as hooks) are how Windows API calls are forwarded via the sandbox IPC to the broker. It is up to the broker to re-issue the API calls and return the results or simply fail the calls. The interception + IPC mechanism does not provide security; it is designed to provide compatibility when code inside the sandbox cannot be modified to cope with sandbox restrictions."
If I understand correctly, it is designed, as You say, to make code that is having problems with the restrictions run OK. This would mean that this mechanism would allow to reach additionally, normally unreachable due to the restrictions, files/keys from the sandbox. OK, so far it makes sens.
What I don't understand is why this compatibility mechanism additionally limits places that are normally accessible from the sandbox. Call it what You want, but I call 'limiting access' a security mechanism.
>> compatibility mechanism additionally limits places that are normally
Looks like in the TargetXXX intercepts the first thing done is to call the orginal NtXXXX function, so it does not seem to place additional limits.
See for example TargetNtCreateFile :
http://src.chromium.org/viewvc/chrome/trunk/src/sandbox/src/filesystem_interception.cc?view=annotate
Line 27, the first thing done is to call the original. If the error code is not access denied then it just returns, if the error code is access denied it does a bunch more things.
What do you think?
I researched a little more to find how come I got some files restricted while testing, and why weren't they restricted after the interceptions have been removed, and it looks like I mixed up some flags during tests. Ups ;D
Thanks for straighting things up in that case ;> I'll write some correcting news later today.
http://blogs.msdn.com/david_leblanc/archive/2007/07/31/practical-windows-sandboxing-part-3.aspx
But i havent read all the sandbox code of chrome
BTW nice blog.
Thank you for your post, especially for the link ;>
Hmm I'll have to check later if Chrome does some desktop magic like described in the link provided by you. If not, well, it looks like the desktop switching really does not provide the security it should.
You have a nice description of the chrome sandbox.
I was reading the comments and came across some people suggesting that the chrome sandbox does not provide security via the API hooking. That's not exactly true.
The chrome sandbox utilizes the job object and tokens to sandbox the process. The reason why the API is called immediately in the handler is to check whether the process is allowed to access the resource. If it is allowed by the kernel despite the job and the token boundries, then the call is allowed to be made. If the call fails due to an access denied, then the sandbox informs the host and the host decides how to handle the resource request.
I just wanted to clarify this so that others don't get thrown off by the comments like I did :-)
Add a comment: