• [ Регистрация ]Открытая и бесплатная
  • Tg admin@ALPHV_Admin (обязательно подтверждение в ЛС форума)

Статья The Guest Who Could: Exploiting LPE in VMWare Tools

stihl

Moderator
Регистрация
09.02.2012
Сообщения
1,311
Розыгрыши
0
Реакции
591
Deposit
0.228 BTC
stihl не предоставил(а) никакой дополнительной информации.
VMWare Tools provides a rich set of drivers and services that enhance manageability of virtual machines and enable guest-host communication. While the host-to-guest RPC mechanisms have long been attractive targets for vulnerability research due to their potential for VM escapes, the other components – especially guest-only services – are often overlooked. One such component is the VMware Guest Authentication Service, also known as the VMware Alias Manager and Ticket Service, or simply VGAuth. It ships with the default VMware Tools installation and is present on most guest VMs (both Windows and *nix) in ESXi-managed environments. This article details a set of vulnerabilities we discovered in the Windows implementation of this service, as found in VMware Tools 12.5.0 (build 24276846).

Background: VGAuth Overview​

The Guest Authentication Service is responsible for authenticating host-initiated operations that target the guest OS. When the host performs actions like writing files or modifying the registry, it must do so on behalf of a user in the guest. VGAuth acts as a middleware to provide the appropriate user context without requiring explicit credentials.

To achieve this, the service exposes several key capabilities:

  • Alias Store: Allows guest users to manage certificates used to map host identities to local users. Certificates are stored under C:\ProgramData\VMware\VMware VGAuth\aliasStore directory. Each user has a corresponding user-<username>.xml file, owned by the Administrators group and ACL’d with FullAccess for the alias store owner. There is also a mapping.xml file for global user-to-cert mappings.
  • Ticket Authentication: Lets clients store authentication information (represented by token handle on Windows) and receive a randomly generated ticket string. Other clients can later retrieve the original handle by presenting the ticket.
  • SAML Authentication: Verifies SAML requests against stored certificates and returns an access token for the mapped user. On Windows, this involves either generating an S4U2Self ticket (for domain users) or creating a new logon session via a custom LSA-mode security package (for local users).
Although the service is disabled by default on *nix systems, on Windows it runs by default even in non-ESXi-managed environments (like VMware Workstation). It runs under the SYSTEM account, with its binary located at C:\Program Files\VMware\VMware Tools\VMware VGAuth\VGAuthService.exe.

While much of the source code is available via Для просмотра ссылки Войди или Зарегистрируйся, the Windows-specific internals (e.g., IO, ACL and token handling) are propritary.

Communication is performed using a Для просмотра ссылки Войди или Зарегистрируйся over named pipes (on Windows) or UNIX sockets (on *nix). Two types of pipes are involved:

  • vgauth-service – a public pipe any user can connect to, used to initiate a session
  • vgauth-service-<username> – a private pipe created per user, with ACLs allowing read/write access only to that user
The public pipe is accessible to all users as its ACL grants open access, and its sole purpose is to initiate a session. Once a session is initiated, all subsequent communication occurs over the private pipe, tied to a specific user identity.

The client is considered a superuser if:

  • Its SID matches NT AUTHORITY\SYSTEM, or
  • It is a direct member of the BUILTIN\Administrators group (group membership is verified via NetLocalGroupGetMembers, so indirect membership (e.g., via nested groups) does not count)

Breaking down VGAuth RPC Interface​

The service supports 10 message types:

  1. SessionRequest – Initiates session, creates per-user private pipe
  2. Connect – Associates a client process via PID
  3. AddAlias – Adds a certificate to a user’s alias store
  4. RemoveAlias – Removes a certificate from the store
  5. QueryAliases – Lists user’s stored aliases
  6. QueryMappedAliases – Lists all available mapped aliases
  7. CreateTicket – Stores user-provided handle, returns the ticket string
  8. ValidateTicket – Retrieves handle by ticket
  9. RevokeTicket – Deletes a stored ticket
  10. ValidateSamlBToken – Validates a SAML request using the user’s alias store and returns primary token handle for the mapped user
Different requests are subject to specific access restrictions:

  • Only SessionRequest can be sent over the public pipe
  • AddAlias, RemoveAlias, QueryAliases and CreateTicket require that the username parameter matches the pipe owner, unless the client is a superuser
  • ValidateTicket is only callable by superusers
  • CreateTicket, ValidateTicket and ValidateSamlBToken require prior client PID authentication via Connect.
Some operations involve transferring handles between the service and the client process. To ensure the caller really owns the specified PID, VGAuth implements a custom authentication mechanism rather than using GetNamedPipeClientProcessId (likely for compatibility reasons).

The process works as follows:

  1. The client sends a Connect request containing its own PID
  2. The service creates an event object and duplicates its handle into the specified client process
  3. The client signals the event (using SetEvent)
  4. The service waits and verifies that the event was indeed signaled confirming the caller has access to the process handle
This challenge-response mechanism proves that the caller owns or can access the process with the given PID.

Finding a way in​

To send meaningful requests to VGAuth, a client must first establish a session by connecting to the public pipe and triggering the service to create a user-specific private pipe. Here’s a simplified version of how session creation works, based on the ServiceStartUserConnection function in service.c:

  1. The client connects to the public pipe: \\.\pipe\vgauth-service
  2. The client sends a SessionRequest containing the target username
  3. The service validates the username by looking up its SID
  4. The service creates a private pipe: \\.\pipe\vgauth-service-<username>, with a DACL that only grants access to the resolved SID
  5. The client connects to this private pipe, which effectively authenticates the session
However, there’s a critical implementation detail – the private pipe is created using the following call:

Код:
HANDLE hPrivatePipe = CreateNamedPipeW(
    lpName,
    PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
    PIPE_TYPE_BYTE,
    PIPE_UNLIMITED_INSTANCES,
    0x1000, // input buffer size
    0x1000, // output buffer size
    0x1388, // timeout
    lpSecurityAttributes
);

Notice that FILE_FLAG_FIRST_PIPE_INSTANCE is missing, and the pipe name is predictable and consistent across reboots and users. This opens the door for a classic named pipe pre-creation attack: if a low-privileged user creates the pipe before the service does, the DACL provided by the service is ignored and the attacker’s DACL applies instead.

This allows us to impersonate a superuser session by:

  1. Creating a named pipe \\.\pipe\vgauth-service-system with a permissive or null DACL
  2. Connecting to the public pipe and sending a SessionRequest with username system
  3. Once the service “creates” the private pipe (which we already control), we close our handle to release it
  4. Finally, we connect to vgauth-service-system pipe – now treated by the service as an authenticated SYSTEM session
At this point, we are communicating over a pipe tied to NT AUTHORITY\SYSTEM, granting full superuser access within the VGAuth protocol.

What Can We Do as SYSTEM?​

Once authenticated as a superuser, we can:

  • View, add, or remove certificate aliases for any user via QueryAliases, AddAlias, and RemoveAlias
  • Retrieve token handles created by other users using ValidateTicket
  • Use ValidateSamlBToken to obtain a primary token handle for any local or domain user
That said, some of these capabilities are more useful than others.

Ticket retrieval (ValidateTicket) is limited by PID authentication: we can only retrieve handles from processes we can already access. Without a way to spoof PIDs, this isn’t particularly exploitable.

SAML impersonation (ValidateSamlBToken) can yield high-privilege tokens (e.g., for Administrator), but without privileges like SeImpersonatePrivilege or SeAssignPrimaryTokenPrivilege, a low-privileged user can’t meaningfully use them.

That leaves one more promising angle: alias store manipulation. Superusers can manipulate any user’s alias store by simply specifying the username in the request (the service skips the usual username-to-pipe-owner match in this case).
Further, the RemoveAlias and QueryAliases requests do not require the user to actually exist. This is intentional: admins might want to remove stale certificates left behind by deleted accounts.

But there’s a subtle side effect – username values are not sanitized in these cases, which means we can pass in path traversal sequences like ../../../../../../evil. VGAuth then constructs the alias file path using this value, resulting in C:\ProgramData\VMware\VMware VGAuth\aliasStore\user-../../../../../../evil.xml → C:\evil.xml.
This lets us break out of the intended alias store directory and operate on arbitrary file paths as SYSTEM.

Both QueryAliases and RemoveAlias requests begin by loading the corresponding user’s alias store XML file. This is handled by the ServiceLoadFileContentsWin function in alias.c which does the following:

  1. Check the file’s attributes and size
  2. Verify that the file is owned by the Administrators group
  3. If the user exists, verify that their SID has access to the file (via ACL)
  4. Open the file and re-check attributes, size, and ACL using GetFileInformationByHandle
  5. Read the contents
Since the file must be owned by the Administrators group, this prevents us from reading or spoofing arbitrary files. This also implies that if we want the file to pass the check, we’ll likely need to work with an existing alias store file as a base – at least during the validation step.

Before opening the file, the service evaluates a macro to reject certain types of files:

Код:
#define FILE_ATTRS_NORMAL(a) (!((a) & (FILE_ATTRIBUTE_DEVICE | \
                                       FILE_ATTRIBUTE_DIRECTORY | \
FILE_ATTRIBUTE_REPARSE_POINT)))

The check for FILE_ATTRIBUTE_REPARSE_POINT may look like link following protection, especially considering Microsoft’s Для просмотра ссылки Войди или Зарегистрируйся for this attribute:



In fact, FILE_ATTRIBUTE_REPARSE_POINT is only reliably set on directories that are junctions, mount points, or contain reparse data, and on the files that are actual symbolic link objects (created via CreateSymbolicLink). This means that when we access a file through a symlink, the attribute is of course not set on the final resolved file. Likewise, when using the heavily-abused junction + DOS device symlink trick, it won’t be set as well.

Finally, once the file is opened, the service does not validate where the handle actually points – there’s no check like GetFinalPathNameByHandle to verify that the resolved path remains within the intended directory.

This opens the door to time-of-check/time-of-use (TOCTOU) attack: we can construct a path-traversal-style alias store name that resolves to a symlink which points to a valid alias store XML file, and switch the symlink’s target to something more dangerous before the next operation occurs.

b1ad94c6-pic1.jpg

Quick reminder: absuing symlinks on Windows (yet again)​

In order to create a file symlink as an unprivileged user, we have to:

  1. Set up a junction (mount point) from empty writable directory to writable directory in NT Object Manager Namespace:
    C:\LPE –(mount point)–> \RPC CONTROL
  2. Create DOS device symlink from OMNS to target file:
    \RPC CONTROL\evil.xml –(DOS device symlink)–> C:\ProgramData\VMware\VMware VGAuth\aliasStore\user-attacker.xml
The result is:
C:\LPE\evil.xml —(OMNS junction + DOS device symlink)—> C:\ProgramData\VMware\VMware VGAuth\aliasStore\user-attacker.xml

For TOCTOU exploitation & symlink target switching, we can use Для просмотра ссылки Войди или Зарегистрируйся which are placed on a file to run user-supplied code on the specified access attempt (r/w/rw), blocking it until the handler function exits.

Achieving arbitrary file delete​

Now that we can fully control the alias store file path via path traversal and symbolic links, we can explore how this affects the behavior of QueryAliases and RemoveAlias. QueryAliases does not seem exploitable: the function simply loads and parses the alias store XML using a GLib parser (g_markup_parse) and returns the structured result. However, RemoveAlias is much more interesting. Let’s take a look at how the deletion logic works in ServiceAliasRemoveAlias (from alias.c):

  1. Load and parse the alias store for the given user
  2. Remove the specified certificate
  3. If no aliases remain and the user does not exist, delete the file
  4. Otherwise, save the updated alias store
