Skip to content
USB redirection heap disclosure

USB redirection heap disclosure

github.com • September 29, 2026

This is a report on behalf of Julien Lair, Security Researcher at Quarkslab (quarkslab.com)

An information leak vulnerability that facilitates turning a heap overflow into a RCE explit that bypasses ASLR. The client sends uninitialized heap memory back to the RDP server. Those bytes contain live pointers, so a malicious server can defeat ASLR on the client. This is the piece that turns Vuln1 (the heap overflow) into a reliable RCE. The attacker is the server, no credentials needed.

FreeRDP with the urbdrc (USB redirection) channel compiled and active. The uninitialized reserve is present from 2.0.0 to current master (the line number shifts a little between versions: around :86 from 2.0.0 to 3.5.0, :83 in 3.10.0, :134 in 3.24.2 and 3.28.0).

Remmina 1.4.x through the system libfreerdp (its RDP plugin exposes USB redirection with the usb profile option, which turns on urbdrc).

FreeRDP 993499447 (on Ubuntu 26.04 with glibc 2.43-2ubuntu2), ASLR + NX on, with a virtual USB device redirected: leak confirmed, the server recovered the client heap base and, chained with Vuln1, the libc system address (full RCE, see ../poc/qemu-rce/ ).

Earlier dynamic runs (libfreerdp 3.24.2): xfreerdp3 342 leaked-pointer hits, Remmina 1.4.40 311; both recovered connect_base and the libc system address.

Technical description

When the client finishes a USB request (a URB), urb_write_completion in channels/urbdrc/client/data_transfer.c builds the response and reserves OutputBufferSize bytes with Stream_Seek, without writing or zeroing them:

Stream_Seek only moves the stream position, it does not fill the reserved space. The same pattern is in a second completion path at data_transfer.c:892/:893.

OutputBufferSize is how much data the transfer was supposed to return. When a control transfer IN fails (the device stalls, LIBUSB_ERROR_PIPE) or returns fewer bytes than declared, that reserved space is never filled with device data. The completion PDU then goes to the server with OutputBufferSize bytes of stale heap taken from the stream's backing allocation.

Those stale bytes hold live heap and library pointers from the client process. A malicious server that gets the client to redirect a device and then issues IN transfers that fail reads back tens of kilobytes of client memory, and from it rebuilds connect_base (the client heap and connection arena) and the libc base, so the address of system. That defeats ASLR, which is exactly what Vuln1 needs.

The victim must have USB redirection active (xfreerdp /usb:..., or the usb option in a Remmina profile) with a device redirected. On Linux the client needs access to the USB node, which usually means running it as root or with libusb access.

On a failed or short IN transfer, set OutputBufferSize to 0 (or return a no-data completion), and zero the reserved region before sending (use Stream_Zero instead of Stream_Seek), so no uninitialized memory ever leaves the client.

Extracted Entities

Attack Types (1)

Domains (1)

Platforms (2)