PHP代码审计的意义
什么是代码审计
什么是代码审计?代码审计就是获取目标的源代码,这个目标可以是一个网站,也可以是一个手机app,只要我们得到了目标的源代码,我们就可以去挖掘目标系统的漏洞,代码审计是指对源代码进行检查,寻找到代码中的bug,这是一项需要多方面技能的技术,包括对编程的掌握、漏洞形成原理的理解,系统和中间件等的熟悉。代码审计是企业安全运营人员及安全从业者必备的基础能力,代码审计在很多场景中都需要用到,比如企业安全运营、渗透测试、漏洞研究等
黑盒测试与白盒测试的区别
在代码审计中,黑盒测试和白盒测试的主要区别就在于是否可以拿到源代码,黑盒测试是拿不到源代码的,白盒测试是可以拿到源代码的
是否应该掌握代码审计
渗透测试人员掌握代码审计是非常重要的,因为我们在渗透测试的过程中经常需要针对目标环境的payload进行调试。另外,如果通过目录扫描工具扫到Web目录下的一个源码备份包,通常攻击者都会利用源码包找寻一些配置文件或者敏感信息,因为里面有数据库、API等一类的配置。对于掌握和没掌握代码审计的人来说,结果完全不一样、对于没掌握代码审计的人来说,可能就止步于此,而对于掌握了代码审计的人,他可以对源码包进行安全审计,发现网站的代码里面存在的漏洞,然后利用挖掘的漏洞进行渗透,总而言之,代码审计是渗透测试必不可少的一部分
编程能力的要求
代码审计对编程语言的基础有一定的要求,至少要能看的懂代码,能够理解代码是什么意思还有代码的逻辑,即使在代码审计中碰到一些你没见过的函数,也是可以直接上百度去查的,所以只要初步掌握了编程语言,想学习PHP代码审计应该都不是什么问题
PHP代码审计流程
首先做代码审计第一种是通读全文法,通读全文法作为最麻烦的方法也是最全面的审计方法,特别是大型的项目,通读全文也是了解整个项目,了解业务逻辑最好方法,了解整个项目,这样也可以挖掘到更多的中高危漏洞,然后第二种是检查敏感函数的参数,然后回溯变量,判断变量是否可控并且没有经过严格的过滤,这是一个逆向追综的过程,名为敏感函数参数回溯法,这个方法是最有效的,最常用的方法,大多数漏洞的产生是因为函数的使用不当导致的,我们可以全局搜索一些敏感函数,看看是否有未经过滤的参数传进来,就可以挖掘漏洞。第三种叫定向功能分析方法,这个方法主要是根据程序的业务逻辑来进行代码审计的,查看网站的功能,大概推测可能存在那些漏洞常见的功能漏洞,程序初始安装、文件上传、数据库备份、找回密码、验证码等。还有一种是可以先找出哪些文件在接受外部传入的参数,然后跟踪变量的传递过程,观察是否有变量传入到高危的函数中,或者在传递的过程中是否有代码逻辑的漏洞,这是一种正向追踪的方式、这样的挖掘方式比逆向挖掘的更全。
代码审计需要使用那些软件
我们在PHP代码审计的过程中经常需要用到以下几款软件:
- PHPStorm
- SQLyog
- 虚拟机
- Burpsuite
- PHPStudy
- Seay源代码审计系统
代码审计环境搭建
这里提供了代码审计需要用到的工具,大家可以通过以下链接下载
链接:https://pan.baidu.com/s/1e-526vPdsDtSUoexZKZP8w?pwd=8888
提取码:8888
代码审计工具
代码审计工具是一类辅助我们做白盒测试的程序,他可以分为很多类,列如安全性审计以及代码规范性审计等。Seay源代码审计是一款针对于PHP代码安全性审计的系统,主要运行于Windows系统上,这款软件能够发现SQL注入、代码执行、命令执行、文件包含、文件上传、绕过转义防护、拒绝服务、XSS跨站、信息泄露、任意URL跳转等漏洞,基本上覆盖常见的PHP漏洞,系统配置了有以下的功能:
- 一键审计
- 快速函数定位
- 自定义多窗口搜索
- MySQL执行监控
- 一键调试选中代码
- 文档自动查询
- 插件扩展
- 代码高亮
- 编码调试转换
- 数据库执行监控
主界面如图所示:
php核心配置详解
代码在不同的环境下执行的结果也会大有不同,可能就因为一个配置问题,导致一个非常高危漏洞能够利用,也可能你已经找到的一个漏洞就因为你的配置的问题,导致你无法成功构造漏洞利用的代码。在PHP中,不同的版本中配置的指令也有不一样的地方,因此我们在代码审计之前需要非常熟悉PHP各个版本中配置文件的核心指令,才能更高效的挖掘漏洞
以下只列出会影响PHP脚本安全的配置列表以及核心配置选项:
- register_globals(全局变量注册开关)
该选项在设置为on的情况下,会直接吧用户GET、POST等方式提交上来的参数注册成全局变量并且初始化值为参数对应的值,使得提交参数可以直接在脚本中使用。register_globals在PHP版本小于等于4.2.3时设置为PHP_INI_ALL,中PHP5.3.0起被废弃,不推荐使用,在PHP5.4.0中移除了该选项 - allow_url_include(是否允许包含远程文件)
在该配置为on的情况下,它可以直接包含远程文件,当存在include( var ) 且 var)且var)且var可控的情况下,可以直接控制$var变量来执行PHP代码。allow_url_include在PHP5.2.0后默认设置为off,配置范围是PHP_INI_ALL。与之类似的配置还有allow_url_fopen,配置是否允许打开远程文件 - magic_quotes_gpc(魔术引号自动过滤)
magic_quotes_gpc在安全方面做了很大的贡献,主要他被开启,在不存在编码或者其他特殊绕过的情况下,可以使得很多漏洞无法被使用,他也是让渗透测试人员很头疼的一个东西。当该选项设置为on时,会自动在GET、POST、COOKIE变量中的单引号、双引号、反斜杠及空字符的前面加上反斜杠,但是在PHP5中并不会过滤$_SERVER变量,导致很多类似client-ip、referer一类的漏洞能够利用。在PHP5.3之后的不推荐使用magic_quotes_gpc,PHP5.4之后取消了magic_quotes_gpc。在PHP版本小于4.2.3时,配置范围是PHP_INI_ALL;在PHP版本大于4.2.3时,是PHP_INI_PERDIR - magic_quotes_runtime(魔术引号自动过滤)
magic_quotes_runtime也是自动在单引号、双引号、反斜杠及空字符的前面加上反斜杠。与magic_quotes_gpc的区别是处理的对象不一样,magic_quotes_runtime只对从数据库或者文件中获取的数据进行过滤,他的作用也很大,因为很多程序员只对外部输入的数据进行过滤,却没有想过从数据库获取的数据同样也会有特殊字符存在,所以攻击者的做法是先将攻击代码写入数据库,在程序读取、使用到被污染的数据后即可触发估计。同样magic_quotes_runtime在PHP5.4之后也被取消,配置范围是PHP_INI_ALL - magic_quotes_sybase(魔术引号自动过滤)
magic_quotes_sybase指令用于自动过滤特殊字符,当设置为on时,他会覆盖掉magic_quotes_gpc=on的配置中,即使配置了gpc=on也是没有效果的。这指令与gpc的共同点是处理的对象一致,即都对GET、POST、Cookie进行处理。而他们之间的区别在于处理的方式不同,magic_quotes_sybase仅仅是转义了空字符和吧单引号编程了双引号。于gpc相比他的配置范围是PHP_INI_ALL,在PHP5.4.0中移除了该选项 - safe_mode(安全模式)
安全模式是PHP内嵌的一种安全机制,当safe_mode=on时,联动可以配置的指令有safe_mode_includea_dir、safe_mode_exec_dir、safe_mode_allowed_env_vars、safe_mode_protected_env_vars。safe_mode指令的配置范围为PHP_INI_SYSTEM,PHP5.4之后被取消 - open_basedir PHP可访问目录
open_basedir指令用来现在PHP只能访问哪些目录,通常我们只需要设置Web文件目录即可,如果需要加载外部脚本,也需要吧脚本所在目录路径加入到open_basedir指令中,多个目录以分号分割。使用open_basedir需要注意的一点是,指定的现在实际上是前缀,而不是目录名。如果要将访问仅限制在指定的目录内,请用斜线结束路径名 - disable_functions(禁用函数)
当需要使用指令来禁止危险函数时,切记要把dl()函数也加到禁止列表,因为攻击者可以利用dl()函数来加载自定义的PHP拓展以突破disable_functions指令的限制。disable_functions的指令限制为php_ini_only - display_errors和error_reporting错误显示
display_errors表明是否显示PHP脚本内部错误的选项,在调试PHP的时候,通常把PHP错误显示打开,但是在生产环境中,建议关闭PHP错误回显,即设置display_errors=off,以避免一些安全隐患。在设置display_errors=on时,还可以配置一个指令是error_reporting,这选项用来配置错误显示的级别,可使用数字也可以使用内置常量配置。这两个指令的配置范围都是PHP_INI_ALL
PHP 危险函数归纳
在PHP中,以下的函数是PHP中经常用到的危险函数:
- include/require/include_once/require_once
- eval/assert/preg_replace/create_function
- system/passthru/exec/shell_exec
- file_get_contents/fread/readfile/file/show_source
- file_put_contents/fwrite/mkdir
- unlink/rmdir
- move_uploaded_file/copy/rename
- extract/parse_str
- simplexml_load_files/simplexal_load_string
- unserialize
- urldecode/base64_decode
代码执行函数
eval 把字符串作为PHP代码执行,很多常见的webshell都是用eval来执行具体操作的
assert 也是把字符串作为PHP代码执行
preg_replace 是正则表达式函数
create_function 创建匿名函数并执行传入的命令
包含函数
文件包含函数主要作用为包含并运行指定文件,include/require/include_once/require_once $file,如果$file可控的情况下,我们就可以包含任意文件了,从而达到getshell的目的,包含函数也能够读取任意文件内容,这就需要用到支持的协议和封装协议和过滤器
命令执行函数
exec() 执行一个外部程序
system() 执行外部程序,并且显示输出
只要命令就能执行的参数可控系统命令
文件操作函数
copy:拷贝文件
file_get_contents:将整个文件读入一个字符串
file_put_contents:将一个字符串写入文件
unlink:删除文件
rmdir:删除目录
反序列化函数
unserialize 反序列化一个序列化的对象