The deletion function on step 3 (ServiceFileUnlinkFile) simply invokes g_unlink. On Windows, this resolves to _wunlink, which is implemented using DeleteFileW. This is a perfect spot to apply our symbolic link switch: we use a real alias store file initially (so parsing and certificate removal succeed), and then switch the symlink target at the exact moment the deletion occurs.

Omitting the previously discussed authentication bypass, the exploitation steps are:

  1. Add a dummy alias to our own alias store: AddAlias(username="attacker", cert=PEM_CERT)
  2. Create a symbolic link: C:\LPE\evil.xml → C:\ProgramData\VMware\VMware VGAuth\aliasStore\user-attacker.xml
  3. Place a write-access oplock on the alias store file (user-attacker.xml) to detect the exact moment VGAuth begins modifying it
  4. Call RemoveAlias(username="../../../../../../LPE/evil", cert=PEM_CERT)
  5. When the oplock is triggered (just before deletion), switch the symlink target: C:\LPE\evil.xml → C:\Config.Msi::$INDEX_ALLOCATION
The RemoveAlias logic will now perform a DeleteFileW on the resolved path, effectively deleting the target file or directory, which is a well-known privilege escalation technique – for example, removing C:\Config.Msi allows exploitation via Windows Installer behavior, as described in Для просмотра ссылки Войди или Зарегистрируйся.

This gives us the first reliable local privilege escalation path from any user with access to the VGAuth service.

d5ed6576-pic2.png

Achieving arbitrary file write​

We now know how we can exploit RemoveAlias when a certificate is the last one in the alias store. But what happens when it’s not the last?

In that case, VGAuth updates the alias store file by rewriting it, which turns out to be even more interesting. When RemoveAlias deletes a certificate but others remain, the service invokes AliasSaveAliasesAndMapped, which rewrites the alias store as follows:

  1. It creates a temporary file inside the alias store directory, initializing its ACL to GENERIC_ALL for SYSTEM and Administrators.
  2. If the user still exists, the temporary file’s ACL is overwritten to give the user FullAccess. Otherwise, the ACL from the original alias store file is copied.
  3. The updated alias list is written to the temporary file.
  4. The temporary file is moved into place, replacing the original alias store file.
The replacement is performed within AliasSafeRenameFiles function (alias.c) using the following logic:

  1. Check that the source file exists and is a regular file
  2. Rename the existing alias file to a backup <alias_filename>.bak
  3. Rename the temporary file to replace the alias store file
  4. Delete the backup file
All file moves are done using g_rename(src, dst) → MoveFileExW(src, dst, MOVEFILE_REPLACE_EXISTING).

Each of these files – the temporary file, the final destination, and the backup – is written to paths we control via the symlink + path traversal trick. But there’s an added complication: the Object Manager Namespace (OMNS) is not a real filesystem. While we can redirect paths to OMNS using a junction (e.g., C:\LPE → \RPC CONTROL), we can’t create arbitrary new files under it during normal filesystem operations. This means that the service cannot create the temporary or backup file unless we pre-create symlinks for them.

In case of the backup file, this is straightforward – as we know its name, we can just create a symlink pointing anywhere. The temporary file, however, is more tricky. VGAuth generates temporary file names using a call to Для просмотра ссылки Войди или Зарегистрируйся with a pattern like user-<username>XXXXXX. This replaces the first X with a letter (starting from a), and the other ones with digits of the current thread ID – something like user-attackera12345. If the specified file already exists, the first character is incremented to b, and so on – which means our symlink must point to a non-existent file from the start. Since the service is asynchronous and single-threaded, the thread ID remains stable. Also, the alias store directory is world-readable, so we can use ReadDirectoryChangesW to monitor file creation and learn the exact temporary file name in real time – for example, while adding new aliases.

