AppSec Blog

Spot the Vuln - Sleep - SMTP Command Injection


Affected Software: PunBB

Fixed in Version: 1.3.2

Issue Type: SMTP Command Injection

Original Code: Found Here


Interesting bug here. In 2008, Stefan Esser reported a bug to the PunBB team which described a SMTP command injection vulnerability. If we look at the code below, we see that PunBB opens a socket connection to a SMTP host and passes various user/attacker controlled values to the SMTP server. Because of this setup, it is possible to craft a SMTP message that tricks the SMTP server into thinking the data provided for the message is completed, and executes any data that follows as SMTP commands. The attacker accomplished this by injecting Carriage Return and Line Feed characters following by a period character on a line by itself (as defined in RFC 821 ? SMTP). The PunBB developers addressed this vulnerability by sanitizing CRLFs and period characters.

The Web Application Hackers Handbook (by Dafydd Stuttard) describes various forms of SMTP injection in a pretty comprehensive manner. If the PunBB developers used the test cases described by Dafydd in his book would have likely identified this vulnerability before shipping. Here's a sample from the Web Application Hackers Handbook that talks about SMTP injection (see section 8.2)

Developers Solution

<?php ...snip... function smtp_mail($to, $subject, $message, $headers = ") { global $pun_config; $recipients = explode(',', $to); +// Sanitize the message +$message = str_replace("\r\n.", "\r\n..", $message); +$message = (substr($message, 0, 1) == '.' ? '.'.$message : $message); // Are we using port 25 or a custom port? if (strpos($pun_config['o_smtp_host'], ':') !== false) list($smtp_host, $smtp_port) = explode(':', $pun_config['o_smtp_host']); else { $smtp_host = $pun_config['o_smtp_host']; $smtp_port = 25; } if (!($socket = fsockopen($smtp_host, $smtp_port, $errno, $errstr, 15))) error('Could not connect to smtp host "'.$pun_config['o_smtp_host'].'" ('.$errno.') ('.$errstr.')', __FILE__, __LINE__); server_parse($socket, '220'); if ($pun_config['o_smtp_user'] != " && $pun_config['o_smtp_pass'] != ") { fwrite($socket, 'EHLO '.$smtp_host."\r\n"); server_parse($socket, '250'); fwrite($socket, 'AUTH LOGIN'."\r\n"); server_parse($socket, '334'); fwrite($socket, base64_encode($pun_config['o_smtp_user'])."\r\n"); server_parse($socket, '334'); fwrite($socket, base64_encode($pun_config['o_smtp_pass'])."\r\n"); server_parse($socket, '235'); } else { fwrite($socket, 'HELO '.$smtp_host."\r\n"); server_parse($socket, '250'); } fwrite($socket, 'MAIL FROM: <'.$pun_config['o_webmaster_email'].'>'."\r\n"); server_parse($socket, '250'); $to_header = 'To: '; @reset($recipients); while (list(, $email) = @each($recipients)) { fwrite($socket, 'RCPT TO: <'.$email.'>'."\r\n"); server_parse($socket, '250'); $to_header .= '<'.$email.'>, '; } fwrite($socket, 'DATA'."\r\n"); server_parse($socket, '354'); fwrite($socket, 'Subject: '.$subject."\r\n".$to_header."\r\n".$headers."\r\n\r\n".$message."\r\n"); fwrite($socket, '.'."\r\n"); server_parse($socket, '250'); fwrite($socket, 'QUIT'."\r\n"); fclose($socket); return true; }

Post a Comment


* Indicates a required field.