8000 [3.8] bpo-43124: Fix smtplib multiple CRLF injection (GH-25987) (GH-2… · python/cpython@b93aea4 · GitHub
[go: up one dir, main page]

Skip to content

Commit b93aea4

Browse files
[3.8] bpo-43124: Fix smtplib multiple CRLF injection (GH-25987) (GH-28036)
Co-authored-by: Łukasz Langa <lukasz@langa.pl> (cherry picked from commit 0897253) Co-authored-by: Miguel Brito <5544985+miguendes@users.noreply.github.com>
1 parent c9c2a0b commit b93aea4

File tree

3 files changed

+65
-3
lines changed

3 files changed

+65
-3
lines changed

Lib/smtplib.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,15 @@ def send(self, s):
365365
def putcmd(self, cmd, args=""):
366366
"""Send a command to the server."""
367367
if args == "":
368-
str = '%s%s' % (cmd, CRLF)
368+
s = cmd
369369
else:
370-
str = '%s %s%s' % (cmd, args, CRLF)
371-
self.send(str)
370+
s = f'{cmd} {args}'
371+
if '\r' in s or '\n' in s:
372+
s = s.replace('\n', '\\n').replace('\r', '\\r')
373+
raise ValueError(
374+
f'command and arguments contain prohibited newline characters: {s}'
375+
)
376+
self.send(f'{s}{CRLF}')
372377

373378
def getreply(self):
374379
"""Get a reply from the server.

Lib/test/test_smtplib.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,16 @@ def testEXPNNotImplemented(self):
294294
self.assertEqual(smtp.getreply(), expected)
295295
smtp.quit()
296296

297+
def test_issue43124_putcmd_escapes_newline(self):
298+
# see: https://bugs.python.org/issue43124
299+
smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost',
300+
timeout=10) # support.LOOPBACK_TIMEOUT in newer Pythons
301+
self.addCleanup(smtp.close)
302+
with self.assertRaises(ValueError) as exc:
303+
smtp.putcmd('helo\nX-INJECTED')
304+
self.assertIn("prohibited newline characters", str(exc.exception))
305+
smtp.quit()
306+
297307
def testVRFY(self):
298308
smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3)
299309
self.addCleanup(smtp.close)
@@ -369,6 +379,51 @@ def testSendNeedingDotQuote(self):
369379
mexpect = '%s%s\n%s' % (MSG_BEGIN, m, MSG_END)
370380
self.assertEqual(self.output.getvalue(), mexpect)
371381

382+
def test_issue43124_escape_localhostname(self):
383+
# see: https://bugs.python.org/issue43124
384+
# connect and send mail
385+
m = 'wazzuuup\nlinetwo'
386+
smtp = smtplib.SMTP(HOST, self.port, local_hostname='hi\nX-INJECTED',
387+
timeout=10) # support.LOOPBACK_TIMEOUT in newer Pythons
388+
self.addCleanup(smtp.close)
389+
with self.assertRaises(ValueError) as exc:
390+
smtp.sendmail("hi@me.com", "you@me.com", m)
391+
self.assertIn(
392+
"prohibited newline characters: ehlo hi\\nX-INJECTED",
393+
str(exc.exception),
394+
)
395+
# XXX (see comment in testSend)
396+
time.sleep(0.01)
397+
smtp.quit()
398+
399+
debugout = smtpd.DEBUGSTREAM.getvalue()
400+
self.assertNotIn("X-INJECTED", debugout)
401+
402+
def test_issue43124_escape_options(self):
403+
# see: https://bugs.python.org/issue43124
404+
# connect and send mail
405+
m = 'wazzuuup\nlinetwo'
406+
smtp = smtplib.SMTP(
407+
HOST, self.port, local_hostname='localhost',
408+
timeout=10) # support.LOOPBACK_TIMEOUT in newer Pythons
409+
410+
self.addCleanup(smtp.close)
411+
smtp.sendmail("hi@me.com", "you@me.com", m)
412+
with self.assertRaises(ValueError) as exc:
413+
smtp.mail("hi@me.com", ["X-OPTION\nX-INJECTED-1", "X-OPTION2\nX-INJECTED-2"])
414+
msg = str(exc.exception)
415+
self.assertIn("prohibited newline characters", msg)
416+
self.assertIn("X-OPTION\\nX-INJECTED-1 X-OPTION2\\nX-INJECTED-2", msg)
417+
# XXX (see comment in testSend)
418+
time.sleep(0.01)
419+
smtp.quit()
420+
421+
debugout = smtpd.DEBUGSTREAM.getvalue()
422+
self.assertNotIn("X-OPTION", debugout)
423+
self.assertNotIn("X-OPTION2", debugout)
424+
self.assertNotIn("X-INJECTED-1", debugout)
425+
self.assertNotIn("X-INJECTED-2", debugout)
426+
372427
def testSendNullSender(self):
373428
m = 'A test message'
374429
smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Made the internal ``putcmd`` function in :mod:`smtplib` sanitize input for
2+
presence of ``\r`` and ``\n`` characters to avoid (unlikely) command injection.

0 commit comments

Comments
 (0)
0