欢迎来到 无奈人生 安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

如何绕过过滤器和WAF规则实现PHP远程漏洞利用

来源: 作者: 时间:2019-02-24 21:26 点击: 我要投稿
广告位API接口通信错误,查看德得广告获取帮助

在本文中,我们将主要分析如何绕过过滤器、输入清理和WAF规则,实现PHP的远程代码执行。通常,当我在写这样的文章时,人们总是会问,“真的有人写出这样的代码吗?”并且通常都不是疑问句。在再次被问到这个问题之前,我要抢先回答:“是真的。”
在研究过程中,我们对两个易受攻击的PHP脚本进行了测试。其中,第一个脚本非常简单,并且近乎愚蠢,但它只是为了重现一个远程代码执行漏洞的利用场景:

显然,第六行存在问题。第三行尝试拦截注入system、exec或passthru之类的函数。在PHP中,有许多其他函数可以执行系统命令,但我们重点关注这三个函数。该脚本在CloudFlare WAF后面的Web服务器中运行。和往常一样,我使用了CloudFlare,因为它非常简单,并且广为人知,并不意味着CloudFlare WAF不安全。其他所有WAF都或多或少会有相同的问题。第二个脚本落后于ModSecurity + OWASP CRS3的安全要求。
尝试读取/etc/passwd
针对第一个脚本,我尝试使用system()函数,通过请求/cfwaf.php?code=system(“cat /etc/passwd”);来读取/etc/passwd。

如大家所见,CloudFlare会阻止我的请求,可能是由于/etc/passwd。但是,我们有方法能轻松绕过,可以使用类似于cat /etc$u/passwd这样的命令。

CloudFlare WAF已经被绕过,但其中还存在对用户输入的检查,这阻止了我的请求,因为我正在尝试使用“system”函数。那么不禁要问,是否有一种语法,能让我在不使用“system”字符串的情况下使用系统功能呢?我们来看看PHP官方文档中,有关字符串的内容:https://secure.php.net/manual/en/language.types.string.php
PHP字符串转义序列
\[0–7]{1,3}是八进制表示法的字符序列,可以溢出一个字节。例如:“\400” === “\000”
\x[0–9A-Fa-f]{1,2}是十六进制表示法的字符序列。例如:“\x41"
\u{[0–9A-Fa-f]+}是Unicode代码点(Codepoint)序列,将作为该代码点的UTF-8表示输出到字符串(在PHP 7.0.0版本中加入)。
看来,并不是所有人都知道PHP中有很多用于表示字符串的语法。因此,使用“PHP变量函数”,就成为了我们绕过过滤器和WAF规则的瑞士军刀。
PHP变量函数
PHP支持变量函数的概念。这意味着,如果变量名称附加了括号,PHP将会查找与变量等价的名称相同的函数,并尝试执行。除此之外,这可以用于实现回调、函数表等功能。
这意味着,像var(args);和“string”(args);这样的内容,都等价于function(args);。如果我能够通过使用变量和字符串来调用函数,那么我就可以使用转义序列,而不再是函数的名称。一个例子如下所示:

其中,第三种语法是十六进制表示法中的字符转义序列,PHP将其转换为字符串“system”,然后使用参数“ls”将其转换为函数system。我们在易受攻击的脚本上进行尝试:

这种技术不适用于所有的PHP函数,变量函数不适用于类似echo、print、unset()、isset()、empty()、include、require这样的语言结构。利用包装器函数,可以将这些结构中的任何一个作为可变函数。
改进用户输入清理
在易受攻击的脚本中,如果我从用户输入中排除双引号和单引号等字符,那么会发生什么?即使不使用双引号,是否也可以绕过它?我们来进行一下尝试:

正如我们在第三行所看到的那样,现在脚本将阻止在$_GET[code] querystring参数中使用双引号和单引号。现在,我之前的Payload应该已经被阻止:

幸运的是,在PHP中,我们并不总是需要引号来表示字符串。PHP中,还存在其他能够声明元素的类型,例如$a = (string)foo;。在这种情况下,$a包含字符串foo。此外,在没有特定类型声明的圆括号中的内容,都将被视为字符串:

基于此,我们有两种绕过新过滤器的方法:第一种方法是使用类似于(system)(ls);的形式,但我们不能再代码参数中使用“system”,所以我们可以连接字符串,类似于(sy.(st).em)(ls);。第二种方法是使用$_GET变量。如果我发送一个请求,类似于?a=system&b=ls&code=$_GET[a]($_GET[b]);,那么其结果为$_GET[a],就会替换为字符串“system”。同时,$_GET[b]可以被替换为字符串“ls”。这样一来,我就能绕过所有过滤器了!

[1] [2]  下一页

在本文中,我们将主要分析如何绕过过滤器、输入清理和WAF规则,实现PHP的远程代码执行。通常,当我在写这样的文章时,人们总是会问,“真的有人写出这样的代码吗?”并且通常都不是疑问句。在再次被问到这个问题之前,我要抢先回答:“是真的。”
在研究过程中,我们对两个易受攻击的PHP脚本进行了测试。其中,第一个脚本非常简单,并且近乎愚蠢,但它只是为了重现一个远程代码执行漏洞的利用场景:

显然,第六行存在问题。第三行尝试拦截注入system、exec或passthru之类的函数。在PHP中,有许多其他函数可以执行系统命令,但我们重点关注这三个函数。该脚本在CloudFlare WAF后面的Web服务器中运行。和往常一样,我使用了CloudFlare,因为它非常简单,并且广为人知,并不意味着CloudFlare WAF不安全。其他所有WAF都或多或少会有相同的问题。第二个脚本落后于ModSecurity + OWASP CRS3的安全要求。 本文来自无奈人生安全网
尝试读取/etc/passwd
针对第一个脚本,我尝试使用system()函数,通过请求/cfwaf.php?code=system(“cat /etc/passwd”);来读取/etc/passwd。

如大家所见,CloudFlare会阻止我的请求,可能是由于/etc/passwd。但是,我们有方法能轻松绕过,可以使用类似于cat /etc$u/passwd这样的命令。

CloudFlare WAF已经被绕过,但其中还存在对用户输入的检查,这阻止了我的请求,因为我正在尝试使用“system”函数。那么不禁要问,是否有一种语法,能让我在不使用“system”字符串的情况下使用系统功能呢?我们来看看PHP官方文档中,有关字符串的内容:https://secure.php.net/manual/en/language.types.string.php
PHP字符串转义序列
\[0–7]{1,3}是八进制表示法的字符序列,可以溢出一个字节。例如:“\400” === “\000” copyright 无奈人生
\x[0–9A-Fa-f]{1,2}是十六进制表示法的字符序列。例如:“\x41"
\u{[0–9A-Fa-f]+}是Unicode代码点(Codepoint)序列,将作为该代码点的UTF-8表示输出到字符串(在PHP 7.0.0版本中加入)。
看来,并不是所有人都知道PHP中有很多用于表示字符串的语法。因此,使用“PHP变量函数”,就成为了我们绕过过滤器和WAF规则的瑞士军刀。
PHP变量函数
PHP支持变量函数的概念。这意味着,如果变量名称附加了括号,PHP将会查找与变量等价的名称相同的函数,并尝试执行。除此之外,这可以用于实现回调、函数表等功能。
这意味着,像var(args);和“string”(args);这样的内容,都等价于function(args);。如果我能够通过使用变量和字符串来调用函数,那么我就可以使用转义序列,而不再是函数的名称。一个例子如下所示:

其中,第三种语法是十六进制表示法中的字符转义序列,PHP将其转换为字符串“system”,然后使用参数“ls”将其转换为函数system。我们在易受攻击的脚本上进行尝试:

内容来自无奈安全网


这种技术不适用于所有的PHP函数,变量函数不适用于类似echo、print、unset()、isset()、empty()、include、require这样的语言结构。利用包装器函数,可以将这些结构中的任何一个作为可变函数。
改进用户输入清理
在易受攻击的脚本中,如果我从用户输入中排除双引号和单引号等字符,那么会发生什么?即使不使用双引号,是否也可以绕过它?我们来进行一下尝试:

正如我们在第三行所看到的那样,现在脚本将阻止在$_GET[code] querystring参数中使用双引号和单引号。现在,我之前的Payload应该已经被阻止:

copyright 无奈人生


幸运的是,在PHP中,我们并不总是需要引号来表示字符串。PHP中,还存在其他能够声明元素的类型,例如$a = (string)foo;。在这种情况下,$a包含字符串foo。此外,在没有特定类型声明的圆括号中的内容,都将被视为字符串:

基于此,我们有两种绕过新过滤器的方法:第一种方法是使用类似于(system)(ls);的形式,但我们不能再代码参数中使用“system”,所以我们可以连接字符串,类似于(sy.(st).em)(ls);。第二种方法是使用$_GET变量。如果我发送一个请求,类似于?a=system&b=ls&code=$_GET[a]($_GET[b]);,那么其结果为$_GET[a],就会替换为字符串“system”。同时,$_GET[b]可以被替换为字符串“ls”。这样一来,我就能绕过所有过滤器了!
本文来自无奈人生安全网

[1] [2]  下一页

www.wnhack.com

。 (责任编辑:admin)
【声明】:无奈人生安全网(http://www.wnhack.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱472701013@qq.com,我们会在最短的时间内进行处理。