HexBrain

curl · Report #3584491

LM Challenge-Response Hash Always Sent in SMB Authentication

Informativestatus
mediumseverity
18upvotes
9 Mar 2026disclosed

How it was found

LM Challenge-Response Hash Always Sent in SMB Authentication

Summary

The curl SMB client unconditionally computes and sends both the legacy LAN Manager (LM) and NT challenge-response hashes during SMB session setup. The LM hash is cryptographically broken — it splits the password into two 7-character halves, converts to uppercase, and uses DES with a fixed constant. Combined with the fact that the 8-byte authentication challenge is entirely server-controlled (no client-side nonce mixing), any SMB server that curl connects to can capture the LM response and recover the user's password offline within seconds to minutes using rainbow tables or brute-force tools (hashcat mode 5500). This is a significant credential exposure risk for any user who connects curl to an untrusted SMB server, including in SSRF scenarios.

Vulnerability Details

Affected Component

lib/smb.c — curl's SMBv1 (CIFS) client implementation, specifically the smb_send_setup() function and the smb_connection_state() function's NEGOTIATE response handling.

Affected Versions

Confirmed in curl master at commit 1b35c9e1e3 (2026-03-01). The SMB implementation has used this authentication scheme since its introduction; no NTLMv2 or extended security has ever been added to the SMB code path.

Pre-requisites

  • The victim must initiate a curl SMB connection (smb:// or smbs://) to an attacker-controlled server, or to a server the attacker can man-in-the-middle.
  • The victim must supply credentials (via -u user:password, .netrc, or CURLOPT_USERPWD).
  • SMB support must be compiled in (it is by default when NTLM core is available).

Root Cause Analysis

  1. The server sends an SMB_COM_NEGOTIATE response containing an 8-byte challenge in nrsp->bytes[]. This challenge is entirely server-controlled — the server can choose any 8 bytes, including values optimized for rainbow table lookups.

  2. At smb.c:943, the challenge is copied into smbc->challenge without any validation:

    memcpy(smbc->challenge, nrsp->bytes, sizeof(smbc->challenge));  // 8 bytes
    
  3. At smb.c:681-684, the LM hash is computed and the LM response is derived using the server-controlled challenge:

    Curl_ntlm_core_mk_lm_hash(conn->passwd, lm_hash);      // LM hash of password
    Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm);   // DES-encrypt challenge
    Curl_ntlm_core_mk_nt_hash(conn->passwd, nt_hash);       // NT hash of password
    Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt);   // DES-encrypt challenge
    
  4. Both the 24-byte LM response and 24-byte NT response are sent to the server at smb.c:694-698:

    msg.lengths[0] = smb_swap16(sizeof(lm));   // LM response length = 24
    msg.lengths[1] = smb_swap16(sizeof(nt));    // NT response length = 24
    memcpy(p, lm, sizeof(lm));
    p += sizeof(lm);
    memcpy(p, nt, sizeof(nt));
    

This produces two independent 8-byte DES blocks. Each half has at most 2^37 possible values (7 uppercase ASCII characters), making brute-force trivial. The two halves can be cracked independently, further reducing the effective complexity.

Reproduction

1. Obtain the vulnerable version:

git clone https://github.com/curl/curl.git
cd curl
git checkout 1b35c9e1e3

2. Build curl with SMB support:

cmake -B build-poc \
  -DCMAKE_BUILD_TYPE=Debug \
  -DCMAKE_C_FLAGS="-O0 -g" \
  -DCURL_USE_OPENSSL=ON \
  -DCURL_DISABLE_SMB=OFF
cmake --build build-poc -j$(nproc) --target curl

Verify SMB is enabled:

./build-poc/src/curl --version | grep -o smb

3. Install PoC dependency:

pip install pycryptodome

4. Start the malicious SMB server (terminal 1):

python3 poc_clean.py

Output:

[*] Listening on 127.0.0.1:4455 (challenge: 1122334455667788)

5. Connect curl to the malicious server (terminal 2):

./build-poc/src/curl -u 'testuser:Password1' smb://127.0.0.1:4455/share/file.txt

curl will connect and send the SESSION_SETUP_ANDX with both LM and NT responses.

Observed Result

The PoC server captures and cracks the password:

[+] Connection from ('127.0.0.1', 60378)

  User:         testuser
  LM response:  76365e2d142b5612cd10e1b93d342334e8fd283ecd7b9170
  NT response:  8614b8a84404b1c0333c8875a22bc10690bbf6a7edcf549d

  [!] PASSWORD CRACKED: 'Password1'

Key observations:

  1. The 24-byte LM response is non-zero — confirming that curl computes and sends the weak LM hash to the server.
  2. The password Password1 was recovered from the LM response using only the server-chosen challenge and a trivial 5-word dictionary. In practice, hashcat mode 5500 with rainbow tables or GPU brute-force can crack any LM hash in seconds.
  3. The server fully controlled the 8-byte challenge (1122334455667788). A real attacker could choose a challenge value optimized for pre-computed rainbow tables (e.g., 1122334455667788 is a standard rainbow table challenge).

Impact

Summary:

An attacker operating a malicious SMB server (or performing a man-in-the-middle attack on an unencrypted SMB connection) can recover the plaintext password of any user who connects with curl. The attack is completely passive from the attacker's perspective — they simply accept the connection and read the SESSION_SETUP_ANDX message.

The LM hash's maximum effective keyspace is 2 × 2^37 (two independent 7-character uppercase halves), making brute-force trivially fast on modern hardware. Rainbow tables for LM are widely available and provide instant lookup.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original