PHP代码审计简单学习

这是关于php代码审计的简单学习笔记,转移自有道笔记(MyDo->A学习->PHP->代码审计)

审计准备

  1. 获得源码:开源程序等等
  2. 本地搭建软件:本地搭建审计调试,跟踪动态变化

大致信息

  1. 网站结构
  2. 入口文件:index.php…可以知道程序架构,运行流程,包含得配置文件,包含的过滤文件,业务逻辑
  3. 配置文件:config.php等,保存数据库,程序相关得信息.数据库编码(如果是gbk可能存在款字节注入),变量用双引号则可能存在双引号解析代码执行.
  4. 过滤功能:公共函数文件 安全过滤文件 掌握用户得输入哪些被过滤若何过滤,能否绕过过滤.

审计方法

通读全文:全文阅读
敏感函数参数回溯:逆向追踪参数传递过程.
定向功能分析

常见ini配置

  • php.ini
  • .user.ini 类似apache 得.htaccess

关闭全局变量

register_globals=off
设置为on得时候会将$_POST $_GET $_COOKIE等中得$key=>$value直接注册为变量.引起大量安全问题.

短标签

short_open_tag=off
决定是否运行使用php代码开始标志得缩写形式(<??>).可以用于一句话变形

安全模式

safe_mode=off禁用很多危险函数,默认关闭,自php5.3.0废弃.

安全模式下执行程序主目录

禁用类/函数

disable_classes disable_function 接受都好分割得函数名列表作为参数.只能设置再php.ini中

设置上传以及文件大小

file_uploads upload_max_filesize

上传文件临时目录

upload_tmp_dir
临时目录需要写入权限,如果不设置则使用系统得临时目录(/tmp,c:\windows\temp)

用户访问目录限制

open_basedir=.:/tmp/(linux用冒号分割,windows用分号分隔)
一半设置为只能访问当前就目录(php脚本文件所在目录)和/tmp/目录,有效防止木马跨站运行.

错误信息控制

display_error
是否将错误信息作为输出得一部分,生产模式必须关闭,调试模式需要打开.

设置错误报告级别

error_reporting=E_ALL
这个参数,级别设置为最高,显示所有问题,方便查错.

错误日志

error_log
错误日志得位置,必须对web用户可写,默认写入到web服务器得错误日志中.

log_errors_max_length
日志关联信息最大长度,0代表武线长度

魔术引号

效率降低,5.3.0废弃
magic_quotes_gpc=on所有的单双引号,反斜杠,null被一个反斜杠自动转译
magic_quotes_runtime=off php的大部分函数自动的给从外部引入的(包括数据库或者文件)数据中的溢出字符加上反斜线

是否允许打开远程文件

allow_url_fopen
是否激活url形式得fopen封装协议使得可以访问url对象文件,默认的封装协议提供ftp和http协议访问.默认打开

是否允许包含远程文件

allow_url_include
是否允许include,include_once,require,require_once等函数使url形式得fopen封装协议.包含远程文件.默认关闭

常见危险函数和特殊函数

代码执行函数

eval/assert

mixed eval(string $code)
把字符串作为php代码执行
例如

1
<?php @evla($_POST['haha']);?>

bool assert(mixed $assertion [,string $description])
检查断言是否为false(把字符串$assertion作为php代码执行)
大多数杀软把eval列入黑名单,用assert替代.

preg_replace

执行正则表达式执行搜索和替换
mixed preg replace(mixed $pattern,mixed $replacement,mixed $subject[,int $limit=-1[int&$count]])
/e 修正符使preg_replace()将 replacement参数当作PHP代码
preg_replace(”/test/e”,$_GET[“h”],”jutst test”);如果我们提交?h=phpinfo),phpinfo0将会被执行

create_function

创建一个匿名函数,返回第一无二得函数名

string create_function(string $args,string $code)
创建一个匿名函数,并返回独一无二的函数名。
$newfunc=create_function($v’,’return system($v););
$newfunc(whoamif);就相当于system(whoami1);

