标签:CTF | foreach() | preg_match() | preg_match_all() | 代码审计 | 改后缀 | 科学计数法 | 正则表达式
传送门:http://59.63.200.79:1880/Web-Security/CTF/3/web19/index.php
index.php后加.bak形成index.php.bak
打开源代码,现已改名为web19_index.php.bak。
<?php
echo "waht the hell?";
$flag = "*******";
if ("POST" == $_SERVER['REQUEST_METHOD']) {
$password = $_POST['password'];
if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password)){
echo 'Wrong Format';
exit;
}
while (TRUE) {
$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
if (6 > preg_match_all($reg, $password, $arr))
break;
$c = 0;
$ps = array('punct', 'digit', 'upper', 'lower');
foreach ($ps as $pt){
if (preg_match("/[[:$pt:]]+/", $password))
$c += 1;
}
if ($c < 3) break;
if ("42" == $password) echo $flag;
else echo 'Wrong password';
exit;
}
}
?>
代码解释
if ("POST" == $_SERVER['REQUEST_METHOD']) {}
$password = $_POST['password'];
也就是只要POST才能满足if条件判断,才能执行if里边的语句。
if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password)){}
语法:int preg_match ( string $pattern , string $subject )
pattern: 要搜索的模式,字符串形式。 subject: 输入字符串。
返回 pattern 的匹配次数。 它的值将是 0 次(不匹配)或 1 次,因为 preg_match() 在第一次匹配后 将会停止搜索。
preg_match:执行一个正则表达式匹配,匹配到则返回1,匹配不到则返回0。
preg_match_all:执行一个全局正则表达式匹配,返回成功模式匹配的次数,并将匹配结果存储到一个数组中。
两个函数的区别是preg match第一次匹配成功后就停止匹配,而preg match all是匹配到字符串结束为止。
/^[[:graph:]]{12,}$/'
[:graph:]:是除空格符(空格键与[TAB]键)之外的所有按键
匹配可打印字符(非空格非TAB之外的内容)12个及以上,就是password的长度至少为12,如果不满足就直接退出脚本。
注意 如果输入加号 + ,URL 编码的时候会被当做空格处理,要想加上加号+组成12个字符就得先URL编码加号+ 为 %2b。
while (TRUE){}
$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
if (6 > preg_match_all($reg, $password, $arr)){}
while(TRUE),这个没啥说的,只要到这里都能执行下去。
意思是如果if语句成功执行,break退出循环,我们就得不到flag值。所以我们不能让if语句成功执行,也就是说要让全局匹配成功次数大于6次。
因为是全局匹配,所以匹配成功的条件是检测到任何符号出现1次以上或者任何数字出现1次以上或者任何大写字母出现1次以上或者任何小写字母出现1次以上,一旦匹配成功一次,就开始检测下一次的匹配。
这里特别说明什么时候是一次匹配的结束,就是检测到不是属于同一种特殊字符为止,因为这里每种特殊字符可以出现1次或者多次。
因为这里要成功匹配6次以上,所以每种类型的字符必须间隔出现6次以上,结合第一个条件,字符出现12个以上。
连续的符号、数字、大写、小写,作为一段,至有六段。比如TEst.-TEst01,分为TE、st、.-、TE、st、01这六段。
$c = 0;
$ps = array('punct', 'digit', 'upper', 'lower');
foreach ($ps as $pt){
if (preg_match("/[[:$pt:]]+/", $password))
if ($c < 3) break;
语法:foreach ($array as $value){ 要执行代码; }
每进行一次循环,当前数组元素的值就会被赋值给 $value 变量(数组指针会逐一地移动),在进行下一次循环时,您将看到数组中的下一个值。
表示为输入的字符串至少含有符号、数字、大写、小写中的三种类型
if ("42" == $password) echo $flag;
执行了这个语句我们才可以得到想要的flag,也就是password值等于’42’,因为类型都是字符串,所以password中的值必须等于42。
var_dump("1" == "01"); // 1 == 1 --> true
var_dump("10" == "1e1"); // 10 == 10 -->true
var_dump(100 == "1e2"); // 100 == 100 -->true
要得到flag要满足的条件分别是:
2. 字符串中,把连续的大写,小写,数字,符号作为一段,至少分六段,例如a12SD.io8可以分成a 12 SD . io 8六段
下面的这些都等于42(E大小写都可以。):
Payload:password=420.00000E-1
Payload:42000000000.0E-9
Payload:password=42.000e%2b0000
注意:42.000e+0000,这里的加号+要URL编码成%2b,不然URL 编码加号+的时候会被当做空格处理,从而导致不满足要求。
%2b后的0在满足条件后可以再多加几个,小数点后边的0在满足条件的情况下也可以多加几个0。
打赏我,让我更有动力~
© 2016 - 2023 掌控者 All Rights Reserved.