skip to Main Content

I came across an odd HTTP request in my Apache access log:

"GET www.example.com HTTP/1.0"

Using a browser (Waterfox, Firefox or Chrome, (in that order)) or PuTTY/cURL|Terminal how can I reproduce this HTTP request? Preferably for localhost as I can see the logs in real-time.

I did some reading and apparently cURL can only make absolute URL requests. I also have not been able to reproduce this with Edit and Resend in the Network panel of Waterfox. This request triggered some minor errors I wish to fix in my system.

2

Answers


  1. In a terminal it’s quite easy to perform any request.

    You can

    • use telnet on port 80 telnet 127.0.0.1 80. Then you have to write the request (you may need to type fast, and the server may reject you for bad end lines n instead of rn)
    • to bypass telnet limitation you can first write your requests with a simple printf:
    # regular HTTP query
    printf 'GET / HTTP/1.0rnHost: www.example.comrnrn'
    # or the 'absolute url' mode
    printf 'GET www.example.com HTTP/1.0rnrn'
    # or even the official absolute uri mode, I think that's the correct one
    printf 'GET http://www.example.com/ HTTP/1.0rnrn'
    

    But printf is just the same thing as echo, with special charaters handling (like the rn). So you have to copy the result and paste it to telnet.

    I prefer using netcat (sometimes called nc) to manage the tcp/ip socket connection instead of telnet, and put directly the printf result to the tcp/ip socket with a pipe (if you need https you’ll have to use openssl_client instead of netcat). That’s:

    printf 'GET www.example.com HTTP/1.0rnrn' | nc -q 3 127.0.0.1 80
    # or
    printf 'GET http://www.example.com/ HTTP/1.0rnrn' | nc -q 3 127.0.0.1 80
    

    And that’s it you have your low tech browser. With the advantage of being able to write any sort of bad query. The aboslute url used in place of the location in the first header is something present in the RFC, to handle compatibility with the very old HTTP 0.9:

    # HTTP 0.9
    printf 'GET www.example.com/foo/bar rn' | nc -q 3 127.0.0.1 80
    

    And in this request the right VirtualHost to use is the one from the location, not from the Host header:

    # regular HTTP query
    printf 'GET http://www.vhost2.com/foo HTTP/1.0rnHost: www.vhost1.comrnrn' |
      nc -q 3 127.0.0.1 80
    

    That was the base of James Kettle’s Host header attacks back in 2013. So I recommend you effectively track the minor events and fix them. And it’s always good to learn how to inject any special url in your server.

    You may be able to send crafted requests also with curl, but by definition real browsers and command line browsers tends to avoid sending badly crafted requests.

    Tracking real response from HTTP servers from a terminal can also be quite effective when tracking down which server, or proxy is broken when you handle a big chain of such services. Learn how to talk HTTP in a tcp socket, without curl, that’s usefull.

    Login or Signup to reply.
  2. First install Telnet.

    Then copy and paste the following into a terminal window:

    telnet localhost 80
    
    GET www.example.com HTTP/1.0
    

    Press Enter two times.

    This is what it looks like in my access logs:

    ::1 - - [30/Oct/2020:23:37:28 -0700] "GET www.example.com HTTP/1.0" 400 310
    

    You can also do this with PHP. Here is a file I created called test.php:

    <?php
    $fp = stream_socket_client("tcp://localhost:80", $errno, $errstr, 30) or die("$errstr ($errno)");
    $request = "GET www.example.com HTTP/1.0rnrn";
    $written = 0;
    do {
        $bytes = fwrite($fp, substr($request, $written)) or die('fwrite error');
        $written+= $bytes;
    }
    while ($written!==strlen($request));
    fclose($fp) or die('fclose error');
    echo 'Request sent successfully';
    exit;
    

    The above does the same thing it just uses PHP to do it. Create a PHP file with the above text, point your browser to it, it should say "Request sent successfully" and then check your access logs.

    Edit:

    If you need to use TLS then try the following instead. Again save as test.php and point your browser to this file:

    $fp = fsockopen("tls://localhost", 443, $errno, $errstr, 30) or die("$errstr ($errno)");
    $request = "GET www.example.com HTTP/1.0rnrn";
    $written = 0;
    do {
        $bytes = fwrite($fp, substr($request, $written)) or die('fwrite error');
        $written+= $bytes;
    }
    while ($written!==strlen($request));
    while (!feof($fp)) {
        echo fgets($fp, 128);
    }
    fclose($fp) or die('fclose error');
    echo 'Request sent successfully';
    exit;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search