回调函数

mixed call_user_func(callable $callback [,mixed $parameter L,mixed $..])
第一个参数callback是被调用的回调函数,其余参数是回调函数的参数。
mixed call_user_func array(callable $callback,array $param_arr)
把第一个参数作为回调函数(callback)调用,把参数数组作(param_arr)为回调函数的的参数传入。

包含函数

require,include,require_once,include_once

命令执行函数

  • exec() 执行一个外部命令
  • passthru() 执行外部程序并且显示原始输出
  • shell_exec() 通过shell环境执行命令并且将完整得输出以字符串方式返回.
  • system() 执行外部程序并显示输出
  • popen() 通过参数传递一条命令,并对popen()所打开得文件进行执行.

执行函数包括但不限于上述几个。
同样的道理、只要命令的参数可控就能够执行系统命令。

例如:
system(Scmd);或者system(ping-c3’.Starget);当Scmd可以空就能执行任意命令,而当Starget可控的话,可以用管道符等特殊字符截断从而执行任意命令。
Starget=’a l whoamit;

文件操作函数

  • copy-拷贝文件
  • file_get_contents-将整个文件读入一个字符串file_put_contents-将一个字符串写入文件file-把整个文件读入一个数组中
  • fopen-打开文件或者URL - move_uploaded_file-将上传的文件移动到新位置readfile-输出文件
  • rename—重命名一个文件或目录
  • rmdir-删除目录
  • unlink&delete—删除文件

任意文件读取、写入、删除往往是上面几个函数受到了控制(当然还有其他的函数)。
不同的函数在不同的场景有不同的作用和不同的利用手法。
读取:可以读取配置等文件,拿到key写入:可以写入shel代码相关的内容
删除:可以删除.lock文件而可以重新安装覆盖

特殊函数

  • 信息泄漏
    bool phpinfo([int $what=INFO_ALL])
    输出PHP当前状态的大量信息,包含了PHP编译选项、启用的扩展、PHP版本、服务器信息和环境变量(如果编译为一个模块的话)、PHP环境变量、操作系统版本信息、path 变量、配置选项的本地值和主值、HTTP头和PHP授权信息(License)。
  • 软连接-读取文件内容
    bool symlink(string $target,string $link)
    symlink)对于已有的target 建立一个名为link的符号连接。
    string readlink(string $path)
    readlink)和同名的C函数做同样的事,返回符号连接的内容。
  • 环境变量
    string getenv(string $varname)
    获取一个环境变量的值。
    bool putenv(string $setting)
    添加setting 到服务器环境变量。环境变量仅存活于当前请求期间。在请求结束时环境会恢复到初始状态。
  • 加载扩展
    bool dl(string $library)
    载入指定参数library的PHP扩展。
  • 配置相关
    string ini_get(string $varname)
    成功时返回配置选项的值。
    string ini_set(string $varname,string $newvalue)
    string ini alter(string $varname,string $newvalue)
    设置指定配置选项的值。这个选项会在脚本运行时保持新的值,并在脚本结束时恢复。
    void ini_restore(string $varname)
    恢复指定的配置选项到它的原始值。
  • 数字判断
    bool is_numeric(mixed $var)
    如果 var是数字和数字字符串则返回 TRUE,否则返回 FALSE。
    仅用is_numeric判断而不用intval转换就有可能插入16进制的字符串到数据库,进而可能导致sql二次注入。
  • 数组相关
    bool in array(mixed $needle,array $haystack L,bool $strict=FALSE])
    在haystack 中搜索 needle,如果没有设置 strict 则使用宽松的比较。
    该函数有一个特性,比较之前会进行自动类型转换。
    $a=’1abc’;in_array($a,array(1,2,3))的返回值会是真
  • 变量覆盖
    void parse_str(string $str[array&$arr])
    如果str是URL传递入的查询字符串(query string),则将它解析为变量并设置到当前作用域。
    int extract(array&$var array I,int $extract type=EXTR_OVERWRITE L,string $prefix=NULL]])
    本函数用来将变量从数组中导入到当前的符号表中。检查每个键名看是否可以作为一个合法的变量名,同时也检查和符号表中已有的变量名的冲突。
    bool mb parse str(string $encoded_string L,array&$result])
    解析GET/POST/COOKIE数据并设置全局变量。由于PHP不提供原始 POST/COOKIE数据,目前它仅能够用于GET数据。它解析了URL编码过的数据,检测其编码,并转换编码为内部编码,然后设置其值为array的result或者全局变量。
    bool import request variables(string $types L,string $prefix])
    将GET/POST/Cookie变量导入到全局作用域中。如果你禁止了register_globals,但又想用到一些全局变量,那么此函数就很有用。
  • 列目录
    array glob(string $pattern L,int $flags=0])
    glob0函数依照 libc glob0函数使用的规则寻找所有与pattern匹配的文件路径,类似于一般shells所用的规则一样。不进行缩写扩展或参数替代。
  • 无参数获取信息
    array get defined_vars(void)
    返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。
    array get defined_constants([bool $categorize=false])
    返回当前所有已定义的常量名和值。这包含define0函数所创建的,也包含了所有扩展所创建的。
    array get_defined_functions(void)
    返回一个包含所有已定义函数列表的多维数组
    array get_included_files(void)
    返回所有被include、include_once、require和require_once的文件名。

