PHP安全相关的笔记

Published: 2022年08月13日

In Vuln.

PHP是WEB爷入门的东西,所以我打算好好学学习它,并把相关内容记下来,慢慢来...

clipart2934061

危险函数

命令执行

system(), passthru(), exec(), shell_exec(, ` , popen(), proc_open(), pcntl_exec(

代码执行

eval\s*\(, asert\s*\(preg_replace\s*\(, call_user_func\s*\(, include, requirecall_user_func_array(, create_function(, array_map(, ob_start(, mail(, usort, uasort

还有个preg_replace_callback可以用来执行代码,写后门用吧

反序列化

反序列化可构造任意值,而一些魔法方法(__destruct__toString__sleep__wakeup__call__construct)若存在问题可执行危险操作[2],若存在框架可看phpggc是否有已知Gadget,主要找unserializephar利用点。

这里重点看phar,它可类比为java中的jar文件,其具体存储可用zip/tar/phar格式,其中phar是专为该功能设计的格式,它们含如下内容

1.stub为一段bootstrap代码,当在执行上下文(如include文件时)会执行它,它里面至少要有<?php ... __HALT_COMPILER();让引擎不再解析后面的内容,这在phar中位于文件首部,而在zip/tar中位于.phar/stub.php文件里

2.manifest含各种属性信息,里面最需要关注的是元数据metadata,它是序列化后的数据并且会被自动反序列化,元数据在zip中会被存放在单个文件或整体的注释(comment)里

3.contents没啥说的就是数据内容,根据存储格式可被bzip2/gzip按单个文件或整体压缩

4.signatuer是只存在于phar格式的签名信息(其实是摘要),包括签名值,签名算法和魔数GBMB,这意味着phar文件首部任意但尾部得合法(该部分可配置为不校验)

phar通常通过phar://流封装来触发,其利用条件如下:

1.能控制本地文件的全部或部分内容,例如通过文件上传方式或往session写内容等将恶意构造的phar文件写入,文件扩展名随意,文件可以被压缩去绕过某些检测

2.有使用文件流的地方且路径前半部可控,这样可通过phar://去操作恶意文件,这里若它对phar有检测,可尝试用php://filter/resource=phar:///compress.[bzip2|zlib]://phar://等方式来绕过,至于文件流相关函数见下文(也可参考[1])

3.存在反序列化利用链,注意由于这里的元数据不会在其他地方使用因此只有__wakeup__destruct能作为链的入口[0]

参考

[0] File Operation Induced Unserialization via the “phar://” Stream Wrapper (PPT)

[1] Phar与Stream Wrapper造成PHP RCE的深入挖掘

[2] 一篇文章带你深入理解漏洞之 PHP 反序列化漏洞

变量覆盖

当使用$$, extract没接收结果, parse_str没提供第二个参数, import_request_variables, register_globals=ON(配置文件)时可能存在变量覆盖漏洞,向$GLOBAL中任意写也会存在变量覆盖。PHP会解析GET/POST方式传入的字典,因此利用该漏洞可以覆盖很多危险点,如用?_SERVER[REMOTE_ADDR]=$(id)来控制原本不可控的点从而实现地址伪造或进行注入

文件操作

主要关心文件读写操作:file_get_contents, file_put_contentsmove_uploaded_file, renameunlink, rmdirfopen, fread, fwrite, fputs, fgets, fgetc, readfile, highlight_file, show_source, parse_ini_file

注:几乎所有能输入文件名的函数都可解析伪协议,利用此可绕过一些限制(如路径后缀)或实现其他攻击(如反序列化)...

解码操作

base64_decode, urldecode, decodeaes, des, sm4, (a)rc4, blowfish, crypt, decryptmd5, auth, rand, srand, seed

注:在使用rand时,若存在足够的样本可用php_mt_rand反推出种子

服务端请求伪造

关注:file_get_contentscurlfsockopenreadfilefopen

其他

安全相关函数

1.addslashes: 为'/"/\/NUL添加\转义,由于它只懂PHP语意并不适用于其他组件(如不适合MySql过滤,可能存在无'时绕过或宽子节注入)

2.htmlspecialchars/htmlentities: HTML实体编码,可以防XSS

3.strip_tags: 删除字符串中的HTML/PHP/JS等标记,仅此而已

4.escapeshellcmd: 作用于整条命令,防止多条命令被执行(他不会对参数转义,因此可以任意加参数),具体的,它在这些符号&#;`|*?~<>^()[]{}$\, \x0A 和 \xFF 前加\转义,以及对不匹配的'"转义

5.escapeshellarg: 用于对单个参数进行转义

超全局变量

有9个超全局变量,如$GLOBAL是全局变量的引用,不过这里主要关注$_SERVER,它里面有很多字段:

1.SERVER_NAME/SERVER_PORT: 如果webserver没设置,则使用HOST头里的值

2.PHP_SELF是当前URI(包括PATH_INFO但不包括QUERY_STRING),PATH_INFO是URI中.php之后的内容,SCRIPT_NAME是PHP_SELF去掉PHP_INFO的内容

3.SCRIPT_FILENAME是当前脚本的绝对地址(符号连接未解析),PATH_TRANSLATED是解析符号连接后的绝对地址

特殊配置

配置 说明
register_globals 早期支持,会把请求注册到全局
magic_quotes_gpc 设置后GPC的'"\0x00会被转意
disable_functions 限制了能使用的函数,通过其他其他组件绕
open_basedir 限定了能打开的目录,可通过DirectoryIterator+Glob绕

版本特性

这里记录每个版本间与安全相关的变化...

5.X

版本 新增或修改 删除
4.0->5.0 include_once/require_once在windows下不区分路径大小写 -
5.1->5.2 添加了data:流; libxml_disable_entity_loader可设置不加载外部实体,libxml 2.9.0开始默认不处理实体了; 新增了filter模块用于对变量进行过滤; 新增allow_url_include选项来禁止远程文件包含,且默认禁止 -
5.2->5.3 新增glob://phar://流封装; 新增dechunk流过滤器,bz2.decompress支持串联了; 新增了内置Phar -
5.3->5.4 <?=形式的短标签始终可用 不再支持register_globals选项; 不再支持安全模式safe mode; 不再支持magic_quotes_[gpc|runtime|sybase]选项
5.5->5.6 php://input现在可多次打开来重用; 添加hash_equals函数进行安全的字符串比较 -

7.X

版本 新增或修改 删除
5.6->7.0 string处理时,16进制字符串不再被认为是数字,因此在一些比较时将会失败; int转换时8进制时若存在无效数字现在将直接出错而不是截断; 整数溢出会产生E_WARNING错误并返回null而不是截断; unserialize支持设置允许反序列化的类(默认允许所有); assert现在是一个语言结构而非函数了 不再支持preg_replace()/e选项; 不再支持<%%>/<%= %>/`