PHP变量流量层面WAF绕过
2022-7-12 23:24:11 Author: xz.aliyun.com(查看原文) 阅读量:25 收藏

[TOC]

简介

  • 本文主要研究PHP的GET/POST/COOKIE大变量生成过程,及可能在WAF流量层面绕过的一些TRICKS
  • 实验环境:PHP 7.3.4 在FPM模式下运行
  • PHP变量处理的主要代码在main/php_variables.c,调用栈如下:

  • 由于代码流程过长,本文不贴出具体代码,但是会在相应地方给出github链接供参考
  • PHP示例代码
<?php

echo "get:";
var_dump($_GET);
echo "cookie:";
var_dump($_COOKIE);
echo "post:";
var_dump($_POST);

TRICKS

变量名和值会进行url解码

  • 以解析$_GET变量为例,大致流程为:获取请求字符串-->获取分割符&-->使用=分割key和value。
  • 在解析key和value时,会分别对其进行url解码,关键代码如下:
if (val) { /* have a value */
            size_t val_len;
            size_t new_val_len;

            *val++ = '\0';
            // 对key进行url解码
            php_url_decode(var, strlen(var));
            // 对value进行url解码
            val_len = php_url_decode(val, strlen(val));
            val = estrndup(val, val_len);
            if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len)) {
                php_register_variable_safe(var, val, new_val_len, &array);
            }
            efree(val);
    }

变量名截断

  • 我们知道00在C语言中意味着字符串的结尾,其编码为%00
  • 在对key进行url解码之后,%00转换为00而截断了key字符串。
  • 但是对value进行url解码的时候,获取了其返回值val_len,即字符串长度,后续注册变量时,也是使用val_len进行内存中的操作,所以未能截断value的值

变量名之前的空格会被忽略

  • URL 不能包含空格。URL 编码通常使用 + 来替换空格

  • 使用%20替换空格

  • 在注册变量时,PHP会对变量名进行判断,丢弃变量名前的空格,关键代码如下:
while (*var_name==' ') {
        var_name++;
    }

变量名的空格和.会转化为_

  • 首先明确一个问题,PHP的变量名中是不能包含点号的。 但是为了处理表单中的点号命名,PHP就会自动把点号.转换成下划线_
  • 这个转换的过程也是发生在PHP变量的注册过程中,关键代码如下:
/* ensure that we don't have spaces or dots in the variable name (not binary safe) */
    for (p = var; *p; p++) {
        if (*p == ' ' || *p == '.') {
            *p='_';
        } else if (*p == '[') {
            is_array = 1;
            ip = p;
            *p = 0;
            break;
        }
    }

变量名的[会转换为_

  • 这个转换过程与.的转换过程不同。PHP在遇到[符号时,会认为变量为数组。后续进行数组处理时,如果未能找到与[匹配的],则会将[替换为.关键代码如下:
ip = strchr(ip, ']');
        if (!ip) {
            /* PHP variables cannot contain '[' in their names, so we replace the character with a '_' */
            *(index_s - 1) = '_';

            index_len = 0;
            if (index) {
                index_len = strlen(index);
            }
            goto plain_var;
            return;
        }

参考


文章来源: https://xz.aliyun.com/t/11512
如有侵权请联系:admin#unsafe.sh