So I have been learning c++, now granted I'm not very good at it but it's rather fun and since we have direct access to all of Microsofts API's it's perfect for vuln research. One of things that interested me was how easy it was to play around with tokens. I also had a hard time understanding the difference between integrity levels and what you could do with each. So I decided to steal some code from MS and put it all together. The end result is a pretty nifty exe you can use for testing and learning.
So how does all this work, well ill explain as much as I can.
The first thing we need to do is call OpenProcessToken, this is going to get the token that the current process is using. There is also OpenThreadToken but we don't need that for this example.
HANDLE Token; // This will be where our token is stored.
OpenProcessToken(GetCurrentProcess(),
TOKEN_DUPLICATE |
TOKEN_ADJUST_DEFAULT |
TOKEN_QUERY |
TOKEN_ASSIGN_PRIMARY,
&Token); //Pass it the handle so it returns.
Now we want to duplicate it, we are going to be changing the Sid to LowIntegrity and we don't want any issues.
HANDLE NewToken; // Our new token will be stored here.
DuplicateTokenEx(Token,
0,
NULL,
SecurityImpersonation,
TokenPrimary,
&NewToken); // Pass it the handle
Now we need to change the Sid to LowIntegrity, this is a predefined string that Microsoft has, there are tons of them and most are located here https://msdn.microsoft.com/en-us/library/cc980032.aspx but the main ones are.
S-1-16-4096 Low Mandatory Label
S-1-16-8192 Medium Mandatory Label
S-1-16-12288 High Mandatory Label
S-1-16-16384 System Mandatory Label
So lets go ahead and actually change the the level of our copied token! This part looks a little complicated but its fairly easy. We are just building all the parts so we can actually change it.
PSID pIntegritySid = NULL;
WCHAR wszIntegritySid[20] = L"S-1-16-4096"; // Low integrity SID
ConvertStringSidToSid(wszIntegritySid, &pIntegritySid); //You will need #include "sddl.h"
// This is the struct for setting our Mandatory label.
TOKEN_MANDATORY_LABEL TIL = { 0 };
TIL.Label.Attributes = SE_GROUP_INTEGRITY;
TIL.Label.Sid = pIntegritySid;
// We need the size when we pass it to SetTokenInformation
DWORD infolength = sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(pIntegritySid);
// And here we finally change the Sid to what we want on the new token.
SetTokenInformation(NewToken, TokenIntegrityLevel, &TIL, infolength);
The last part of this is just setting up the rest of the stuff we need to call CreateProcessAsUser.
PROCESS_INFORMATION ProcInfo = { 0 };
STARTUPINFO StartupInfo = { 0 };
WCHAR ProcessName[MAX_PATH] = L"C:\\Windows\\System32\\cmd.exe";
This is the final call and then we are done, all we are really doing is passing it our modified token and the process that we want to actually open!
CreateProcessAsUser(NewToken,
NULL,
ProcessName,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&StartupInfo,
&ProcInfo);
A few things to keep in mind, this all needs to be wrapped in a function deceleration and its not threaded.
In the code I'm using I added a extra little call to check what level the token was at before we duplicate and modify it. Then I check again once we call CreateProcessAsUser as you can see in the output. I uploaded it to github and you can check it out here https://github.com/trump0dump/helpful/blob/master/low_integrity.cpp, the end result looks something like this!
And you can check to see that its actually running as Low Integrity with ProcessExplorer
Enjoy and I should also mention that you can change the Sid and call it from a High process. Its not very useful but does help with understanding tokens and Integrity Levels :)
No comments:
Post a Comment