LM Challenge-Response Hash Always Sent in SMB Authentication

Disclosed: 2026-03-09 12:15:54 By brewm4ster To curl
Medium
Vulnerability Details
# 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: ```c 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: ```c 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`: ```c 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:** ```bash git clone https://github.com/curl/curl.git cd curl git checkout 1b35c9e1e3 ``` **2. Build curl with SMB support:** ```bash 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: ```bash ./build-poc/src/curl --version | grep -o smb ``` **3. Install PoC dependency:** ```bash pip install pycryptodome ``` **4. Start the malicious SMB server (terminal 1):** ```bash python3 poc_clean.py ``` Output: ``` [*] Listening on 127.0.0.1:4455 (challenge: 1122334455667788) ``` **5. Connect curl to the malicious server (terminal 2):** ```bash ./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.
Actions
View on HackerOne
Report Stats
  • Report ID: 3584491
  • State: Closed
  • Substate: informative
  • Upvotes: 3
Share this report