This gives us three attacker-controlled file targets involved in the write process:

  • The temporary file: created with a predictable name using wmktemp_s()
  • The backup file: <alias_store>.bak, which is created and later deleted
  • The final alias file: the original path, which is replaced by the temporary file
The cleanest exploitation path is to switch the alias store file symlink just before the rename to point somewhere privileged (e.g., C:\Windows\System32\pwn3d.dll) – the temporary file’s permissive ACL remains intact in this case.

To time this correctly, we can place a write oplock on the backup file, which is written just before the final rename. Once the lock triggers, we know we can safely redirect the symlink.

Putting it all together, those are the exploitation steps to achieve arbitrary file write (omitting the authentication bypass):

  1. Add two certificates to our alias store with two AddAlias requests (so the store won’t be deleted)
  2. Monitor C:\ProgramData\VMware\VMware VGAuth\aliasStore with ReadDirectoryChangesW to detect the generated temporary file name
  3. Create a symlink for the alias store file: C:\LPE\evil.xml —> C:\ProgramData\VMware\VMware VGAuth\aliasStore\user-attacker.xml
  4. Create a symlink for the backup file: C:\LPE\evil.xml.bak —> C:\whatever\writeme
  5. Create an empty file C:\whatever\writeme, place a write access oplock on it
  6. Create a symlink to any non-existent file for the temporary file (after leaking its name): C:\LPE\evila12345 —> C:\whatever\nonexistent
  7. Call RemoveAlias(username="../../../../../../LPE/evil", cert=PEM_CERT_2)
  8. When the oplock is triggered (i.e., just before the final rename), switch the symlink target: C:\LPE\evil.xml —> C:\Windows\System32\pwn3d.dll
As a result, the file resides in a privileged location, and is writable by the attacker due to the inherited ACL. You can then use any DLL hijack to trigger code execution as SYSTEM.

d8fc8e54-pic3.png

Disclosure and Patch Timeline​

We responsibly disclosed all vulnerabilities described in this article to Broadcom in early 2025. The issues were acknowledged promptly and addressed in subsequent updates to VMware Tools.

Timeline​

  • March 5, 2025 – Initial vulnerability report submitted to Broadcom
  • March 25, 2025Для просмотра ссылки Войди или Зарегистрируйся (authentication bypass) patched in VMware Tools 12.5.1
  • May 12, 2025Для просмотра ссылки Войди или Зарегистрируйся (path traversal + insecure link resolution) patched in VMware Tools 12.5.2

Patch Details​

CVE-2025-22230​

  • Private pipe names are now randomized (vgauth-service-<username>-<uuid>)
  • Pipe creation now uses the FILE_FLAG_FIRST_PIPE_INSTANCE flag to prevent hijacking
  • Advisory: Для просмотра ссылки Войди или Зарегистрируйся

CVE-2025-22247​

  • Path traversal vectors eliminated by rejecting usernames containing unsafe characters (<>/\)
  • GetFinalPathNameByHandleW added to validate resolved paths at runtime
  • Symlink-based exploitation mitigated via a new allowSymlinks configuration flag (default: false)
  • Advisory: Для просмотра ссылки Войди или Зарегистрируйся
  • Patch diff: Для просмотра ссылки Войди или Зарегистрируйся

Final Thoughts​

While VGAuth doesn’t directly perform privileged operations, its role as an authentication broker made it a powerful target. This was a fun and interesting research path, where a series of primitives came together into a reliable LPE chain.

We appreciate Broadcom’s timely response and collaboration during the disclosure process. Users running VMware Tools in guest Windows VMs are strongly encouraged to upgrade to the latest version to mitigate these issues.


Для просмотра ссылки Войди или Зарегистрируйся
 
Activity
So far there's no one here
Сверху Снизу