threst's Blog

php安全

2018/10/04 Share

0x01 PHP敏感配置项

register_globals(php版本小于5.4时存在)

当该配置项为ON时,会把用户通过GET、POST提交的参数自动注册成全局变量。当代码中存在有未初始化的变量时,可能会导致变量覆盖的问题;

(PS:其中参数覆盖的顺序受到配置文件中variables_order的参数影响,默认是EGPCS。按顺序,右边的参数来源会覆盖左边的的参数来源)

allow_url_include(php版本大于5.2默认为off)

当该配置项为ON时,可以通过include、require等函数进行远程文件包含

其中有个类似的配置项是allow_url_fopen,这个参数配置为on的时候可以函数中例如file_get_contents中打开url。

当两个配置项都为ON的时候,可以直接使用url进行远程包含,当include为ON,fopen为OFF时,只能通过php伪协议进行包含

magic_quato_gpc(php版本小于5.4存在)

此配置项为ON的时候会对GET、POST、COOKIE变量中的单引号(‘)、双引号(“)、反斜杠()、空字符(NULL)前添加反斜杠进行转义,注意:这个配置并不会对SERVER变量里的特殊字符进行转义,因此可能会导致referer、client-ip存在注入等漏洞

magic_quato_runtime(php版本小于5.4存在)

这个配置和magic_quato_gpc的区别就在于runtime是对从数据库或者文件中取出的数据进行转义,因此只对例如file()、fgets()、fread()、mysql_fetch_array()等很多对数据库查询和文件读取的函数产生影响

magic_quato_sybase(php版本小于5.4存在)

这个配置和magic_quato_gpc 的区别在于,sybase只会转义空字符,把单引号转为双引号,并且这个配置如果为ON会覆盖gpc的配置

open_basedir

这个配置用来设置限定php程序只能访问哪些目录。在windows下,多个目录用分号(;)分割,linux下用冒号(:)进行分割。注意的是配置的目录需要用斜杠(/)进行封尾,否则就变成了前缀匹配。例如,配置/var/test,那么/var/test和/var/test123都是可以进行访问的,如果指定一个确定的目录就要写成/var/test/

0x02 PHP常见敏感函数

注入: select from,mysql_connect,mysql_query,mysql_fetch_*,update,insert,delete
宽字节注入: set names gbk、character_set_client=gbk mysql_set_charset('gbk'),iconv
二次编码注入: urldecode,rawurldecode
文件包含 : include,include_once 、require、require_once
文件上传 : move_upload_file
任意文件删除 : unlink、session_destory
代码注入 : eval assert,preg_replace(/e),call_user_func,call_user_func_array,array_map等
命令执行: system、exec、shell_exec、passthru 、pctnl_exec、popen、proc_exec、
变量覆盖: extract、parse_str、$$
反序列化: unserialize
随机数: rand、mt_rand

0x03 常见漏洞解析

各种问题可以导致系统重装

一般程序都是通过判断install文件下有没有安装过程中生成的以lock为后缀的文件或者config配置文件来判断有没有安装。

1.未对系统是否已经安装进行判断

例如PHPSHE B2C商城1.6(wooyun 2014-062047)
可以看到代码未对是否安装进行任何判断,直接进入安装流程

2.变量覆盖绕过

例如frcms (wooyun 2014-073244)
其中主要的漏洞代码是

foreach(Array('_GET','_POST','_COOKIE') as $_request){
    foreach($$_request as $_k => $_v) ${$_k} = _runmagicquotes($_v);
}

他会把你从GET、POST、COOKIE中的变量注册为全局变量,因此我们直接通过GET参数提交$insLockfile变量即可绕过

3.判断已安装后未exit()退出程序

例如startbbs (wooyun-2013-045143)

