Search code examples
c++winapiwindownamed-pipes

Can't open thread token of NamedPipe client: "Cannot open an anonymous level security token"


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;
      }

Solution

  • 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"