# 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";}
```

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