Skip to content

Potential HTTP Response Splitting Vulnerability #1227

Closed
@jamadden

Description

@jamadden

This header injection vulnerability was recently reported to and fixed in both waitress (WSGI server) and WebOb (and waitress has an outstanding issues to discuss further possible vulnerabilities). I also made changes to gevent for these issues.

gunicorn seems to be partly (but not entirely) vulnerable to these issues as well, across at least the sync and gevent workers.

Here are three apps, each producing different kinds of bad output. The badvalue case (invalid values in the header values) is probably the most likely injection vulnerability, with the next being the badname case (invalid value in the header names) and the least likely being the badstatus case (invalid value in the status line):

def badvalue(environ, start_response):
    start_response("200 BadValue",
                   [("Test", "Hi\r\nContent-length: 0\r\nConnection: keep-alive\r\nTransfer-Encoding: identity\r\n\r\n\r\n")])
    return [b"This should be the body!"]

def badname(environ, start_response):
    start_response("200 BadName",
                   [("\r\n\r\n\r\nContent-length: 0\r\nConnection: close\r\n\r\n", "Nothing")])
    return [b"This should be the body!"]

def badstatus(environ, start_response):
    start_response("200 Evil\r\nContent-Length: 0\r\nConnection: close\r\n\r\n", [])
    return [b"This should be the body!"]

Here's what happens hitting badvalue. We get a bunch of duplicate headers that might confuse clients:

$ http 127.0.0.1:8000
HTTP/1.1 200 BadValue
Connection: close
Connection: keep-alive
Content-length: 0
Date: Thu, 17 Mar 2016 13:33:39 GMT
Server: gunicorn/19.4.5
Test: Hi
Transfer-Encoding: chunked
Transfer-Encoding: identity

This should be the body!

Here's what happens hitting badname. The worst I was able to do was produce malformed HTTP; on other servers I was able to cause clients to hang, but I haven't reproduced that with gunicorn (yet):

$ http 127.0.0.1:8000
HTTP/1.1 200 BadName
Connection: close
Connection: close: Nothing
Content-length: 0
Date: Thu, 17 Mar 2016 13:36:39 GMT
Server: gunicorn/19.4.5
Transfer-Encoding: chunked

This should be the body!

Finally, here's badstatus. Here, we completely override the rest of the response:

$ http 127.0.0.1:8000
HTTP/1.1 200 Evil
Connection: close
Content-Length: 0


Should gunicorn check for and raise exceptions for these type of malformed values in start_response?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions