Post

Writeup Giải WHYCTF2025

Writeup Giải WHYCTF2025

WHYCTF2025

I. Planets - Web 50

Khi truy cập vào thử thách trên thì trang web hiển thị ra một danh sách các hành tinh, ngoài ta không có thêm chức năng gì cả:

image.png

Khi ta vào burp ta thấy một lệnh SQL được gọi trực tiếp trong query để nhận về danh sách các hành tinh:

image1.png

Thử thay đổi query SQL để xem tất cả các bảng trong Database này xem có được không nào

Dùng query=SHOW TABLES và kết quả nhận được như sau:

image2.png

vậy bây giờ thử hiển thị bảng abandoned_planets xem bên trong có gì bằng query sau: query=SELECT * FROM abandoned_planets và kết quả nhận được chính là flag

image3.png

Flag : flag{9c4dea2d8ae5681a75f8e670ac8ba999}

II. Shoe Shop 1.0 - Web 50

Khi truy cập trang web ta thấy một trang web có chức năng bán giày như tiêu đề của thử thách với các tính năng cơ bản.

image4.png

Tạo tài khoản và đăng nhập sau đó vào thư mục cart thì được giao diện như sau:

image5.png

Bắt request trong burp suite ta thấy trong request query có một tham số rất đặc biệt đó là id=15 , mình đoán với mỗi người dùng khác nhau thì sẽ có id khác nhac

image6.png

Dựa trên suy đoán trên mình thử thay đổi giá trị của id để xem kết quả trả về như thế nào, ngoài ra trong gợi ý của đề bài có nói rằng đôi giày đặc biệt nằm trong cart của admin . Mà thông thường admin sẽ có id nhỏ nên mình bắt đầu thử giá trị của id từ 0 trở đi.

Với id=0 thì không có gì đặc biệt cả!

image7.png

Tiếp tục thử với id=1 thì đã truy cập được vào cart của admin và đã thấy được giá trị của flag

image8.png

Flag: flag{00f34f9c417fcaa72b16f79d02d33099}

III. WHY2025 CTF TIMES - Web 50

Khi ta mở trang web và bắt request trong burp suite thì bắt gặp một file paywall.min.js

image9.png

Xem thử file js đó ta thấy một đoạn code rất dài đã bị làm rối

image10.png

Truy cập trang https://deobfuscate.io/ để thửu gỡ rối đoạn mã, khi dán đoạn code vào input ta nhận được thông báo như sau

image11.png

Chuyển đến trang web https://obf-io.deobfuscate.io/ và tiếp tục dán đoạn mã ban đầu và giải mã ta nhận được một đoạn mã đã được gỡ rối một phần và trong phần đã được gỡ rối đó ta đã có thể thấy được flag

image12.png

Flag: flag{2d582cd42552e765d2658a14a0a25755}

IV. Buster - Web 50

Khi truy cập vào trang web ta được giao diện như trên, đọc đoạn văn bản bên dưới tấm ảnh gif gợi ý cho ta việc dùng các công cụ để brute force các đường dẫn.

image13.png

Thử dùng gobuster với wordlist cơ bản chạy trong một khoảng thời gian ta có được kết quả như sau

image14.png

Để ý 3 đường dẫn với trạng thái 200 đều là một hoặc một phần của dòng chữ liên quan đến flag cho mình ý tưởng rằng thử thách trên được thiết kế để đi dò từng kí tự của đoạn flag. Để kiểm chứng nhận định đó mình đã thử truy cập vào /fl và /fla đều trả ra trạng thái 200 trong khi các đường dẫn như /fi và flat đều trả ra lỗi 404 đã xác định nhận định trên là đúng

Để khai thác nhận định trên thì việc ngồi mò từng kí tự dường như là bất khả thi nên mình dùng đến một đoạn script bằng python thể phục vụ việc khai thác một cách tự động

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import requests
import string
import time
BASE_URL = "https://buster.ctf.zone/flag_dec{}"
CHARSET = string.ascii_lowercase + string.digits + "_-{}"
SUCCESS_STATUS_CODE = 200
NOT_FOUND_STATUS_CODE = 404
found_flag = ""

print(f"Bắt đầu brute-force sau 'flag_dec': {BASE_URL.format('')}")
print(f"Thử các ký tự: {CHARSET}\n")
while True:
    found_char_in_iteration = False
    print(f"Đang dò ký tự thứ {len(found_flag) + 1}...")

    for char in CHARSET:
        test_string = found_flag + char
        url_to_test = BASE_URL.format(test_string)

        try:
            response = requests.get(url_to_test)

            print(f"Thử '{char}': {url_to_test} -> Status: {response.status_code}")
            if response.status_code == SUCCESS_STATUS_CODE:
                found_flag += char
                print("-" * 50)
                print(f"✓ Tìm thấy ký tự đúng '{char}'! Chuỗi hiện tại: flag_dec{found_flag}")
                print("-" * 50)
                found_char_in_iteration = True
                break

        except requests.exceptions.RequestException as e:
            print(f"Lỗi kết nối: {e}")
            time.sleep(2)
    if not found_char_in_iteration:
        print(f"\nKhông tìm thấy ký tự nào trả về status 200. Dừng brute-force.")
        break

print("\n" + "="*50)
print(f"HOÀN THÀNH! Chuỗi tìm được sau 'flag_dec': {found_flag}")
print(f"URL đầy đủ: flag_dec{found_flag}")
print("="*50)

Ngoài ra trong source code của web cũng có một phần gợi ý về định dạng của flag để ta có thể thu hẹp phạm vi brute force cho tối ưu thời gian hơn

image15.png

Và đây là kết quả khi chạy script

image16.png

Định dạng lại chuỗi url ta được sẽ nhận được một flag hoàn chỉnh

Flag: flag{deca3b962fc316a6d69a7e0c2c33c7fa}

This post is licensed under CC BY 4.0 by the author.