Skip to content

Commit 4f72e60

Browse files
davisjamtim-onetiran
committed
Prevent low-grade poplib REDOS (CVE-2018-1060)
The regex to test a mail server's timestamp is susceptible to catastrophic backtracking on long evil responses from the server. Happily, the maximum length of malicious inputs is 2K thanks to a limit introduced in the fix for CVE-2013-1752. A 2KB evil response from the mail server would result in small slowdowns (milliseconds vs. microseconds) accumulated over many apop calls. This is a potential DOS vector via accumulated slowdowns. Replace it with a similar non-vulnerable regex. The new regex is RFC compliant. The old regex was non-compliant in edge cases. Co-authored-by: Tim Peters <tim.peters@gmail.com> Co-authored-by: Christian Heimes <christian@python.org>
1 parent 6cdb795 commit 4f72e60

2 files changed

Lines changed: 12 additions & 2 deletions

File tree

Lib/poplib.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ def rpop(self, user):
308308
return self._shortcmd('RPOP %s' % user)
309309

310310

311-
timestamp = re.compile(br'\+OK.*(<[^>]+>)')
311+
timestamp = re.compile(br'\+OK.[^<]*(<.*>)')
312312

313313
def apop(self, user, password):
314314
"""Authorisation

Lib/test/test_poplib.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,9 +306,19 @@ def test_noop(self):
306306
def test_rpop(self):
307307
self.assertOK(self.client.rpop('foo'))
308308

309-
def test_apop(self):
309+
def test_apop_normal(self):
310310
self.assertOK(self.client.apop('foo', 'dummypassword'))
311311

312+
def test_apop_REDOS(self):
313+
# Replace welcome with very long evil welcome.
314+
# NB The upper bound on welcome length is currently 2048.
315+
# At this length, evil input makes each apop call take
316+
# on the order of milliseconds instead of microseconds.
317+
evil_welcome = b'+OK' + (b'<' * 1000000)
318+
with test_support.swap_attr(self.client, 'welcome', evil_welcome):
319+
# The evil welcome is invalid, so apop should throw.
320+
self.assertRaises(poplib.error_proto, self.client.apop, 'arthur', 'kingofbritons')
321+
312322
def test_top(self):
313323
expected = (b'+OK 116 bytes',
314324
[b'From: postmaster@python.org', b'Content-Type: text/plain',

0 commit comments

Comments
 (0)