libssh2-publickey-list-calc-poc: Critical Vulnerabilities in the libssh2 Public Key Subsystem
The libssh2-publickey-list-calc-poc demonstrates arbitrary code execution vulnerabilities in libssh2's public-key subsystem, specifically an integer overflow allocation-wrap on Win32 and a stale-callback use-after-free on Win64, both exploitable through the libssh2_publickey_list_fetch() function to spawn attacker-controlled processes like calc.exe.
The bikini/exploitarium repository hosts the libssh2-publickey-list-calc-poc, a collection of proof-of-concept exploits targeting the SSH public-key list parser in libssh2. These vulnerabilities allow remote attackers to achieve arbitrary code execution by manipulating how the library processes malformed public-key responses during the list fetching operation.
Win32 Allocation-Wrap Integer Overflow
On 32-bit Windows architectures, the vulnerability stems from an integer overflow in the buffer size calculation within libssh2_publickey_list_fetch(). The function computes the allocation size using num_attrs * sizeof(libssh2_publickey_attribute), where both operands are 32-bit values.
Heap Corruption via Integer Overflow
When num_attrs is sufficiently large, this multiplication wraps around to a small value—specifically 4 bytes—causing the allocator to create a tiny buffer. The parser then writes attacker-controlled attrs fields past this boundary, corrupting adjacent heap memory. The PoC file poc/publickey_win32_heap_groom_calc_repro.c (lines 95-115) demonstrates grooming the heap to position a victim structure immediately after the under-allocated buffer. By overwriting the victim's callback pointer and triggering its invocation, the exploit launches calc.exe.
Win64 Stale-Callback Use-After-Free
On 64-bit Windows, the vulnerability manifests as a use-after-free condition during list growth operations. Rather than relying on integer overflow, this attack exploits the lifetime management of public-key list entries.
Arbitrary Free and Callback Forgery
The exploit implemented in poc/publickey_win64_arbitrary_free_calc_repro.c (lines 27-31) transmits a crafted "version" response that frees a victim object. A subsequent malformed "publickey" response forces the list to grow, allocating the new entry into the same heap slot previously occupied by the freed victim. During cleanup, the library blindly frees the attacker-controlled attrs pointers stored in this entry, effectively restoring the victim object with forged callback fields. When the overwritten callback is invoked, it executes arbitrary code—demonstrated by spawning calc.exe.
Live Transport Exploitation
The repository provides a complete client-server implementation for demonstrating these vulnerabilities over actual SSH transports. This validates that the vulnerabilities are reachable through network protocols, not just theoretical parsing errors.
Malicious SSH Server Setup
The Python server poc/live_publickey_server.py orchestrates the attack by listening on port 2228 and transmitting groomed version packets followed by malformed publickey responses. The server accepts parameters to control the victim address and heap offset:
python3 poc/live_publickey_server.py --host 127.0.0.1 --port 2228 \
--victim 0x0000013370000000 --offset 27
Windows Client Execution
The companion client poc/live_publickey_client_win64.c connects to the malicious server and processes the crafted responses. When compiled against vulnerable libssh2 objects, the client triggers the stale-callback free chain:
wine ./live_publickey_client_win64.exe 127.0.0.1 2228 calc
If the underlying libssh2 build is vulnerable, this command launches calc.exe on the Windows host.
Mitigations and Checked Builds
The PoC repository includes "checked" builds of libssh2 that implement specific hardening measures to prevent exploitation. These mitigations are implemented in src/publickey.c and demonstrate how to close the attack surface.
Integer Overflow Validation
Checked builds validate that num_attrs values would not overflow the multiplication num_attrs * sizeof(libssh2_publickey_attribute). Rejecting malicious values prevents the allocation-wrap condition on Win32.
Zero-Initialization of List Entries
To prevent the use-after-free condition on Win64, checked builds zero-initialize newly-grown list entries immediately after allocation. This ensures that stale pointers cannot persist across free and reallocation cycles, neutralizing the callback forgery technique.
Building the Proof-of-Concept
You can compile the Win64 exploit against both vulnerable and patched libssh2 objects to observe the mitigation effectiveness.
Compiling Against Vulnerable Objects
x86_64-w64-mingw32-gcc -O2 -s -DLIBSSH2_WINCNG \
-I"$LIBSSH2_SRC/src" -I"$LIBSSH2_SRC/include" \
-o build/publickey_win64_arbitrary_free_calc_repro.exe \
poc/publickey_win64_arbitrary_free_calc_repro.c \
"$LIBSSH2_OBJDIR/publickey_win64.o" -lws2_32 -lbcrypt
Compiling Against Checked (Mitigated) Objects
Replacing the object file with the checked version prevents calc.exe from launching, confirming the fix:
x86_64-w64-mingw32-gcc -O2 -s -DLIBSSH2_WINCNG \
-I"$LIBSSH2_SRC/src" -I"$LIBSSH2_SRC/include" \
-o build/publickey_win64_arbitrary_free_calc_repro_checked.exe \
poc/publickey_win64_arbitrary_free_calc_repro.c \
"$LIBSSH2_OBJDIR/publickey_win64_checked.o" -lws2_32 -lbcrypt
Summary
- The Win32 exploit in
poc/publickey_win32_heap_groom_calc_repro.cleverages an integer overflow when calculatingnum_attrs * sizeof(libssh2_publickey_attribute)to achieve heap corruption and callback overwrite. - The Win64 exploit in
poc/publickey_win64_arbitrary_free_calc_repro.cexploits a use-after-free during list growth to forge callback pointers and execute arbitrary code. - Both vulnerabilities reside in the
libssh2_publickey_list_fetch()function withinsrc/publickey.c. - Mitigations include validating
num_attrsfor overflow conditions and zero-initializing new list entries to prevent stale pointer exploitation.
Frequently Asked Questions
What is the libssh2-publickey-list-calc-poc?
The libssh2-publickey-list-calc-poc is a proof-of-concept exploit suite housed in bikini/exploitarium that demonstrates critical vulnerabilities in libssh2's public-key list parsing functionality. It targets the libssh2_publickey_list_fetch() function to achieve arbitrary code execution on both 32-bit and 64-bit Windows systems.
How does the Win32 integer overflow lead to code execution?
On Win32, the calculation num_attrs * sizeof(libssh2_publickey_attribute) overflows to 4 bytes, causing a buffer under-allocation. The parser writes attacker-controlled data beyond this buffer, overwriting adjacent heap structures containing function pointers. By controlling the overwrite data, attackers redirect execution to launch processes like calc.exe.
What files are involved in the live transport demonstration?
The live transport proof uses poc/live_publickey_server.py (a Python-based malicious SSH server) and poc/live_publickey_client_win64.c (a Windows client binary). Together, they demonstrate that the vulnerabilities are exploitable over actual network connections rather than just in isolated parsing tests.
How do the checked builds prevent exploitation?
Checked builds implement two key mitigations: they reject num_attrs values that would trigger integer overflow during size calculation, and they zero-initialize newly allocated list entries to prevent use-after-free conditions. These changes are implemented in src/publickey.c and prevent both the allocation-wrap and stale-callback attack vectors.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →