前言
PHP SECURITY CALENDAR 平台 结合红日安全的文章进行代码审计训练
Wish List
考察:in_array函数缺陷
PHP手册对 in_array() 函数的定义:
in_array :(PHP 4, PHP 5, PHP 7)
功能 :检查数组中是否存在某个值
定义 : bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
在 $haystack 中搜索 $needle ,如果第三个参数 $strict 的值为 TRUE ,则 in_array() 函数会进行强检查,检查 $needle 的类型是否和 $haystack 中的相同。如果找到 $haystack ,则返回 TRUE,否则返回 FALSE。
题目叫做愿望清单,代码如下
1 | class Challenge { |
这一关卡考察的是一个任意文件上传漏洞,而导致这一漏洞的发生则是不安全的使用 in_array() 函数来检测上传的文件名,即上图中的第12行部分。由于该函数并未将第三个参数设置为 true ,这导致攻击者可以通过构造的文件名来绕过服务端的检测,例如文件名为 7shell.php 。因为PHP在使用 in_array() 函数判断时,会将 7shell.php 强制转换成数字7,而数字7在 range(1,24) 数组中,最终绕过 in_array() 函数判断,导致任意文件上传漏洞。(这里之所以会发生强制类型转换,是因为目标数组中的元素为数字类型)
参考文章
Twig
题目叫做Twig,代码如下
1 | // composer require "twig/twig" |
这一关题目实际上用的是PHP的一个模板引擎 Twig ,本题考察XSS(跨站脚本攻击)漏洞。虽然题目代码分别用了 escape 和 filter_var 两个过滤方法,但是还是可以被攻击者绕过。在上图 第10行 中,程序使用 Twig 模板引擎定义的 escape 过滤器来过滤link,而实际上这里的 escape 过滤器,是用PHP内置函数 htmlspecialchars 来实现的,具体可以点击 这里 了解 escape 过滤器, htmlspecialchars 函数定义如下:
htmlspecialchars :(PHP 4, PHP 5, PHP 7)
功能 :将特殊字符转换为 HTML 实体
定义 :string htmlspecialchars ( string $string [, int $flags = ENT_COMPAT | ENT_HTML401 [, string$encoding = ini_get(“default_charset”) [, bool $double_encode = TRUE ]]] )
& (& 符号) =============== &
“ (双引号) =============== "
‘ (单引号) =============== '
< (小于号) =============== <
>(大于号) =============== >
第二处过滤在 第17行 ,这里用了 filter_var 函数来过滤 nextSlide 变量,且用了 FILTER_VALIDATE_URL 过滤器来判断是否是一个合法的url,具体的 filter_var 定义如下:
filter_var : (PHP 5 >= 5.2.0, PHP 7)
功能 :使用特定的过滤器过滤一个变量\
定义 :mixed filter_var ( mixed $variable [, int $filter = FILTER_DEFAULT [, mixed $options ]] )
针对两处过滤,可以使用javascript伪协议绕过。demo代码示例
使用 payload :?url=javascript://comment%250aalert(1) ,可以执行 alert 函数:
实际上,这里的 // 在JavaScript中表示单行注释,所以后面的内容均为注释,那为什么会执行 alert 函数呢?那是因为我们这里用了字符 %0a ,该字符为换行符,所以 alert 语句与注释符 // 就不在同一行,就能执行。当然,这里我们要对 % 百分号编码成 %25 ,因为程序将浏览器发来的payload:javascript://comment%250aalert(1) 先解码成: javascript://comment%0aalert(1) 存储在变量 $url 中(上图第二行代码),然后用户点击a标签链接就会触发 alert 函数。
参考文章:https://xz.aliyun.com/t/2457
Snow Flake
考察内容:
- class_exits() 函数->可以使用路径穿越来包含任意文件。
- 使用PHP的内置类 SimpleXMLElement 来进行 XXE 攻击
代码如下:
1 | function __autoload($className) { |
第一个漏洞:文件包含漏洞,第8行中使用了 class_exists() 函数来判断用户传过来的控制器是否存在,默认情况下,如果程序存在 __autoload 函数,那么在使用 class_exists() 函数就会自动调用本程序中的 __autoload 函数,这题的文件包含漏洞就出现在这个地方。攻击者可以使用 路径穿越 来包含任意文件,当然使用路径穿越符号的前提是 PHP5~5.3(包含5.3版本)版本 之间才可以。例如类名为: ../../../../etc/passwd 的查找,将查看passwd文件内容,我们来看一下PHP手册对 class_exists() 函数的定义:
class_exists :(PHP 4, PHP 5, PHP 7)
功能 :检查类是否已定义
定义 : bool class_exists ( string $class_name[, bool $autoload = true ] )
$class_name 为类的名字,在匹配的时候不区分大小写。默认情况下 $autoload 为 true ,当 $autoload 为 true 时,会自动加载本程序中的 __autoload 函数;当 $autoload 为 false 时,则不调用 __autoload 函数。
第二个漏洞:在第9行中,实例化类的类名和传入类的参数均在用户的控制之下,可以通过该漏洞,调用PHP代码库的任意构造函数。即使代码本身不包含易受攻击的构造函数,也可以使用PHP的内置类 SimpleXMLElement 来进行 XXE 攻击,进而读取目标文件的内容,甚至命令执行(前提是安装了PHP拓展插件expect)。PHP手册对 SimpleXMLElement 类的定义:
SimpleXMLElement :(PHP 5, PHP 7)
功能 :用来表示XML文档中的元素,为PHP的内置类。
关于 SimpleXMLElement 导致的XXE攻击,demo:
1 |
|
运行结果:
参考:https://xz.aliyun.com/t/2459
False Beard
考察内容:
- strpos使用不当引发漏洞
- 只考虑到 strpos 函数返回 false 的情况,却忽略了匹配到的字符在首位时会返回 0 的情况
题目代码如下:
1 | class Login { |
题目分析:
第11行 和 第12行 ,程序通过格式化字符串的方式,使用 xml 结构存储用户的登录信息。实际上这样很容易造成数据注入。然后 第21行 实例化 Login 类,并在 第16行 处调用 login 方法进行登陆操作。在进行登录操作之前,代码在 第8行 和 第9行 使用 strpos 函数来防止输入的参数含有 < 和 > 符号,猜测开发者应该是考虑到非法字符注入问题。我们先来看一下 strpos 函数的定义:
strpos — 查找字符串首次出现的位置
作用:主要是用来查找字符在字符串中首次出现的位置。
结构:int strpos ( string $haystack , mixed $needle [, int $offset = 0 ] )
在上面这个例子中,strpos 函数返回查找到的子字符串的下标。如果字符串开头就是我们要搜索的目标,则返回下标 0 ;如果搜索不到,则返回 false 。在这道题目中,开发者只考虑到 strpos 函数返回 false 的情况,却忽略了匹配到的字符在首位时会返回 0 的情况,因为 false 和 0 的取反均为 true 。这样我们就可以在用户名和密码首字符注入 < 符号,从而注入xml数据。我们尝试使用以下 payload ,观察 strpos 函数的返回结果。
1 | user=<"><injected-tag%20property="&pass=<injected-tag> |
如上图所示,很明显是可以注入xml数据的。