开始涉足代码审计,将自己的一些笔记记录下来!

PHP代码执行函数

eval

Grammar: eval(phpcode)

eval() 函数把字符串按照 PHP 代码来计算。

该字符串必须是‘合法的 PHP 代码’,且必须以‘分号’结尾。

如果没有在代码字符串中调用 return 语句,则返回 NULL。如果代码中存在解析错误,则 eval() 函数返回 false。

<?php
$string = "beautiful";
$time = "winter";

$str = 'This is a $string $time morning!';
echo $str. "<br />";

eval("\$str = \"$str\";"); /*一定要用\转义,不然会出现语法错误 */
echo $str;
?> 

/* eval 还可以实现
  1.运行普通字符串 eg: eval("echo 'aaa';")
  2.运行带<? php开头的字符串
  3.运行<? Php开头,?>结尾的字符串
  4,运行HTML与PHP混合的字符串
  5.从MySQL读取代码(字符串形式),并动态加载
  6.运行包含include和request的代码
  7.知道运行的过程是否出现异常(但无法捕捉到详细异常信息)
*/

assert

assert函数在php中用于判断一个表达式是否成立。返回bool;

Grammar:

PHP 5

``` bool assert ( [mixed $assertion [, string $description ] )
bool assert ( mixed $assertion [, string $description ] )

PHP 7

``` bool assert ( mixed $assertion [, Throwable $exception ] )
bool assert ( mixed $assertion [, Throwable $exception ] )

mixed 说明一个参数可以接受多种不同的(但不一定是所有的)类型。

例如 gettype() 可以接受所有的 PHP 类型,str_replace() 可以接受字符串和数组。

<?php
$s = 123;
echo assert("is_int($s)");
?> 

//  1 [Finished in 0.0s]

从这个例子可以看到字符串参数会被执行,这跟eval()类似。不过eval($code_str)只是执行符合php编码规范的$code_str。
assert的用法却更详细一点。

assert_option()可以用来对assert()进行一些约束和控制;

默认值

ASSERT_ACTIVE=1 //Assert函数的开关
ASSERT_WARNING =1 //当表达式为false时,是否要输出警告性的错误提示,issue a PHP warning for each failed assertion
ASSERT_BAIL= 0 //是否要中止运行;terminate execution on failed assertions
ASSERT_QUIET_EVAL= 0 //是否关闭错误提示,在执行表达式时;disable error_reporting during assertion expression evaluation
ASSERT_CALLBACK= (NULL) // 是否启动回调函数 user function to call on failed assertions

preg_replace +'/e'

preg_replace — 执行一个正则表达式的搜索和替换

Grammar:

mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )

搜索subject中匹配pattern的部分(通常用正则匹配), 以replacement进行替换。

/e 修正符使preg_replace()将replacement 参数当作php代码执行,但是php5.5.0以及后面的php7都已经不再支持了,用 preg_replace_callback() 代替。

创建函数

Grammar:

string create_function (string $args,string $code)

创建一个匿名函数,但不是真正的匿名函数,因为它返回值为函数名

$args 代表参数,多个参数用逗号分隔,

$code 代表函数体

eg:
func2=create_function("$args1,$args2","return $args1+$args2");
返回值为创建的函数名,是唯一的一个字符串
函数调用
func2(3,5);  //返回值为8

创建函数有两种方式:

1.使用function关键字

2.用string create_function (string $args,string $code)

php $cfunc = create_function('$v', 'return system($v);'); $cfunc = ('whoami'); //上下两者创建匿名函数的方式不同,但是结果一样 $cfunc = 'sys'.'tem';//用'.'来拼接 $cfunc = ('whoami');

两种定义函数方式的区别

function定义的函数是在编译阶段生成的

create_function创建的函数是在执行阶段生成的

所以,可以在function定义的函数定义之前或则之后调用它。

callable

call_user_func_array() 和。call_user_func()

<?php
function test($v1){
    echo "testing $v1";
}
call_user_func('test','karma');
?> 
//输出 testing karma
//若为function test(callable $v1) 强制回调类型,则会出现错误 (why?)
//

array_map

包含函数

include

include如果引入的文件不存在,试图继续往下执行,报一个warning
(如果你不介意之前的内容是否被包含,之后的内容都要执行,就使用include)

Grammar:

include $file;

在变量$file 可控的情况下,我们就可以包含任意文件。

由于配置环境不同,可以分为远程文件本地文件包含。

包含函数也能读取任意文件内容,需要用到【支持的协议和封装协议】和【过滤器】

eg:用php留filter读取任意文件

include($_GET['file']);

//?file=php://filter/convert.base64-encode/resource=index.php 

require

比include更严谨:

require如果引入的文件不存在,报fatal error,不再继续执行.
(如果之前的内容一定要被包含,才允许继续执行之后的代码,就使用require)

Include/require 与 include_once /require_once的区别

_once 会自动判断文件是否已经引入,如果引入,不再重复执行.
即:保证被包含文件只可能被引入一次.
(如果包含的文件里有定义函数,那么被包含的文件只能被包含一次,如果多次包含,就会出现函数重定义的错误,php是不运行函数重定义的,会出现致命错误,之后代码不在运行)

allow_url_include = on

远程文件包含

命令执行函数

exec()

Grammar:

function exec(string $command,array[optional] $output,int[optional] $return_value)

执行一个外部程序

exec 执行系统外部命令时不会输出结果,而是返回结果的最后一行,如果你想得到结果你可以使用第二个参数,让其输出到指定的数组,此数组一个记录代表输出的一行,即如果输出结果有20行,则这个数组就有20条记录,所以如果你需要反复输出调用不同系统外部命令的结果,你最好在输出每一条系统外部命令结果时清空这个数组,以防混乱。第三个参数用来取得命令执行的状态码,通常执行成功都是返回0。

passthru()

Grammar:

function passthru(string $command,int[optional] $return_value)

执行外部程序并且显示原始输出

passthru与system的区别,passthru直接将结果输出到浏览器,不需要使用 echo 或 return 来查看结果,不返回任何值,且其可以输出二进制,比如图像数据。

proc_open()

Grammar:

resource proc_open ( string $cmd , array $descriptorspec , array &$pipes [, string $cwd [, array $env [, array $other_options ]]] )

执行一个命令,并且打开用来输入/输出的文件指针

shell_exec()&``

