# baby-union >로그인 시 계정의 정보가 출력되는 웹 서비스입니다. SQL INJECTION 취약점을 통해 플래그를 획득하세요. 문제에서 주어진 init.sql 파일의 테이블명과 컬럼명은 실제 이름과 다릅니다. ## Solution: ![image](https://hackmd.io/_uploads/Skw-1V--yl.png) Cách Backend xử lý request, cụ thể Vì backend không triển khai bất kỳ filter nào và lấy giá trị từ 2 input truyền vào `uid` và `upw` truyền trực tiếp vào câu query. ![image](https://hackmd.io/_uploads/SJT8yNWWJg.png) Cấu trúc database ![image](https://hackmd.io/_uploads/r1vJl4W-kl.png) Hướng giải quyết như sau: đầu tiên mình sẽ dumb table (xác định table chứa flag ) -> dumb colum (xác định các cột chứa nội dung flag ) -> query và lấy flag thông qua `union select`. **Dumb table chứa flag** ``` apple' UNION SELECT 1,TABLE_NAME,3,4 FROM INFORMATION_SCHEMA.TABLES;# ``` Ta có thể dễ nhận ra table chứa flag là `onlyflag`. ![image](https://hackmd.io/_uploads/S1uVb4--yx.png) **Dumb column** ``` apple' UNION SELECT 1,COLUMN_NAME,3,4 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'onlyflag';# ``` ![image](https://hackmd.io/_uploads/ByyTb4bbyl.png) Giờ chỉ cần dumb data từ các cột `svalue`, `sflag` và `sclose` sau đó concat => flag Tuy nhiên ta có thể thấy chỉ có giá trị của các cột thứ tự 1,2,4 mới được render.Vì vậy câu query để lấy data sẽ là: ``` apple' UNION SELECT svalue,sflag,3,sclose FROM onlyflag;# ``` ![image](https://hackmd.io/_uploads/ry-3fEWb1x.png) # Type c-j >php로 작성된 페이지입니다. 알맞은 Id과 Password를 입력하여 플래그를 획득하세요. ## Solution: ![image](https://hackmd.io/_uploads/BJelr4-Wyx.png) Gía trị được gửi đến check.php ![image](https://hackmd.io/_uploads/rkO3UV--1x.png) ![image](https://hackmd.io/_uploads/rkdqLVWZke.png) Hàm `getRandStr` được gọi và tạo ra một chuỗi random 10 ký tự và gán cho biến `$id`. Sau đó sử dụng thuật toán mã hóa `sha-1` để mã hóa ký tự 1 và gán cho biến `$pw` . **Hướng giải quyết như sau:** Vấn đề là mình phải xác định được giá trị của `input_id` được nhập vào sao cho bằng với biến `$id` và đội dài `input_id` phải là 10. Vấn đề kế tiếp đơn giản hơn, chỉ cần sử dụng thuật toán mã hóa `sha-1` để mã hóa ký tự 1 và lấy 8 ký tự đầu của chuỗi mã hóa gán cho `input_pw`. Trong PHP, khi một chuỗi được chuyển đổi thành kiểu số nguyên bằng cách dùng (int), PHP sẽ đọc chuỗi từ trái sang phải. - Nếu mình nhập một chuỗi bắt đầu bằng chữ cái bất kỳ => 0 khi convert sang int - Nếu bắt đầu bằng một số nguyên => chỉ các số nguyên được đổi sang int. Tương tự vậy nếu biến `$id` được tạo từ một chuỗi không bắt đầu bằng số ví dụ "abac134678" thì (int)$id cũng sẽ trả về 0. **Vì vậy** Sử dụng chuỗi `ababababab` có độ dài 10 ký tự cho Trường `id`. Gen hash SHA1 với giá trị là 1 ![image](https://hackmd.io/_uploads/HJrbsVZbJe.png) vì chỉ cần 8 giá trị đầu => chỉ cần nhập `356a192b` cho trường `pw` ![image](https://hackmd.io/_uploads/S1WLkHWWJg.png) Gửi một vài lần, ngay khi hàm `getRandStr` tạo một chuỗi ngẫu nhiên với chuỗi bắt đầu bằng chữ thì ta sẽ bypass được và render flag thành công. ![image](https://hackmd.io/_uploads/H1gPkHbbyl.png) # Broken Buffalo Wings ## Description: >Buffalo wings, also known as hot wings or chicken wings... ## Solution: ![image](https://hackmd.io/_uploads/S16mn7SWyl.png) Khi truy cập tệp nginx.conf, có thể thấy không có bất kỳ hạn chế nào nếu truy cập trực tiệp /flag.txt. ![image](https://hackmd.io/_uploads/Syzxp7H-kg.png) truy cập `http://host3.dreamhack.games:22303/flag.txt` và lấy flag. ![image](https://hackmd.io/_uploads/HyIUpXHbyg.png) # random-test ## Description: ![image](https://hackmd.io/_uploads/SJskCmSWye.png) ## Solution: Dưới đây là src code của chall. ![Screenshot 2024-11-04 000936](https://hackmd.io/_uploads/B1pdAXHbkl.png) Điều kiện đầu tiên là gía trị của biến `locker_num` không được rỗng, tiếp theo `rand_str[0:len(locker_num)]` sẽ lấy các ký tự của rand_str từ vị trí 0 đến vị trí `len(locker_num) - 1`. # Broken Is SSRF possible? ## Description: >?? : 퍼벙-(ssrf 터지는 소리) ## Solution: ![image](https://hackmd.io/_uploads/SkRkOEeLJx.png) Đầu tiên để truy cập `/admin` thì ta phải sử dụng ip phải là `127.0.0.1`, và giá trị của tham số `nickname` được SHA256ing sẽ là giá trị biến flag. ![image](https://hackmd.io/_uploads/BJPDtNeLkg.png) Khi truy cập `/flag` giá trị của tham số `nickname` được gửi kèm trong request sẽ được SHA256ing và so sánh với giá trị của biến `flag` ở trên nếu kết quả là `true` => trả về `flag` mà ta cần tìm để solve chall. ``` @app.route('/check-url', methods=['POST']) def check_url(): global isSafe data = request.get_json() if 'url' not in data: #(1) return jsonify({'error': 'No URL provided'}), 400 url = data['url'] host = re.search(r'(?<=//)[^/]+', url) print(host.group()) if host is None: #(2) print("호스트가 감지되지 않았습니다.") return "Fail" host = host.group() if ":" in host: host = host.split(":") host = host[0] if host != "www.google.com": #(3) isSafe = False return "Host는 반드시 www.google.com이어야 합니다." isSafe = True result = check_ssrf(url,1) if result != "SUCCESS" or isSafe != True: return "SSRF를 일으킬 수 있는 URL입니다." try: response = requests.get(url) status_code = response.status_code return jsonify({'url': url, 'status_code': status_code}) except requests.exceptions.RequestException as e: return jsonify({'error': 'Request Failed.'}), 500 ``` 1) Tại `/check-url` có thể thấy để bypass khối if `(1)` ta chỉ cần gửi dữ liệu theo format json với key name là `url`. 2) Để bypass khối if `(2)` giá trị của `url` sau khi được filter bởi chuỗi regex sau `host = re.search(r'(?<=//)[^/]+', url)` không được none. - nói sơ qua về chuỗi regex trên thì cụ thể nó sẽ filter ra chuỗi ở giữa `//` và `/`, ví dụ nếu ta truyền http://www.google.com/something thì sau khi filter sẽ còn www.google.com và gán cho biến `host`. 3) Sau đó khối if thứ `(3)` sẽ kiểm tra giá trị của host và "www.google.com" nếu khác sẽ trả về `"Host는 반드시 www.google.com이어야 합니다."` Nếu vượt qua các khối if trên giá trị `url` sẽ được truyền vào hàm `check_url` để kiểm tra có phải là một payload thực hiện ssrf không. ``` @app.route('/check-url', methods=['POST']) def check_url(): global isSafe data = request.get_json() if 'url' not in data: return jsonify({'error': 'No URL provided'}), 400 url = data['url'] host = re.search(r'(?<=//)[^/]+', url) print(host.group()) if host is None: print("호스트가 감지되지 않았습니다.") return "Fail" host = host.group() if ":" in host: host = host.split(":") host = host[0] if host != "www.google.com": isSafe = False return "Host는 반드시 www.google.com이어야 합니다." isSafe = True result = check_ssrf(url,1) if result != "SUCCESS" or isSafe != True: return "SSRF를 일으킬 수 있는 URL입니다." try: response = requests.get(url) status_code = response.status_code return jsonify({'url': url, 'status_code': status_code}) except requests.exceptions.RequestException as e: return jsonify({'error': 'Request Failed.'}), 500 ``` Phân tích qua `/check-url` có thể thấy nếu thành công vượt qua các khối if thì `url` ban đầu được truyền vào sẽ được gửi đi thông qua đoạn code sau `response = requests.get(url,allow_redirects=False)` và ta có thể thực hiện ssrf Nhưng vấn đề là làm sao để ta có thể chèn ip `127.0.0.1` vào yêu cầu mà host phải chứa `www.google.com` để thực hiện ssrf => ta có thể nhúng thông tin xác thực vào URL bằng `@`. Bây giờ ta đã có giải pháp, và vấn đề cuối cùng là phải vượt qua được các điều kiện trong hàm `check_ssrf`. Giờ thì ta sẽ vào phân tích hàm `check_ssrf`. 1) chỉ cần checked không >= 3 là ok (nghĩa là 1 payload url không được được gửi quá fail 3). 2) protocol trong url chỉ có thể là `http` và `https`. 3) và tương tự như `check_url()` thì host sau khi filter bởi chuỗi regex giống `check_url()` không được none. 4) và giá trị `host` phải tồn tại. Tổng hợp lại ta có payload như sau: ``` http://www.google.com:pwd@127.0.0.1/admin?nickname=healtheworld ``` ![image](https://hackmd.io/_uploads/SyXNe8e8Jx.png) giờ ta đã thành công gán giá trị `healtheworld` được SHA256ing cho biến flag. Sau đó tiếp tục gửi một request đến `/flag` với tham số `nickname="healtheworld"` để lấy flag. => biến flag sẽ so sánh với `healtheworld` từ request `/flag` được SHA256ing và trả về `true`. ``` DH{please_share_your_idea_okay_good} ```