代码之家  ›  专栏  ›  技术社区  ›  John

发出不带正斜杠的HTTP请求

  •  0
  • John  · 技术社区  · 4 年前

    我在Apache访问日志中遇到了一个奇怪的HTTP请求:

    “得到 www.example.com HTTP/1.0“

    使用浏览器(Waterfox、Firefox或Chrome,按此顺序)或PuTTY/cURL|终端,我如何再现此HTTP请求?最好为 localhost 因为我可以实时查看日志。

    我读了一些书 显然地 cURL只能发出绝对URL请求。我也无法在Waterfox的网络面板中通过编辑和重新发送来重现这一点。此请求触发了我希望在系统中修复的一些小错误。

    0 回复  |  直到 4 年前
        1
  •  4
  •   regilero    4 年前

    在终端中,这相当 容易的 执行 任何 请求。

    你可以

    • 在端口80上使用telnet telnet 127.0.0.1 80 。然后,您必须编写请求(您可能需要快速键入,服务器可能会因结尾行错误而拒绝您,而不是\r\n)
    • 要绕过telnet限制,您可以首先使用简单的 printf :
    # regular HTTP query
    printf 'GET / HTTP/1.0\r\nHost: www.example.com\r\n\r\n'
    # or the 'absolute url' mode
    printf 'GET www.example.com HTTP/1.0\r\n\r\n'
    # or even the official absolute uri mode, I think that's the correct one
    printf 'GET http://www.example.com/ HTTP/1.0\r\n\r\n'
    

    但是 输出函数 echo ,具有特殊字符处理(如 \r\n ). 因此,您必须复制结果并将其粘贴到telnet。

    我更喜欢使用 netcat (有时被称为 nc )管理tcp/ip套接字连接而不是telnet,并使用管道将printf结果直接放入tcp/ip套接字(如果需要https,则必须使用opensslclient而不是netcat)。那是:

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

    这就是你的低技术浏览器。其优点是能够编写任何类型的错误查询。代替第一个标头中位置的aboslute url是RFC中存在的,用于处理与非常旧的HTTP 0.9的兼容性:

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

    在此请求中,要使用的正确VirtualHost是来自位置的VirtualHost,而不是来自Host标头的VirtualHost:

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

    这就是基础 James Kettle's Host header attacks back in 2013 。所以我建议你有效地跟踪 次要事件 并修复它们。学习如何在服务器中注入任何特殊的url总是很好的。

    您也可以使用curl发送精心编制的请求,但根据定义,真正的浏览器和命令行浏览器往往会避免发送精心编制糟糕的请求。

    当您处理一大串这样的服务时,跟踪来自终端的HTTP服务器的真实响应也可以非常有效地跟踪哪个服务器或代理发生故障。学习如何在没有curl的情况下在tcp套接字中谈论HTTP,这很有用。

        2
  •  0
  •   PHP Guru    4 年前

    首先安装Telnet。

    然后将以下内容复制并粘贴到终端窗口中:

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

    按两次Enter键。

    这是我的访问日志中的样子:

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

    你也可以用PHP来实现这一点。这是我创建的一个名为test.php的文件:

    <?php
    $fp = stream_socket_client("tcp://localhost:80", $errno, $errstr, 30) or die("$errstr ($errno)");
    $request = "GET www.example.com HTTP/1.0\r\n\r\n";
    $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;
    

    上面所做的与使用PHP做的相同。使用上面的文本创建一个PHP文件,将浏览器指向它,它应该显示“请求已成功发送”,然后检查您的访问日志。

    编辑:

    如果您需要使用TLS,请尝试以下操作。再次另存为test.php,并将浏览器指向此文件:

    $fp = fsockopen("tls://localhost", 443, $errno, $errstr, 30) or die("$errstr ($errno)");
    $request = "GET www.example.com HTTP/1.0\r\n\r\n";
    $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;
    
        3
  •  0
  •   Tomas Ebenlendr    1 年前

    您可以(在某种程度上)使用curl对请求进行后期处理。Curl不验证方法(-X、--request或CURLOPT_CUSTOMREQUEST)。因此,您可以使用“换行注入”。

    这里有一个例子,我通过HTTP发送代理请求,指示apache充当反向代理,为我启动TLS(当我需要一些辅助服务器上的软件能够与只接受最新版本TLS的服务器通信时,我使用这种技术)。

    请注意,示例使用 bash 回声的变体,正确插入 CR LF 字符。

    $ curl -v -X "$(echo -en 'GET https://target.domain/actual/path HTTP/1.1\r\nX-Ignore-Injection:' )" my.apache.proxy.example:8080/ignored/path
    * Trying 1.2.3.4:8080...
    * Connected to my.apache.proxy.example (1.2.3.4) port 8080 (#0)
    > GET https://target.domain/actual/path HTTP/1.1
    > X-Ignore-Injection: /ignored/path HTTP/1.1
    > Host: my.apache.proxy.example:8080
    > User-Agent: curl/7.83.0
    > Accept: */*
    ...