最近在学PHP代码审计,那就将学习的笔记都整理一遍吧~
当然,最基本的前提是至少大致学过PHP的语法。
1、安装相关软件,如Sublime text、 Notepad++、editplus、 Seay源代码审计系统等
2、获得源码,可以到网上下载各种网站源码
3、安装网站
通读全文法:麻烦但全面
敏感函数参数回溯法:高效常用,Seay源代码审计系统
定向功能分析法:主要根据程序的业务逻辑来审计,首先是用浏览器逐个访问,看看程序有哪些功能,根据相关功能推测可能存在的漏洞
1、整体了解
2、根据定向功能法针对每一项功能进行审计
3、敏感函数参数回溯法
浏览源码文件夹,了解程序的大致目录。
admin:后台管理目录
install:网站的安装目录,其中的install.sql为数据库的结构信息
sys:这个目录里面一般存放着配置信息文件和公共函数库,分别为config.php和lib.php
user:这里面记录着用户的一些操作,如用户注册等
index.php:一般为网页的首页文件,也是审计的突破口
index.php、admin.php文件一般都是整个程序的入口,通过index文件可以知道程序的架构、运行流程、包含哪些配置文件、哪些过滤文件以及安全过滤文件,了解程序的业务逻辑。
一般类似config.php等文件,保存一些数据库相关信息、程序的一些信息。先看看数据库编码,若是gbk则可能存在宽字节注入;若变量的值用双引号,则可能存在双引号解析代码执行的问题。
通过公共函数文件、安全过滤文件可看出用户输入的数据哪些被过滤和哪些无过滤,在哪、如何过滤,能否绕过过滤的数据,过滤的方式是替换还是正则,有无GPC和使用addslasher()处理等。
程序初始安装漏洞
站点信息泄露
文件上传管理
登录认证、权限管理漏洞
数据库备份漏洞
验证码漏洞等
1、可控的变量(一切输入都是有害的)
2、变量到达有利用价值的函数(危险的函数)
代码审计的本质:找漏洞其实相当于找对应变量和函数。
变量跟踪的过程:
正向跟踪——通过变量找函数
逆向跟踪——通过函数找变量
PHP 的配置文件一般是 php.ini 文件
php.ini 文件必须命名为'php.ini'并放置在httpd.conf中的PHPIniDir指令指定的目录中,使用phpinfo()函数可以查看。
一般情况下需要对其进行配置,使环境更加安全
php.ini:在启动PHP时被读取。对于服务器模块版本的PHP,仅在Web服务器启动时读取一次;对于CGI和CLI版本,每次调用都会读取。在php.ini中可以使用环境变量。Apache Web服务器在启动时,会把目录转到根目录,这将导致PHP尝试在根目录下读取php.ini,若存在的话。还可以在httpd.conf中覆盖php.ini的值以进行更灵活的配置:php_value name value。PHP常量仅能在php.ini中使用,在httpd.conf中必须使用相应的掩码值。
.user.ini文件:自PHP5.3.0起,PHP支持基于每个目录的.htaccess风格的INI文件,此类文件仅被CGI/FastCGI SAPI处理;此功能使得PECL的htscanner扩展作废;若使用Apache,则用.htaccess文件有同样的效果。在.user.ini风格的INI文件中只有具有PHP_INI_PERDIR和PHP_INI_USER模式的INI设置可被识别。当使用PHP作为Apache模块时,也可以用Apache的配置文件和.htaccess文件中的指令来修改PHP的配置设定;需要有“AllowOverride Options”或“AllowOverride All”权限。
语法:设置指令的格式:directive = value 大小写敏感
Value可以使:用引号界定的字符串("foo”)、数组、PHP常量(E_ALL、M_PI)、INI常量(On、Off、none)、表达式
INI文件中表达式仅使用:!、()、|位或、&位与、~位非、
一个空字符串可以用在等号后不写任何东西表示,或者用 none 关键字:
foo = ; 将foo设为空字符串
foo = none ; 将foo设为空字符串
foo = "none" ; 将foo设为字符串''none''
启用全局变量:register_globals=off
作用是关闭自动注册的全局变量。
设置为On,php会将$_POST,$_GET,$_COOKIE,$_ENV,$_SESSION数组中的$key=>$value直接注册为变量,但有三个问题:不知道变量来源;变量之间相互覆盖;安全问题。因而要设置为Off。
短标签:short_open_tag=off
作用是决定是否允许使用PHP代码开始标志的缩写形式(?>)。若禁用,就必须使用PHP代码开始标志的完整形式()。安全模式:safe_mode=off
控制一些PHP函数如system(),同时对文件操作函数进行权限限制,但默认php.ini没有打开安全模式。自PHP5.4.0起废除。
安全模式下执行程序主目录:safe_mode_exec_dir=/var/www/html
使用安全模式后,system()和其他程序执行函数将值可以在此目录下执行程序。
禁用类/函数:disable_classes= ,disable_functions=opendir,readdir,scandir,fopen
接受逗号分隔的函数名。
设置上传及最大上传文件大小:file_uploads=on upload_max_filesize=8M
文件上传临时目录:upload_tmp_dir =
(系统临时目录/tmp、C:\Windows\Temp)
用户访问目录限制:open_basedir = .:/tmp/
一般可以设置只能访问网站目录,表示允许访问当前目录和/tmp/目录。
错误信息控制:display_error=On
调试时On;站点发布后应关闭,以免暴露信息。
设置错误报告级别:error_reporting=E_ALL
作用是将错误级别设置为最高,可以显示所有的问题,方便查错。
日志级别是常量,在php.ini中有,推荐使用E_ALL|E_STRICT
错误日志:
error_log= 错误日志的位置,若不定义则默认写入Web服务器的错误日志中去。
log_errors = on 建议将错误日志输出到文件而不是直接输出到前端。
log_errors_max_length = 1024 错误日志关联信息的最大长度,设为0为无限长度。
魔术引号:自PHP 5.3.0起弃用
magic_quotes_gpc=On
magic_quotes_runtime=Off
功能是自动转义,和 addslashes() 作用完全相同
是否允许打开远程文件:allow_url_fopen=on
使得可以访问URL对象例如文件
是否允许包含远程文件:allow_url_include=off
允许include、include_once、require、require_once等函数使用URL形式的fopen封装协议。
eval(),将字符串作为PHP代码执行
assert(),检测一个断言是否为FALSE;因为eval列入了黑名单,所以用assert替代其
preg_replace(),作用是执行正则表达式,这个函数的原型为:mixed preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit]),如果在构造正则表达式的时候,使用了/e修正符,这时,preg_replace() 就会将 replacement 参数当作 PHP代码执行。
第一种模式:
phpinfo()';
preg_replace("/(.*?)$re", '\\1', $var);
?>
第二种模式:
第三种模式:
create_function(),创建一个匿名函数
call_user_func()、call_user_func_array(),回调函数
require()、include()、require_once()、include _once()
分本地文件包含和远程文件包含,可以读取任意文件内容。
exec():执行一个外部程序
";
echo exec($cmd);
echo "
";
?>
passthru():执行外部程序并且显示原始输出
";
passthru($cmd);
echo "
";
?>
proc_open():执行一个命令,并且打开用来输入的文件指针
shell_exec():通过shell环境执行命令,并且将完整的输出以字符串方式返回
";
echo shell_exec($cmd);
echo "
";
?>
system():执行外部程序,并且显示输出
";
system($cmd);
echo "
";
?>
popen():popen()的参数传递一条命令,并对并对 popen() 所打开的文件进行执行。
";
echo popen($cmd,'r');
echo "
";
?>
";
echo `$cmd`;
echo "
";
?>
copy():拷贝文件
file_get_contents():将整个文件读入为一个字符串
file_put_contents():将一个字符串写入文件
file():把整个文件读入一个数组中
fopen():打开文件或者 URL
move_uploaded_file():将上传的文件移动到新位置
readfile():输出文件
rename():重命名一个文件或目录
rmdir():删除目录
unlink() & delete():删除文件
信息泄露:phpinfo()
软连接,读取文件内容:symlink()、readlink()
环境变量:getenv()、putenv()
加载扩展:dl(),载入指定参数library的PHP扩展
配置相关:ini_get()、ini_set()、ini_alter()、ini_restore()
数字判断:is_numeric(),仅用该函数判断而不用intval()转换可能会导致SQL二次注入,因为可能会插入16进制的字符串。
数组相关:in_array(),检查数组中是否存在某个值
变量覆盖:parse_str(),将字符串解析为变量并设置到当前作用域,另外还有extract()、mb_parse_str()、import_request_variables()
列目录:glob(),使用规则筛选所有与pattern匹配的文件路径
无参数获取信息:get_defined_vars()返回一个包含所有已定义变量列表的多维数组、get_defined_constants()返回当前所有已定义的常量名和值、get_defined_functions()返回一个包含所有已定义函数列表的多维数组、get_included_files()返回所有被包含的文件名
echo()、print():两者输出一样,前者为PHP语句,后者为函数
print_r():输出数组
var_dump():会额外输出数据类型
debug_zval_dump():跟上一个类似,区别是增加了refcount记录变量被引用的次数
exit():退出当前程序执行
单行注释://
多行注释:/**/
双引号解析变量、而单引号不解析变量
$str = "hello";
echo "$str";//双引号解析变量
echo '$str';//单引号不解析
在 php 中可由用户操作的全局变量列表如下:
$GLOBALS:引用全局作用域中可用的全部变量
echo $test="test2";
echo $GLOBALS['test'];
}
$test = "test1";
test();
?>
$_GET:HTTP GET 变量
$_POST:HTTP POST 变量
$_FILES:HTTP 文件上传变量
表单:
GET:
POST:
$_SESSION:Session 变量
这里输出为空数组:
接着修改php.ini文件,添加E:
$_COOKIE:HTTP Cookies