I am trying to impersonate a client with SYSTEM
privileges.
I noticed that this client it trying to connect to the named pipe: \\.\pipe\abc
.
I setup a named pipe server \\.\pipe\abc
and wait for it to connect.
Once it was connected, it failed:
[ ] Creating pipe server
[ ] Waiting for client to connect
[ ] Client connected
[ ] Client impersonated!
[ ] Failed to get thread token! 1347
The error 1347 according to Microsoft:
ERROR_CANT_OPEN_ANONYMOUS
1347 (0x543)
Cannot open an anonymous level security token.
Why did it happen? It succeeded to impersonate but then failed to open the thread.
This is my code until the failure on OpenThreadToken
.
SECURITY_ATTRIBUTES SecurityAttrs = {
sizeof(SECURITY_ATTRIBUTES),
NULL, // assigned access token of calling process
FALSE
};
DWORD openMode = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_OWNER;
DWORD pipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
std::cout << "[ ] Creating pipe server\n";
for (;;) {
// create the named pipe
HANDLE pipe = NULL;
DWORD msgSize = 1024;
pipe = CreateNamedPipeA(
"\\\\.\\pipe\\abc",
openMode,
pipeMode,
1, // max instances
msgSize, // out buffer size
msgSize, // in buffer size
0, // timeout. 0 ~= 50ms
&SecurityAttrs);
if (pipe == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
std::cout << "[!] Pipe creation failed! " << err << std::endl;
return err;
}
// wait for client to connect
std::cout << "[ ] Waiting for client to connect\n";
bool connected = ConnectNamedPipe(pipe, NULL) ? true : (
GetLastError() == ERROR_PIPE_CONNECTED);
if (!connected)
continue;
std::cout << "[ ] Client connected\n";
// read from pipe
char buf[msgSize];
DWORD bytesread = 0;
bool status = ReadFile(
pipe,
&buf,
msgSize,
&bytesread,
NULL);
// impersonate the connector
if (!ImpersonateNamedPipeClient(pipe)) {
DWORD err = GetLastError();
std::cout << "[!] Impersonation failed! " << err << std::endl;
return -1;
}
std::cout << "[ ] Client impersonated!\n";
HANDLE hToken = {};
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, false, &hToken)) {
DWORD err = GetLastError();
std::cout << "[!] Failed to get thread token! " << err << std::endl;
return err;
}
CodePudding user response:
According to OpenThreadToken,
If the token has the anonymous impersonation level, the token will not be opened and OpenThreadToken sets ERROR_CANT_OPEN_ANONYMOUS as the error.
And According to Impersonation Levels,
The client of a named pipe, RPC, or DDE connection can control the impersonation level. For example, a named pipe client can call the CreateFile function to open a handle to a named pipe and specify the server's impersonation level.
When the named pipe, RPC, or DDE connection is remote, the flags passed to CreateFile to set the impersonation level are ignored. In this case, the impersonation level of the client is determined by the impersonation levels enabled by the server, which is set by a flag on the server's account in the directory service. For example, if the server is enabled for delegation, the client's impersonation level will also be set to delegation even if the flags passed to CreateFile specify the identification impersonation level.
Your named pipe client do need to call the CreateFile
function to open a handle to a named pipe and specify the server's impersonation level.
CodePudding user response:
based on comments, in client code -
FILE_FLAG_OPEN_NO_RECALL | FILE_FLAG_OVERLAPPED;
used if place dwFlagsAndAttributes in call of CreateFile
however need notice that FILE_FLAG_OPEN_NO_RECALL == (SECURITY_SQOS_PRESENT|SECURITY_ANONYMOUS)
and FILE_FLAG_OPEN_NO_RECALL == SECURITY_SQOS_PRESENT
both this flags have the same binary value 0x00100000
(and SECURITY_ANONYMOUS == 0
)
think this is problem of design of CreateFile
api. it have less parameters, compare NtCreateFile
and it try combine different parameters in single. for instance in single dwFlagsAndAttributes
combine FileAttributes
CreateOptions
ObjectAttributes->SecurityQualityOfService
. so parameter is "overloaded"