class Install extends Install_Controller
{
function __construct ()
{
    parent::__construct();
    $this->load->library('myclass');
    $file=FCPATH.'install.lock';
    if (file_exists($file)){
        $this->myclass->notice('alert("系统已安装过");window.location.href="'.site_url().'";');
    }
}

可以看到其中判断install.lock文件存在后直接使用js代码将用户进行重定向,但是并没有die程序,直接从前端删除返回的js代码即可重装

4.还可以借助任意文件删除的漏洞来删除lock文件,然后进行重装(PS:这个就留在任意文件删除再分析)

例如: 用thinkphp 改造的hdcms (wooyun-2015-092061)
我们先跟着框架走一遍,首先查看入口文件index.php

首先定义了一些基本的框架目录,然后就直接开始引入框架文件,我们进入框架初始化文件hdphp.php

前面还是检测一次是否成功初始化常量,然后检测是否进行过编译,否则就载入文件进行首次编译,然后进行boot的run方法,查看该方法内容。

前面依然是定义了各种常量,我们可以直接跳过,来到最后的应用初始化,查看该方法

可以看到module_path常量是通过将get形式提交的var_group参数进行拼接的,然后又将module_path拼接入module_config_path,最后使用require进行了文件包含。(PS:因为这里后面制定了config.php,所以需要用到%00进行截断)

但是我们分析到目前为止只能说是疑似存在文件包含漏洞,我们还要看GET参数接收时有没有进行过滤,于是我们进入之前的解析路由方法route::parseurl(),代码较长我就不贴图了,里面就是将url中的参数进行截取解析,没有进行任何的过滤和检测,因此可以确定此处存在文件包含漏洞。因此我们接下来需要确定输入点,可以发现变量是通过thinkphp中获取参数的C方法进行获取的,而C方法获取的变量在config.php中,于是我们查看文件中可以看到var_group对应的变量是g

因此我们可以先上传一个文件然后index.php?g=../test.php%00

之前的文件包含漏洞我们是通过index.php这个入口文件一步步搞懂cms框架然后进行审计。除了这种方法,我们还可以直接定位数据库查询语句或者功能附近,看看传入的数据有没有被进行清洗。

注入漏洞这里我们就用两个有意思的骚操作来分析一下

1.Ecshop 支付宝插件全局转义绕过导致sql注入

其实在ECshop中的init.php中对用户输入的参数进行了全局转义

但是我们来到来到案发现场看看,巧妙的运用str_replace的替换功能来帮助单引号进行逃逸

其中的核心漏洞代码是$order_sn = str_replace($_GET[‘subject’], ‘’, $_GET[‘out_trade_no’]);其中代码对用户提交的out_trade_no参数中将subject替换为空,然后送入check_money函数中的sql查询语句.
这个漏洞的关键在于str_replace函数中的替换内容和源字符串都是可控的。
理解这个漏洞之前我们再来回顾一下php中addslashes中的转义处理机制[-->\,”–>\”,”–>\”,null–>\0]
于是我们可以提交out_trade_no参数为%00’后面再跟上我们的payload,提交的subject参数为0,我们来看一下数据转换过程.
out_trade_no=%00’ ————>经过全局gpc转义————> out_trade_no=\0\’————>送入str_replace函数处理,将0替换————>out_trade_no=\‘ 也就是等于了’,最终也就成功在sql语句中引入了一个单引号,从而可以进行注入

2.格式化字符串导致的单引号逃逸

再来分析一下前段时间出来的wordpress格式化字符导致的注入

具体的代码分析在这就不贴图了,我们直接来分析一下格式化字符串漏洞的核心原理,其中一个关键点就是sprintf的padding特性

printf()和sprintf()函数中可以通过使用%接一个字符来进行padding功能

例如%10s 字符串会默认在左侧填充空格至长度为10,还可以 %010s 会使用字符0进行填充,但是如果我们想要使用别的字符进行填充,需要使用 ‘ 单引号进行标识,例如 %’#10s 这个就是使用#进行填充(百分号不仅会吃掉’单引号,还会吃掉 斜杠)

同时sprintf()可以使用指定参数位置的写法

%后面的数字代表第几个参数,$后代表格式化类型

于是当我们输入的特殊字符被放到引号中进行转义时,但是又使用了sprintf函数进行拼接时,例如%1$’%s’ 中的 ‘%被当成使用%进行padding,导致后一个’逃逸了

还有一种情况就是’被转义成了’,例如输入%’ and 1=1#进入,存在SQL过滤,’被转成了\’
于是sql语句变成了select * from user where username = ‘%\’ and 1=1#’;
如果这个语句被使用sprintf函数进行了拼接,%后的被吃掉了,导致了’逃逸

<?php
$sql = "select * from user where username = '%\' and 1=1#';";
$args = "admin";
echo sprintf( $sql, $args ) ;
//result: select * from user where username = '' and 1=1#'
?>

不过这样容易遇到 PHP Warning: sprintf(): Too few arguments的报错
这个时候我们可以使用%1$来吃掉转移添加的\

<?php
$sql = "select * from user where username = '%1$\' and 1=1#' and password='%s';";
$args = "admin";
echo sprintf( $sql, $args) ;
//result: select * from user where username = '' and 1=1#' and password='admin';
?>

0x03 php安全

strcmp 弱类型比较特性

strcmp是C与PHP中常用的一个函数,用来比较两个字符串是否相等。如果二者相等,则返回数字0,否则返回其他数字。 strcmp函数当我们传入一个数组和一个字符串时,将会触发一个警告,函数返回FALSE。由于PHP弱类型的特性,FASLE == 0,会让系统误认为返回的值是0,最后绕过strcmp函数的判断。

Linux PHP 写入与删除文件差异特性

有时候目标网站存在任意文件上传漏洞,但操作执行完成后即刻删除,导致我们的webshell无法保留在服务器上。这种情况多存在于一些有缓存文件、临时文件的逻辑中,在实战里经常遇到。 Linux下,php的文件写入与移动删除等操作中,由于对于路径的处理存在差异,在有上述情况存在时,我们可以通过传入文件名为shell.php/.的文件,绕过删除函数。

preg_replace 利用 \0 截断执行代码

有些情况下,我们可控preg_replace的第一个参数(正则表达式)中的部分内容。 在PHP5.4.7以前,preg_replace的第一个参数可以利用\0进行截断,并将正则模式修改为e。众所周知,e模式的正则支持执行代码,此时将可构造一个任意代码执行漏洞。

利用php filter流绕过死亡exit

很多开发者在写入缓存、日志、配置文件的时候,通过在文件开头增加<?php exit; ?>。此时,即使用户控制文件内容,也无法执行。 我们可以利用PHP的filter流,通过php://filter/write=string.strip_tags|convert.base64-decode/resource=config.php来写入文件。 此时,PHP会先用strip_tags去除死亡exit,再将webshell用base64-decode还原,最终写入的文件中不再有死亡exit。

filter_var FILTER_VALIDATE_EMAIL 绕过

filter_var是一组PHP中过滤、检测用户输入的方法,其中开发者通常利用filter_var($email, FILTER_VALIDATE_EMAIL)来过滤用户输入的邮箱。 RFC 3696规定邮箱local part部分可以用双引号包裹,双引号内即可填入任意字符。 我们可以利用RFC 3696,传入”aaa’aaa”@example.com,即可保留单引号,并通过filter_var的检测,最终触发SQL注入漏洞。

控制Nginx虚拟主机的Host

在同一服务器上运行多个网站,Nginx会根据HTTP数据包中的Host头来区分用户访问的是哪个网站。我们如果修改Host头的值,将不能进入指定的网站。 此时,我们可以借助Nginx特性,用如下两个方法在$_SERVER[‘HTTP_HOST’]中注入恶意代码: 1. 在存在两个Host头时,Nginx取到的是第1个,PHP中取到的是第2个。我们将恶意代码放在第2个位置,将可控制$_SERVER[‘HTTP_HOST’] 2. Nginx在处理Host时,会将Host用冒号分割成hostname和port,port部分被丢弃。所以,将恶意代码放在port位置,即可部分控制$_SERVER[‘HTTP_HOST’]

利用GBK编码吃反引号

在开启GPC或模拟全局GPC的CMS中,我们传入的单引号(’)和转义符(\)等将被用一个转义符(\)进行转义,导致我们无法闭合单引号进行注入。 在GBK编码的程序中,部分开发者会用iconv将字符串转换编码后存入数据库。在这种情况下,我们可以利用GBK编码中的0xE55C,转义正常的反斜线,绕过全局GPC进行注入。

iconv()绕过上传白名单

在上传文件的过程中,如果目标使用的字符编码和访客操作系统使用的字符编码不同,可能导致上传后的文件名出现乱码。所以,开发者在获取文件名后,通常调用iconv()对其进行编码转换。 如果转换编码的操作在验证文件名后缀操作之后,那么我们可以利用iconv()特性,截断文件名,进而去除白名单中的后缀,造成文件上传漏洞。

PHP mt_rand() 随机数预测

mt_rand()生成随机数有如下特点: 1. PHP > 4.2.0中,系统会自动设置随机数种子,相同种子生成的随机数相同 2. 同一进程中,如果多次调用mt_rand()函数,只会自动播种一次 所以,如果同一次我们生成了数个随机数,在知道其中一部分的情况下,即可反推随机数种子。 32位系统中,种子最大值为2^16-1,64位系统中,种子最大值为2^31-1。我们爆破到该种子,即可预测其他未知的随机数。
https://mp.weixin.qq.com/s/3TgBKXHw3MC61qIYELanJg

PHP5 rand() 随机数预测

PHP5 rand()函数使用了glibc库中的rand()函数,glibc中维护了一个随机数链,其上下文中存在如下关系: state[i] = state[i-3] + state[i-31] return state[i] >> 1 进而导致PHP5中的rand()函数生成的随机数也存在上述关系。如果开发者使用rand()函数生成密钥、salt等安全相关元素,将导致被预测。

利用json_encode吃转义符

在开启GPC或模拟全局GPC的CMS中,我们传入的单引号(’)和转义符(\)等将被用一个转义符(\)进行转义,导致我们无法闭合单引号进行注入。 部分开发者会将一些结构复杂内容(如数组)用json_encode编码成一个字符串后存入数据库,在这种情况下,我们可以绕过全局GPC进行注入

file_put_contents写入文件绕过内容黑名单

在开发者使用file_put_contents写入文件的时候,有的情况下会用字符串匹配的方式拦截如“<”、”>”、”?”等字符,导致我们无法写入webshell。 file_put_contents函数第二个参数支持传入数组,用户传入的数组将被拼接成一个字符串写入文件。数组因为类型不同导致无法使用字符串匹配来检测,进而利用这种方式绕过了黑名单。

PHP MD5 比较的陷阱

PHP是一门弱类型语言,在使用“==”进行变量比较的时候,会先进行类型转换,再进行比较操作。即使比较的是两个字符串,如果二者满足“科学计数法”的表达方法,也会先转换成数字再进行比较。 比如: var_dump(“0e1234” == “0e5678”); 其返回结果是true。 在比较md5时,如果目标密码的md5值恰好是“0e”+数字,将可以出现密码绕过漏洞。

PHP 5.6.11 数组比较Bug

PHP 5.6.11/5.5.27/5.4.44以前的版本中,存在一处数组比较的Bug(Bug #69892),我们可以通过 var_dump([0 => 0] === [0x100000000 => 0]); 来复现该特性。

0x04 代码审计关注点)

file_put_contents、copy、file_get_contents等读取写入操作与unlink、file_exists等删除判断文件函数之间对于路径处理的差异导致的删除绕过

<?php
$filename = __DIR__ . '/tmp/' . $user['name'];
$data = $user['info'];
file_put_contents($filename, $data);
if (file_exists($filename)) {
    unlink($filename);
}
?>

查看php源码,其实我们能发现,php读取、写入文件,都会调用php_stream_open_wrapper_ex来打开流,而判断文件存在、重命名、删除文件等操作则无需打开文件流。
我们跟一跟php_stream_open_wrapper_ex就会发现,其实最后会使用tsrm_realpath函数来将filename给标准化成一个绝对路径。而文件删除等操作则不会,这就是二者的区别。
所以,如果我们传入的是文件名中包含一个不存在的路径,写入的时候因为会处理掉“../”等相对路径,所以不会出错;判断、删除的时候因为不会处理,所以就会出现“No such file or directory”的错误。

于是乎linux可以通过xxxxx/../test.php、test.php/. windows可以通过test.php:test test.ph<来绕过文件删除,此外发现还可以使用伪协议php://filter/resource=1.php在file_ge_contents、copy等中读取文件内容,却可以绕过文件删除

extract()、parse_str() 等变量覆盖

extract函数从数组导入变量(如\$_GET、 \$_POST),将数组的键名作为变量的值。而parse_str函数则是从类似name=Bill&age=60的格式字符串解析变量.如果在使用第一个函数没有设置EXTR_SKIP或者EXTR_PREFIX_SAME等处理变量冲突的参数时、第二个函数没有使用数组接受变量时将会导致变量覆盖的问题

intval()整数溢出、向下取整和整形判断的问题

32位系统最大的带符号范围为-2147483648 到 2147483647,64位最大的是 9223372036854775807

​ 因此,在32位系统上 intval(‘1000000000000’) 会返回 2147483647

此外intval(10.99999)会返回10,intval和int等取整都是’截断’取整,并不是四舍五入
intval函数进去取整时,是直到遇上数字或者正负号才开始进行转换,之后在遇到非数字或者结束符号(\0)时结束转换

浮点数精度问题导致的大小比较问题

当小数小于10^-16后,PHP对于小数就大小不分了
var_dump(1.000000000000000 == 1) >> TRUE
var_dump(1.0000000000000001 == 1) >> TRUE

is_numeric()与intval()特性差异

is_numeric函数在判断是否是数字时会忽略字符串开头的’ ‘、’\t’、’\n’、’\r’、’\v’、’\f’。

​ 而’.’可以出现在任意位置,E、e能出现在参数中间,仍可以被判断为数字。也就是说is_numeric(“\r\n\t 0.1e2”) >> TRUE

intval()函数会忽略’’ ‘\n’、’\r’、’\t’、’\v’、’\0’ ,也就是说intval(“\r\n\t 12”) >> 12

strcmp()数组比较绕过

int strcmp ( string $ str1 , string \$str2 )

参数 str1第一个字符串。str2第二个字符串。如果 str1 小于 str2 返回 < 0;

如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0。

但是如果传入的两个变量是数组的话,函数会报错返回NULL,如果只是用strcmp()==0来判断的话就可以绕过

sha1()、md5() 函数传入数组比较绕过

sha1() MD5()函数默认接收的参数是字符串类型,但是如果如果传入的参数是数组的话,函数就会报错返回NULL。类似sha1(\$_GET[‘name’]) === sha1(\$_GET[‘password’])的比较就可以绕过

弱类型==比较绕过

这方面问题普及的很多,不作过多的解释

md5(‘240610708’); // 0e462097431906509019562988736854
md5(‘QNKCDZO’); // 0e830400451993494058024219903391
md5(‘240610708’) == md5(‘QNKCDZO’)
md5(‘aabg7XSs’) == md5(‘aabC9RqS’)
sha1(‘aaroZmOk’) == sha1(‘aaK1STfY’)
sha1(‘aaO8zKZF’) == sha1(‘aa3OFF9m’)
‘0010e2’ == ‘1e3’
‘0x1234Ab’ == ‘1193131‘
‘0xABCdef’ == ‘ 0xABCdef’
当转换为boolean时,以下只被认为是FALSE:FALSE、0、0.0、“”、“0”、array()、NULL
PHP 7 以前的版本里,如果向八进制数传递了一个非法数字(即 8 或 9),则后面其余数字会被忽略。var_dump(0123)=var_dump(01239)=83
PHP 7 以后,会产生 Parse Error。
字符串转换为数值时,若字符串开头有数字,则转为数字并省略后面的非数字字符。若一开头没有数字则转换为0
\$foo = 1 + “bob-1.3e3”; // $foo is integer (1)
\$foo = 1 + “bob3”; // $foo is integer (1)
\$foo = 1 + “10 Small Pigs”; // $foo is integer (11)
‘’ == 0 == false
‘123’ == 123
‘abc’ == 0
‘123a’ == 123
‘0x01’ == 1
‘0e123456789’ == ‘0e987654321’
[false] == [0] == [NULL] == [‘’]
NULL == false == 0» true == 1

eregi()匹配绕过

eregi()默认接收字符串参数,如果传入数组,函数会报错并返回NULL。同时还可以%00 截断进行绕过

PHP变量名不能带有点[.] 和空格,否则在会被转化为下划线[_]

parse_str("na.me=admin&pass wd=123",$test);
var_dump($test); 
array(2) {
  ["na_me"]=>
  string(5) "admin"
  ["pass_wd"]=>
  string(3) "123"
}

PS:通过$_SERVER[‘REQUEST_URI’]方式获得的参数不会进行转换

\$_REQUEST是直接从GET,POST 和 COOKIE中取值,不是他们的引用。即使后续GET,POST 和 COOKIE发生了变化,也不会影响$_REQUEST的结果

php在遇到相同参数时接受的是第二个参数
in_arrary()函数默认进行松散比较(进行类型转换)

in_arrary(“1asd”,arrart(1,2,3,4))    => true
in_arrary(“1asd”,arrart(1,2,3,4),TRUE)    => false   \\(需要设置strict参数为true才会进行严格比较,进行类型检测)

htmlspecialchars()函数默认只转义双引号不转义单引号,如果都转义的话需要添加上参数ENT_QUOTES
在php4、php<5.2.1中,变量的key值不受magic_quotes_gpc影响
sprintf()格式化漏洞(可以吃掉转义后的单引号)
printf()和sprintf()函数中可以通过使用%接一个字符来进行padding功能
例如%10s 字符串会默认在左侧填充空格至长度为10,还可以 %010s 会使用字符0进行填充,但是如果我们想要使用别的字符进行填充,需要使用 ‘ 单引号进行标识,例如 %’#10s 这个就是使用#进行填充(百分号不仅会吃掉’单引号,还会吃掉\ 斜杠)
同时sprintf()可以使用指定参数位置的写法

<?php
$format  = 'This %2$s contains %1$04d monkeys';
echo sprintf($format,$num,$location);
?>
以上实例会输出:
The tree contains 0005 monkeys

%后面的数字代表第几个参数,$后代表格式化类型
于是当我们输入的特殊字符被放到引号中进行转义时,但是又使用了sprintf函数进行拼接时
例如%1$’%s’ 中的 ‘%被当成使用%进行padding,导致后一个’逃逸了
还有一种情况就是’被转义成了\’,例如输入%’ and 1=1#进入,存在SQL过滤,’被转成了\’
于是sql语句变成了 select * from user where username = ‘%\’ and 1=1#’;
如果这个语句被使用sprintf函数进行了拼接,%后的\被吃掉了,导致了’逃逸

<?php
$sql = "select * from user where username = '%\' and 1=1#';";
$args = "admin";
echo sprintf( $sql, $args ) ;
//result: select * from user where username = '' and 1=1#'
?>

不过这样容易遇到 PHP Warning: sprintf(): Too few arguments的报错
这个时候我们可以使用%1$来吃掉转移添加的\

<?php
$sql = "select * from user where username = '%1$\' and 1=1#' and password='%s';";
$args = "admin";
echo sprintf( $sql, $args) ;
//result: select * from user where username = '' and 1=1#' and password='admin';
?>

php中 = 赋值运算的优先级高于and

$c = is_numeric($a) and is_numeric($b) 程序本意是要a、b都为数字才会继续,但是当\$a为数字时,会先赋值给\$c,所以可能导致$b绕过检测

parse_url与libcurl对与url的解析差异可能导致ssrf

当url中有多个@符号时,parse_url中获取的host是最后一个@符号后面的host,而libcurl则是获取的第一个@符号之后的。因此当代码对http://user@eval.com:80@baidu.com 进行解析时,PHP获取的host是baidu.com是允许访问的域名,而最后调用libcurl进行请求时则是请求的eval.com域名,可以造成ssrf绕过
此外对于https://evil@baidu.com这样的域名进行解析时,php获取的host是`evil@baidu.com`,但是libcurl获取的host却是evil.com

url标准的灵活性导致绕过filter_var与parse_url进行ssrf

filter_var()函数对于http://evil.com;google.com 会返回false也就是认为url格式错误,但是对于0://evil.com:80;google.com:80/ 、0://evil.com:80,google.com:80/、0://evil.com:80\google.com:80/却返回true。

通过file_get_contents获取网页内容并返回到客户端有可能造成xss

例如如下代码

if(filter_var($argv[1], FILTER_VALIDATE_URL)) {
   // parse URL
   $r = parse_url($argv[1]);
   print_r($r);
   // check if host ends with google.com
   if(preg_match('/baidu\.com$/', $r['host'])) {
      // get page from URL
      $a = file_get_contents($argv[1]);
      echo($a);
   } else {
      echo "Error: Host not allowed";
   }
} else {
   echo "Error: Invalid URL";
}

虽然通过filter_var函数对url的格式进行检查,并且使用正则对url的host进行限定
但是可以通过data://baidu.com/plain;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pgo=页面会将<script>alert(1)</script>返回给客户端,就有可能造成xss

序列化漏洞常见的魔法函数

construct():当一个类被创建时自动调用
destruct():当一个类被销毁时自动调用
invoke():当把一个类当作函数使用时自动调用
tostring():当把一个类当作字符串使用时自动调用
wakeup():当调用unserialize()函数时自动调用
sleep():当调用serialize()函数时自动调用
__call():当要调用的方法不存在或权限不足时自动调用

CATALOG
  1. 1. 0x01 PHP敏感配置项
    1. 1.1. register_globals(php版本小于5.4时存在)
    2. 1.2. allow_url_include(php版本大于5.2默认为off)
    3. 1.3. magic_quato_gpc(php版本小于5.4存在)
    4. 1.4. magic_quato_runtime(php版本小于5.4存在)
    5. 1.5. magic_quato_sybase(php版本小于5.4存在)
    6. 1.6. open_basedir
  2. 2. 0x02 PHP常见敏感函数
  3. 3. 0x03 常见漏洞解析
    1. 3.1. 各种问题可以导致系统重装
      1. 3.1.1. 1.未对系统是否已经安装进行判断
      2. 3.1.2. 2.变量覆盖绕过
      3. 3.1.3. 3.判断已安装后未exit()退出程序
      4. 3.1.4. 4.还可以借助任意文件删除的漏洞来删除lock文件,然后进行重装(PS:这个就留在任意文件删除再分析)
        1. 3.1.4.1. 1.Ecshop 支付宝插件全局转义绕过导致sql注入
        2. 3.1.4.2. 2.格式化字符串导致的单引号逃逸
  4. 4. 0x03 php安全
    1. 4.1. strcmp 弱类型比较特性
    2. 4.2. Linux PHP 写入与删除文件差异特性
    3. 4.3. preg_replace 利用 \0 截断执行代码
    4. 4.4. 利用php filter流绕过死亡exit
    5. 4.5. filter_var FILTER_VALIDATE_EMAIL 绕过
    6. 4.6. 控制Nginx虚拟主机的Host
    7. 4.7. 利用GBK编码吃反引号
    8. 4.8. iconv()绕过上传白名单
    9. 4.9. PHP mt_rand() 随机数预测
    10. 4.10. PHP5 rand() 随机数预测
    11. 4.11. 利用json_encode吃转义符
    12. 4.12. file_put_contents写入文件绕过内容黑名单
    13. 4.13. PHP MD5 比较的陷阱
    14. 4.14. PHP 5.6.11 数组比较Bug
  5. 5. 0x04 代码审计关注点)
    1. 5.1. file_put_contents、copy、file_get_contents等读取写入操作与unlink、file_exists等删除判断文件函数之间对于路径处理的差异导致的删除绕过
    2. 5.2. extract()、parse_str() 等变量覆盖
    3. 5.3. intval()整数溢出、向下取整和整形判断的问题
    4. 5.4. 浮点数精度问题导致的大小比较问题
    5. 5.5. is_numeric()与intval()特性差异
    6. 5.6. strcmp()数组比较绕过
    7. 5.7. sha1()、md5() 函数传入数组比较绕过
    8. 5.8. 弱类型==比较绕过
    9. 5.9. eregi()匹配绕过
    10. 5.10. PHP变量名不能带有点[.] 和空格,否则在会被转化为下划线[_]
    11. 5.11. \$_REQUEST是直接从GET,POST 和 COOKIE中取值,不是他们的引用。即使后续GET,POST 和 COOKIE发生了变化,也不会影响$_REQUEST的结果
    12. 5.12. php中 = 赋值运算的优先级高于and
    13. 5.13. parse_url与libcurl对与url的解析差异可能导致ssrf
    14. 5.14. url标准的灵活性导致绕过filter_var与parse_url进行ssrf
    15. 5.15. 通过file_get_contents获取网页内容并返回到客户端有可能造成xss
    16. 5.16. 序列化漏洞常见的魔法函数