Trickkiste: Wozu ist GetTokenInformation(..., TokenLinkedToken,...) gut?
Die Doku auf MSDN zeigt sich reichlich dürr, was die Beschreibung dieser TOKEN_INFORMATION_CLASS angeht. Es heisst lediglich: "The buffer receives a TOKEN_LINKED_TOKEN structure that contains a handle to another token that is linked to this token". Und in der Beschreibung zur Struktur TOKEN_LINKED_TOKEN heisst es zum einzigen Member der Struktur, LinkedToken: "A handle to the linked token."
Sehr elaboriert, diese Erklärungen. Hier beschreibe ich mal, welches Problem man mit dem Linked Token löst:
Wenn man eine Anwendung (oder in dem Fall eher einen Service) am Laufen hat, der einen AccessCheck mit einem restricted Token gegen einen Security Descriptor macht, der dann deswegen scheitert, weil der Token restricted ist, aber erfolgreich wäre, wenn der Token kein restricted Token wäre, dann sollte die Anwendung einen AccessCheck nicht gegen den restricted Token machen, sondern gegen dessen linked Token, wenn man diese Semantik nicht haben möchte mit dem Scheitern wegen eines restricted Tokens.
"Errhhh, whut?"
Vielleicht lässt sich das Ganze an einem Beispiel erklären: Wir haben einen Service, der unter Vista oder Server 2008 oder höher läuft. Wir nehmen weiterhin an, dass der Service einen Client impersonated und der Impersonation Token ist bei einem Clientrequest mal zufällig der restricted Token eines Consent Admins. Wenn nun in unserem Service ein Aufruf von AccessCheck mit diesem Token gegen einen Security Descriptor stattfindet, der für ein Access Right, das dem AccessCheck übergeben wurde, eine Access Allowed ACE in der DACL beinhaltet, dann scheitert AccessCheck mit ERROR_ACCESS_DENIED, obwohl das eine Access Allowed ACE war. Das ist so by design, so funktionieren restricted Tokens, das ist die erhöhte Sicherheit, die man seit Windows Vista mit User Account Control hat, wo man für solche Fälle einen Consent Admin eben zu einem Full Admin elevaten muss. Wäre nämlich der Client-Prozess, von dem der Token stammt, elevated, so würde der Service den full Token impersonaten und derselbe Aufruf von AccessCheck wäre dann erfolgreich (unter der Annahme, dass im Security Descriptor nicht noch irgendeine explizite Access Denied ACE in der DACL wäre). Wenn man will, dass der AccessCheck mit dem restricted Token in diesem Fall scheitert, weil etwa der Service dann eine privilegierte Aktion auslöst, dann kann man natürlich mit diesem Verhalten durchaus auch zufrieden sein. Dann benutzt der Service die User Account Control und daraus entstandene restricted Tokens genau so wie beispielsweise der Rest des Betriebssystems beim Zugriff auf das Dateisystem etc.
Aber nicht jeder AccessCheck den man in seinem Service macht, führt zu einer privilegierten Aktion. Und nicht jeder Service möchte unbedingt dieselbe Semantik mit restricted Tokens verwenden wie der Rest des Systems, vielleicht will unser Service ja die traditionelle Semantik verwenden aus der Zeit vor dem Erscheinen der restricted Tokens.
Aber wie kommt es überhaupt zu der Situation, dass ein impersonated Token ein restricted Token ist? Restricted Token gibt es schliesslich nur für interaktiv angemeldete User und der Impersonation Token eines Service entstammt üblicherweise einer Netzwerklogonsession eines Users, der an einer entfernten Maschine interaktiv angemeldet ist.
Die Antwort: Der Token kann genau dann restricted sein, wenn der Clientprozess auf derjenigen Maschine läuft, auf der auch der Service läuft, also wenn Client und Server lokal laufen und der zugehörige User zum Client ein Consent Admin ist. Das ist nur auf den ersten Blick ein etwas pathologisches Szenario, denn das gibt es tatsächlich alle Nase lang. Vorstellbar beispielsweise bei einem Service, der Custom Windows NT object security verwendet um Zugriff auf die Ressourcen, die er verwaltet, zu regulieren und dieser Service ist zufällig auf einem Terminal Server installiert, auf dem die User den zu diesem Service zugehörigen Client benutzen.
In dieser Situation wäre es nun erforderlich, dass das Clientprogramm elevated wird, und das kann es ja auch nicht sein, dass lokale Clients unseres Service immer elevated werden müssen, wenn der User des Clients ein Consent Admin ist. Und hier kommt nun der Linked Token ins Spiel: Anstatt dass vom Client eine Spezialbehandlung erwartet wird indem man gezwungen wird, ihn zu elevaten, muss der Server sich in dem Fall anders verhalten. Er darf nicht den Impersonation Token mit dem AccessCheck API verwenden, sondern dessen linked Token. Tatsächlich ist das einer der seltenen Fälle wo man älteren Servercode ein wenig abändern muss, damit er unter Vista und Server 2008 und später genauso funktioniert wie unter Server 2003 und früher.
Nun könnte man noch auf folgendes Angriffsszenario kommen: Wenn man ein Consent Admin ist, dann besorgt man sich seinen linked Token (der nicht mehr restricted ist) und ruft damit CreateProcessAsUser auf, um sich so ohne Elevation einen privilegierten Prozess zu verschaffen. Geht aber nicht, weil der linked Token kein primary Token ist (und sich auch nicht zu einem machen lässt). Das geht nur, wenn der eigene Prozess das Privileg SE_TCB_NAME ("act as part of the operating system") enabled hat. Wenn man allerdings SE_TCB_NAME enablen kann, ist man in der "Trusted Computing Base" und damit eh schon privilegiert und muss sich nicht noch privilegierter machen. Also kein Angriffsszenario.