A Bit About the Local Security Authority
It's been a while since our last thread and I need to kill time while a ginormous time travel trace file finishes copying, so let's talk a bit about LSA, the Windows Local Security Authority.
Twitter warning: Like all good things this is mostly correct, with a few details fuzzier than others for reasons: a) details are hard on twitter; b) details are fudged for greater clarity; c) maybe I'm just dumb.
The LSA is a system component that oversees all the security decisions on your machine. Whenever Windows needs to authenticate a user or verify permissions or what not, the system asks the LSA. It primarily lives in a user mode service: LSASS.
The LSA is a bit of an interesting beast in that it's not one singular thing. It's made up of a handful of components, mostly living in user mode, with one teeny-tiny* component living in the kernel.
*not so tiny
Before we dig too much into the LSA itself, we need to take a brief look at how Windows security works. There are two fundamental security boundaries in Windows we need to look at: the kernel/usermode boundary, and the user/user boundary.
The user/user boundary is fairly straightforward. Two separate standard users can't interfere with one another on the same machine. This is enforced through authorization rules bound to identifying information about each user: namely their SIDs.
A SID is just a unique identifier. No two things will have the same SID. So user A and user B have separate SIDs, and everything belonging to each user is stamped somehow with that SID. The authorization rules in Windows say if you don't have this SID then you can't touch.
This is fundamentally how all security decisions in Windows are made. Does the user have a SID that matches the list of SIDs that are required to do the thing? Yes, then carry on. No, screw off. Of course, there are two extensions to this, the first being groups.
The groups you're a member of are an extension of your identity, so as a result you have your SID plus all the SIDs of the groups you're a member of. The second is Windows privileges.
A Windows privilege is a right to interact with Windows itself. This includes benign things like turning the computer off or critical things like running system services. Privileges are bound to SIDs (ish). Each privilege has a list of SIDs that are allowed to hold the privilege.
So when I want to turn the computer off Windows checks for the SeShutdownPrivilege, which is granted to the user by virtue of having specific SIDs.
Eh, sort of. These privileges are actually stamped on a user token.
These user tokens are managed by the LSA and are created when a user logs on. Every single user has a token, and every operation in Windows is bound to a token because all processes have a token mapped to them: How Windows Single Sign-On Works (syfuhs.net)
These user tokens, often called NT Tokens, are the way Windows represents user identities when logged in. The token is a kernel data structure. What this means is only things in the kernel can touch this data. Which brings us to the kernel mode/usermode boundary.
The kernel/user boundary is a hardware-enforced boundary. Your CPU dictates whether your code runs in kernel or in user mode. To call things in kernel mode you have to ask the CPU nicely and it may or may not acquiesce because it has a known list of functions that can be called.
This list is highly specific and dictates whether your API can ask the CPU to execute a function in the context of the kernel. This is how for instance your program can read files off disk. The program asks the CPU if it can execute a kernel call to read IO.
Anyway, in practice what this means is all the stuff in the kernel like your NT Token can't be touched by stuff in user mode without going through these special functions, and it turns out there isn't a specific function for managing tokens. How's this all work?
Well, let's start at the beginning. Remember how I said all processes have tokens, and all tokens are managed by LSA, and LSA is a user mode process? Well that sounds a bit...impossible? It turns out the system cheats a bit.
When the computer turns on the first (ish) thing that executes is the kernel executive. It is "the" kernel process. It's the thing that holds all the system goodies. It's the "in the beginning" in the biblical sense. And it's a no good cheater.
The executive kicks off user mode, which starts with a single process: wininit.exe. It needs to be running as an identity so the executive cheats and makes the very first SYSTEM token. Wininit knows this and that there's no security system yet, so it starts lsass.exe.
Incidentally the kernel also knows there's no security system in place, so it halts all further security decisions until LSA starts up. If LSA fails to start the system fails to start.
So LSASS. That was a long fricken preamble. LSASS is kind of dumb. It only has one job, which is to act as a service host. That service that gets hosted is The LSA. The LSA is *also* a service host, whose job is to host additional services. Oy.
So, that LSA service. It's called the LSA server and is backed by lsasrv.dll. If you go look at the files you'll see this is an absolutely massive DLL compared to lsass.exe. That's where all the meat is.
The server has two jobs, one of which is to host an RPC server (shocked face), and to manage additional child services. These child services are critical, but less interesting. They are things like netlogon, the key isolation service, or LDAP or KDC on your domain controller.
But the RPC server on the other hand is super interesting. Whenever your application makes a security call, like LogonUser, or something like SSPI's InitializeSecurityContext, your process must call this RPC server.
Your application doesn't get to touch LSA directly. It goes through some stub calls like LogonUser, which are RPC clients, which communicate to LSA, and then LSA does all the magic.
That magic is also kinda interesting, because LSA (server) doesn't strictly know what the magic is. LSA (server) knows how to communicate with clients, but it has to hand the actual work off to plugins called authentication providers. Extensibility is fun.
So to recap you have LSASS, which hosts services, specifically the LSA Server service. The LSA Server service hosts the RPC server, and other complementary services, and the RPC server (kinda sorta) hosts authentication providers. Wheeeee.
These APs are where the magic happens. There are a handful of builtin APs like Kerberos and NTLM and a very special one called Negotiate, which knows how to...negotiate...between Kerb and NTLM and whatever else is registered.
I won't go into the logon process, but here it is: What Happens When you Type Your Password into Windows? (syfuhs.net)
Somewhere along the way the logon process needs to create an NT token for the user, so everything running as that user has an identity in the system.
APs now start to cross the streams with LSA. One other thing LSA knows how to do is communicate with the kernel. Aha! Remember the kernel waiting on the security system to start up? This is why. LSA needs to be able to call into the kernel to ask the kernel to create tokens.
So the AP asks LSA to create a token. LSA calls into the kernel via RPC (ALPC specifically) and the kernel says "okie-doke here you go".
But this is RPC. Can't anyone call RPC? Actually yes. But it turns out the kernel-side RPC server checks the caller's token to make sure it's SYSTEM. Funny how that works. /fin