shell_exec() 函数实际上仅是反撇号 (`) 操作符的变体

通过shell环境执行命令,并且将完整的输出以字符串的方式返回。

system()

Grammar:

function system(string $command,int[optional] $return_value)

执行外部程序,并且显示输出

system和exec的区别在于system在执行系统外部命令时,直接将结果输出到浏览器,不需要使用 echo 或 return 来查看结果,如果执行命令成功则返回true,否则返回false。第二个参数与exec第三个参数含义一样。

popen()

Grammar:

popen(command,mode)

通过popen()的参数传递一条命令,并对popen()所打开的文件进行执行。

fcntl_exec()

ob_start()

escapeshellcmd()

// 该函数用于过滤

……

文件操作函数

copy

Grammar:

copy(source,destination)

拷贝文件

file_get contents

Grammar:

file_get_contents(path,include_path,context,start,max_length)

将整个文件读入一个字符串

file_put contents

Grammar:

file_put_contents(file,data,mode,context)

将一个字符串写入文件

file

Grammar:

file(path,include_path,context)

把整个文件读入一个数组中

fopen

Grammar:

fopen(filename,mode,include_path,context)

打开文件或者url

move_uploaded_file

Grammar:

move_uploaded_file(file,newloc)

将上传的文件移动到新的位置

readfile

Grammar:

readfile(filename,include_path,context)

输出文件

rename

Grammar:

rename(oldname,newname,context)

重命名一个文件或目录

rmdir

Grammar:

rmdir(dir,context)

删除目录

Grammar:

unlink(filename,context)

删除文件

读文件

hightlight_file($filename);
show_source($filename);
print_r(php_strip_whitespace($filename));
print_r(file_get_contents($filename));
readfile($filename);
print_r(file($filename)); // var_dump
fread(fopen(filename,”r”),filename,”r”),size);
include($filename); // 非php代码
include_once($filename); // 非php代码
require($filename); // 非php代码
require_once($filename); // 非php代码
print_r(fread(popen(“cat flag”, “r”), $size));
print_r(fgets(fopen($filename, “r”))); // 读取一行
fpassthru(fopen($filename, “r”)); // 从当前位置一直读取到 EOF
print_r(fgetcsv(fopen(filename,”r”),filename,”r”),size));
print_r(fgetss(fopen($filename, “r”))); // 从文件指针中读取一行并过滤掉 HTML 标记
print_r(fscanf(fopen(“flag”, “r”),”%s”));
print_r(parse_ini_file($filename)); // 失败时返回 false , 成功返回配置数组

……

特殊函数

### 信息泄漏

bool phpinfo ([int $what = INFO_ALL])

输出php当前状态的大量信息

软连接-读取文件内容:

symlink()对于已有的target建立一个名为link的符号连接

string redline (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_numeric (mixed $var)

恢复指定的配置选项到它的原始值

数字判断

Bool is_numeric (mixed $var)

如果var时数字和数字字符串则返回true,否则返回false

仅用is_numeric判断而不用intval转换就有可能插入16进制的字符串到数据库,进而可能导致sql二次注入

数组相关

Bool in_array (mixed. $needle , array $haystack [,bool $strict =false])

在haystack中搜索needle,如果没有设置strict则使用宽松的比较

该函数有一个特性,比较之前会进行自动类型转换:$a = '1abc';

超全局变量

$GLOBALS

变量覆盖

void parse_str (string $str [,array & &str])

如果str是URL传递入的查询字符串(query string),则将它解析为变量并设置到当前作用域

int extract (array &var_array [,int $extract_type = EXTR_OVERWRITE [, srting $orefix = NULL]])

本函数用来将变量从数组中导入到当前的符号表中。检查每个键名看是否可以作为一个合法的变量名,同时也检查和符号表中已有的变量名的冲突

Bool mb_parse_str ( string $encoded_string [, array. &result ])

解析GET/POST/Cookie 变量导入到全局作用域中。如果你禁止了 register_glovals,但又想用到一些全局变量,那么此函数就很有用

extract()
import_request_variables()
parse_str()
mb_parse_str()
全局变量覆盖:register_globals为ON,$GLOBALS

列目录

array glob ( string $pattern [, int $flags =0])

glob()函数依照libc glob()函数使用的规则寻找所有与pattern匹配的文件路径,类似于一般shells所用的规则一样。不进行缩写扩展或参数替代。

print_r(glob(“”)); // 列当前目录
print_r(glob(“/
”)); // 列根目录 print_r(scandir(“.”));
print_r(scandir(“/“));
$d=opendir(".");while(false!==($f=readdir($d))){echo"$f\n";}
$d=dir(".");while(false!==($f=$d->read())){echo$f."\n";}

无参数获取信息

array get_defined_vars (void)

返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户自定义变量

array get_defined_constants ([bool $categorize = false])

返回当前所有已定义的常量名和值。这包含define()函数所创建的,也包含了所有拓展所创建的

array get_defined_functions (void)

返回一个包含所有已定义函数列表的多位数组

array get_included_files (void)

返回所有被include、include_once、require和require_once的文件名

序列化函数

serialize()
unserialize()
ini_set(‘session.serialize_handler’, ‘php_serialize’);

文件上传

move_uploaded_file()
getimagesize() //验证文件头只要为GIF89a,就会返回真

Reference

代码执行函数:

PHP Eval研究笔记

PHP assert函数的用法

PHP preg_replace() 正则替换所有符合条件的字符串

PHP——创建函数

PHP——使用callable强制指定回调类型

包含函数:

PHP——Info()信息泄漏漏洞利用提权及防范

PHP——include 和 require 的理解与区别

命令执行函数:

PHP——exec()函数以及获取其返回值

PHP——执行系统外部命令函数:exec()、passthru()、system()、shell_exec()

文件操作函数:

特殊函数:

Linux连接文件:硬连接和软连接