ez_curl(http-header格式解析 + exprees 请求参数截断)
首先看 js 的 express 框架
1 | app.get('/flag', (req, res) => { |
必须满足查询参数中不包含 flase,请求头有 admin:true (这里的请求头是 post 中的请求头)
再看 web php 代码
$input = file_get_contents('php://input');
这里是直接获取的 post 内容
$headers = (array)json_decode($input)->headers;
将一个 JSON 字符串解析为 PHP 对象,然后提取其中的 headers
字段,并将其转换为 PHP 数组
1 | for($i = 0; $i < count($headers); $i++){ $offset = stripos($headers[$i], ':'); $key = substr($headers[$i], 0, $offset); $value = substr($headers[$i], $offset + 1); |
这段 PHP 代码遍历一个 HTTP 头数组($headers
),检查是否有 admin
头且其值包含 true
,如果匹配到,则终止脚本并返回 'try hard'
。
$params = (array)json_decode($input)->params;
同理,这一段用于将 post 中的 params 数据转化php数组
1 | $url .= http_build_query($params); //将 $params 转化为查询字符串并拼接到 url 后面 |
那么矛盾点就出来了,一个是请求头 header 的 admin,一个是请求参数 param 的 admin 的矛盾
首先解决 header
js 要求 admin 值包含 true,php 要求不能有 admin:true (包含) 出现
可以构造
1 | {headers:["admin: x"," true: y"]} |
本来应该这样
1 | {headers:["admin:true"]} |
RFC 7230(HTTP/1.1 协议的定义)规定了 field-name 是由一个或多个打印的 ASCII 字符组成,不包括分隔符,包括空格。因此,如果一个 field-name 的第一个字符是空格,那么这个 HTTP header 是非法的,应该被服务器或客户端忽略或拒绝。
根据rfc,header字段可以通过在每一行前面至少加一个SP或HT来扩展到多行
curl 生成的 headers 如下 (注意空格)
这段数据先传入服务端,被 php 函数处理加工,经过 curl 后是这样的(注意空格)
因为 curl 会找冒号去分开数据
1 | admin: x |
然后这段数据继续通过代理传向后端服务,由于协议,header 会转化为
1 | "admin": "x true y" |
从而绕过 js 处的 true 判断
然后解决 paramas
因为 curl 在 params 查询参数添加了 admin=flase,所以要想办法截断
而 express 框架对于查询参数大小是有截断的

大概是 1000 个参数
那么只要参数足够多就可以挤掉最后 curl 添加的 admin=false
构造
1 | params:["admin":true,"x":1,"x":1........] |
最后 exp
1 | {headers:["admin":"x"," true":"y"],arams:["admin":true,"x":1,"x":1........]} |
1 | import requests |
注意这里请求参数个数 1000,太大了比如 10000 就无法成功
而且请求参数尽量不要重复,也会出现错误