XDebug

Xdebug是一个开放源代码的PHP程序调试器(即一个Debug工具)可以用来跟踪,调试和分析PHP程序的运行状况功能强大的神器,对审计有非常大的帮助。

配置-设置选项

日志

xdebug.trace_output_dir-日志追踪输出目录xdebug.trace_output_name日志文件名,xdebug提供了一系列的标识符,生成相应格式的文件名,具体请参考官网xdebug.trace_options记录添加到文件中方式:1=追加(如果存在该文件).0(default)=覆盖(如果存在该文件)

显示数据

xdebug.collect_params非零值=控制function的参数显示选项

  • 0=不显示.
  • 1=参数类型,值(例如:array(9)).
  • 2=同上1,只是在CLI模式下略微有区别
  • 3=所有变量内容
  • 4=所有变量内容和变量名(例如:array(0=>9)).

xdebug.collect_return
1=显示function返回值.Default0不显示
xdebug.collect_vars
1=显示当前作用域使用了哪些变量,显示变量名,该选项不会记录变量的值xdebug.collect_assignments
1=添加一行显示变量赋值(若为1,形如$a=1;这类Assignment Expression会在race文件里显示)

格式

xdebug.trace_format-日志追踪输出目录

  • 0=人可读.从左至右每列分别表示:时间点,内存,内存差(需要设置xdebug.show_mem_delta=1),等级,函数名,函数参数(需要设置,xdebug.collect_params=1,只要是非零),当前代码行所在文件名,行号.
  • 1=机器可读[1].需要借助第三方app,例如:xdebug trace file parser 或者xdebug trace viewer
  • 2=html格式即table,用browser打开,显示table

行为

追踪方式有2种,一种是自动追踪,所有php脚本运行时,都会产生trace文件;另一种是触发方式追踪。
xdebug.auto_trace
1=打开自动追踪。

xdebug.trace_enable_trigger注:该特性只在2.2+版本才能设置1=使用XDEBUG_TRACE GET/POST触发追踪,或者通过设置cookie XDEBUG_TRACE.为了避免每次请求时,都会生成相应trace追踪文件,你需要把auto_trace设置为0

其他配置选项请自行研究

如果文章有问题欢迎指出,或者你也可以联系我
本文作者:E1se
本文链接: 2019/03/14/PHP代码审计简单学习/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!
-------------本文结束-------------
0%