PHP特性总结
写在前面
有些文件包含,PHP函数漏洞等有关PHP的题目会放在这里
包含题目
- [BSidesCF 2020]Had a bad day
- [安洵杯 2019]easy_web
- [WUSTCTF 2020]朴实无华
[BSidesCF 2020]Had a bad day
打开题目发现点击woofers和meowers以后url会发生变化,并且加载了图片出来,实际上是get提交了一个category的一个变量,猜测可能是SQL注入或者文件包含,SQL测试无果,尝试伪协议读取index的源码,发现报错,再次尝试后得到源码如下:大概意思就是传入的category必须包含woofers,meowers,index中的一个。而使用php伪协议的时候,是可以插入其他参数的。不影响最后伪协议的执行,伪协议是类似于提取关键词的机制,因此构建payload1
2
3
4
5
6
7
8
9
10
11
12
$file = $_GET['category'];
if(isset($file))
{
if( strpos( $file, "woofers" ) !== false || strpos( $file, "meowers" ) !== false || strpos( $file, "index")){
include ($file . '.php');
}
else{
echo "Sorry, we currently only support woofers and meowers.";
}
}end1
?category=php://filter/read=convert.base64-encode/meowers/resource=flag
[安洵杯 2019]easy_web
打开题目发现url里提交了一个img参数和一个cmd参数,img参数的值是TXpVek5UTTFNbVUzTURabE5qYz0,扔到base64解码后还是一个base64串,再解码以后是一个16进制字符串,最后结果是555.png。照这种思路,把flag.php编码以后传进去,发现成功,但是应该是flag被过滤了。试试index.php,发现了源码img的内容经过preg_replace后变成只有字母数字和.的内容,然后经过一个flag的严格匹配.而我们想要命令执行只能通过cmd,cmd过滤了一堆字符,sh和bash肯定是没法用了,cat和tac也被过滤了,;也被过滤了。这下我是真不会了,去看师傅们的wp发现反斜是没有被过滤的。这里贴一个脚本1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd']))
header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));
$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
echo '<img src ="./ctf3.jpeg">';
die("xixi~ no flag");
} else {
$txt = base64_encode(file_get_contents($file));
echo "<img src='data:image/gif;base64," . $txt . "'></img>";
echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "<br>";
} else {
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
} else {
echo ("md5 is funny ~");
}
}这个脚本会报错Warning: preg_match(): No ending delimiter ‘/‘ found in C:\phpstudy_pro\WWW\127.0.0.11\1.php on line 81
2
3
4
5
6
7
8
$cmd=$_GET['cmd'];
$cmd1="ca\t";
echo $cmd;
echo "<br>";
echo $cmd1;
echo "<br>";
echo preg_match("/\\/", $cmd);
没有结束符/,即\把|也转义了,而下面这个就不会报错
1 |
|
只有三个反斜的时候参能真正匹配到一个反斜杠,因此构建payload
1 | cmd=ca\t /flag |
md5序列Google一下很好找,
[WUSTCTF 2020]朴实无华
打开题目,发现人间极乐bot其实是提示,查看robots.txt。发现fakefl4g,查看源代码什么也没有,在响应头里发现了一个lookme字段有一个fl4g.php。查看发现源码
1 |
|
要求传入一个num,md5和get_flag.三个绕过最后接一个命令执行
第一个绕过,intval
1 | intval() 函数用于获取变量的整数值。 |
看到intval(‘1e10’)会返回1,而当字符串强制转换为int型时,会把字符串当作科学计数法转换,所以这里可用字符串1e10绕过
第二个绕过,要求md5加密以后和原来的字符串一样,众所周知,php具有弱类型,== 在进行比较的时候,会先将字符串类型转化成相同,再比较。因此,根据这一点,可以遍历出一个字符串,使得进行MD5加密前是’0e’开头的,MD5加密后也是’0e’开头的,这样子,就能保证加密前后的值是相等==的了,这个直接Google
找到满足条件的字符串’0e215962017’
第三个绕过,要求传入的命令不能有空格,如果get_flag里面有cat,就会被替换成wctf2020,但都是常规绕过。这里就不细说
payload
1 | ?num=1e10&md5=0e215962017&get_flag=ls |
发现fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
最终payload:
1 | ?num=1e10&md5=0e215962017&get_flag=ca\t$IFS$1fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag |