curl · Report #3481595
SMTP CRLF Injection & Protocol Desynchronization in libcurl
How it was found
Executive Summary
A critical security vulnerability has been identified in libcurl's SMTP protocol handler. The vulnerability allows for SMTP Command Smuggling and Protocol Desynchronization by injecting CRLF sequences into email address fields. This can be exploited to bypass security controls, forge emails, and smuggle arbitrary commands into the SMTP stream.
Vulnerability Details
1. Root Cause: Insufficient Input Validation
The function smtp_parse_address in lib/smtp.c is responsible for parsing email addresses for options like CURLOPT_MAIL_FROM, CURLOPT_MAIL_RCPT, and CURLOPT_MAIL_AUTH.
Unlike other parts of the SMTP handler (e.g., custom requests), this function does not use Curl_urldecode with REJECT_CTRL and does not perform any validation for control characters. It allows \r\n to pass through into the suffix component, which is later concatenated into raw protocol commands sent via Curl_pp_sendf.
2. Protocol Desynchronization (Response Smuggling) The vulnerability is amplified by a failure in the SMTP state machine to detect "extra" responses from the server.
libcurl uses a "pingpong" mechanism lib/pingpong.c where it sends one command and waits for one response. If an attacker injects multiple commands (e.g., MAIL FROM:<addr>\r\nQUIT), the server sends multiple responses.
Code-Level Evidence (lib/smtp.c):
- VULNERABLE: The handlers for
MAIL,RCPT, andDATAresponses (lines 1152, 1173, 1233) fail to check thepp.overflowflag. They read the first response and proceed to the next state, leaving the injected responses in the buffer to be consumed as the "result" of subsequent legitimate commands. - PROTECTED: The
STARTTLShandler (line 930) correctly implements this check:if(smtpc->pp.overflow) return CURLE_WEIRD_SERVER_REPLY;
The absence of this check in core mail-sending states allows an attacker to desynchronize the client-server state, causing curl to misinterpret the success or failure of later commands based on injected responses.
Proof of Concept (PoC)
{F5166562} {F5166563}
Reproduction Steps
Step 1: Start the Mock SMTP Server
Run the following command in a terminal to start the mock server. This server logs every command received and highlights when it processes smuggled instructions. {F5166566}
python3 smtp_repro.py
Step 2: Run the Exploit Command
In a different terminal, run the following curl command. We use a specially crafted --mail-from that includes a smuggled RCPT TO and DATA block.
curl -v smtp://localhost:2525 \
--mail-from $'<[email protected]>\r\nRCPT TO:<[email protected]>\r\nDATA\r\nSubject: Smuggled!\r\n\r\nThis email bypasses legitimate recipient lists!\r\n.\r\n' \
--mail-rcpt "[email protected]" \
--upload-file /dev/null
Step 3: Observe the Desynchronization
Server-Side Output (Terminal 1)
The Python server will show that it received a single block of data but interpreted it as multiple independent SMTP commands:
[!] Received Data Block (potentially containing multiple commands):
[C->S] MAIL FROM:<[email protected]>
[C->S] RCPT TO:<[email protected]>
[C->S] DATA
[C->S] Subject: Smuggled!
...
[!] EXPLOIT: Server is executing SMUGGLED command: RCPT TO:<[email protected]>
[!] EXPLOIT: Server is entering SMUGGLED DATA phase
Protocol Desynchronization Proof
Watch the final lines of the server log:
- curl sends its "legitimate"
RCPT TO:<[email protected]>. - curl reads the next available bytes from the socket.
- Due to the injection, the next response in the socket is the
354or250for the injected commands. - curl treats this smuggled response as the validation for
[email protected].
Actual curl -v Impact:
curl logs will report that it successfully sent the mail to [email protected], but in reality, the response it verified was for the smuggled recipient [email protected]. The legitimate email might even fail, yet curl could report success if the injected commands were crafted to align with the expected response codes.
Recommendations
- Implement
REJECT_CTRL: Update smtp_parse_addresscurl-master/lib/smtp.c#1825-1906to reject control characters. - Universal Overflow Enforcement: Add
pp.overflowvalidation to all SMTP state response handlers (MAIL, RCPT, DATA, VRFY, EXPN) to ensure client-server state synchronization.
Impact
- Email Fraud/Spoofing: Forge sender addresses and inject arbitrary headers.
- Unauthorized Distribution: Send emails to undisclosed recipients by smuggling
RCPT TOcommands. - Protocol Smuggling: Use
curl-master/lib/urlapi.c#1271-1277as an SSRF proxy to tunnel commands into internal SMTP relays.