Challenge
CTF Name: Cookie Arena
Challenge: PHP Inclusion to RCE
Challenge description: Try to get the flag somewhere in root directory
Challenge category: PHP inclusion, nginx, web, log poisoning, path traversal
Year: 2023
Link: https://battle.cookiearena.org/challenges/web/php-inclusion-to-rce
Thu thập thông tin
Đầu vào challenge, mình được ném vào trong 1 trang chỉ có 1 nút duy nhất là What is CTF? Trong challenge này không có bất kỳ tính năng nào, đúng nghĩa ném 1 trang HTML hơi rỗng rồi kêu “mày hack đi” 🙃
Lướt cả trang thì thu thập được 2 URL:
- / – Click vào nút What is CTF sẽ được chuyển đến URL dưới
- /file=ctf.txt
Nhìn vào query param trên, mình nghĩ đến path traversal, nên mình có vài test case:
- /?file=/etc/passwd – Không có nội dung trả về
- /?file=../../../../../../../../../../../../etc/passwd – Không có nội dung trả về
- /?file=./ctf.txt – Nội dung tương tự với /?file=ctf.txt
- /?file=../ctf.txt – Nội dung tương tự với /?file=ctf.txt
- ?file=ctf../.txt – Nội dung tương tự với /?file=ctf.txt
- %2Fetc%2Fpasswd – Không có nội dung trả về
- ..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd – Không có nội dung trả về
Từ dữ kiện trên thì mình đoán được backend đằng sau đã replace ../ thành chuỗi rỗng (“”), rõ ràng nhất là ở path ?file=ctf../.txt được trả về cùng nội dung /?file=ctf.txt.
Vậy nếu “../” replace thành “”, thì “….//” có được replace thành “” không? Mình thử với test case sau:
- /?file=….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//etc/passwd
Mình hiển thị ra được file /etc/passwd ngon lành, chứng tỏ “….//” được replace thành “../” chứ không replace hết thành “”. Lỗ hổng Path Traversal có tồn tại trong app này.
Giờ mình sẽ lợi dụng Path Traversal để lấy flag, vấn đề là mình không biết được file flag tên gì, chỉ biết nó nằm ở directory / trên Linux. App này cũng không có tính năng upload để mình tìm đường nghịch. Vì thế mình tiếp tục đi tìm thông tin dựa vào request.
Một thông tin thú vị nữa mình thấy đó là Server: nginx trong response header, chứng tỏ NGINX đang đứng giữa client request và application.

Vậy câu hỏi sẽ là: Mình có print ra được log của nginx bằng Path Traversal không? Để thử thì mình phải tìm đến vị trí file log của NGINX, mặc định sẽ nằm ở /var/log/nginx/access.log, mình thử bằng query param:
/?file=….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//….//var/log/nginx/access.log

Access log của NGINX log ra ngon lành.
Dữ kiện có được
Vậy giờ mình có những dữ kiện:
- Backend Language: PHP
- Web server: NGINX
- Logic:
- Hiển thị file được nhận từ query param
- Mọi ký tự “../” sẽ được replace thành “”
- Hiển thị nội dung đó lên UI
- Để hiển thị nội dung, có thể PHP đã sử dụng function include. include sẽ nhận param là đường dẫn file, và hiển thị nội dung của file đó lên. Nếu include dính vào file có block <?php ?> thì nó sẽ thực thi lệnh trong block đó.
Mình hình dung code trong file PHP sẽ như thế này
<h2> CTF </h2>
<span>Do some bypass to find the flag.</span>
<?php
$file_to_show = $_GET["file"];
$file_to_show = replacePathPattern($file_to_show); // "../" -> ""
include($file_to_show)
...
?>
Tiến hành thử lấy flag
Vậy nên tiếp theo mình sẽ “nhét” đoạn mã PHP của mình vào trong access log. Để nhét an toàn nhất thì mình chọn header User-Agent, vì nó sẽ không bị encode lại như khi để trong URL, và header này cũng khá là thoải mái khi sửa thành cái gì cũng được, rất ít khi bị ảnh hưởng bởi logic hoặc các web server.
Mình bắt đầu thử 1 đoạn cơ bản bằng function phpinfo(), function này sẽ hiển thị nguyên 1 đoạn UI config của PHP lên.

Về lại trang hiển thị access log thì mình thấy hiển thị thông tin cấu hình của PHP lên UI ngon lành:

Tiếp đến, để dò ra file flag nó nằm ở đâu thì mình sẽ cho chạy lệnh shell_exec(“/bin/ls /”) để thực thi lệnh “ls /” trong linux, sửa lại trong User-Agent y chang hồi nãy

Quay lại trang access log và mình sẽ thấy được tất các file trong directory /.

Mình thấy được tập tin flagQGjBX.txt, nó chính là tập tin chứa flag của CTF này (bỏ qua flag.txt tại vì nó là file rỗng =))) với lấy được ra thì đã xong từ đầu rồi)
Sửa thêm phát cuối để hiển thị nội dung của flagQGjBX.txt là mình hoàn tất Challenge này.


Flag chính là CHH{LfI_1OgS_pOisonIN6_a2f63cea41e3b5c844296a5ce62bdcb2}.
Tóm gọn lại
Application trong challenge này có 2 lỗ hổng là:
- Path Traversal – Mình có thể đi lùi về để lấy những nội dung vượt ngoài folder của application
- PHP Inclusion – Nhờ vào Path Traversal, PHP sẽ đọc những nội dung mà mình muốn xem (một cách không chính thống) thông qua tính năng Inclusion
- Remote Code Execution – Mình có thể thực thi OS command nhờ vào trình thông dịch của PHP thông qua việc nhét đoạn mã mình muốn trong code block <?php … ?> ở bất cứ nơi nào mà mình có thể nhờ PHP Include file đó.