前言
本日進度:
上課紀錄
Lab - swirl
stage 1 & 2
這兩題跟之前 Lab - phpisbest 差不多,只要在後面加上
/?A[]=[0]&B[]=[3]
就能達成各種 null==null
就能過關了
stage 3
這題我有觀察到可以 path
traversal,但是我亂戳戳不到東西,過了大概十分鐘,又沒忍住點了一下 hint
,才發現要戳的東西就是寫在原始碼裡面的 config.php
,就能前往下一關了
Image
Image
stage 4
這題她沒有一個地方讀取 👀
,但有個
extract($_POST)
可以利用 POST
的方式輸入
👀
,之後就跟 lfi2rce
一樣,利用 php
filter chain 構造出 webshell ,就能得到 Flag 了
Image
Image
Note: 這邊要注意的是這個 webshell 指令最後需要的參數
1
,他是透過 $_GET[1]
來取得的,所以要寫在網址後面解析,不是寫在 POST 裡面
Lab - fakelog
他很好心的給我們看了他生成的原始碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import sys
if __name__ == '__main__': if len(sys.argv) < 2: print("no argument") sys.exit()
magic_num = int(sys.argv[1]) if sys.argv[1].isdigit() else sys.argv[1] if magic_num == 0: print("0 is not allowed") sys.exit() while magic_num != 1: with open(f"fakelog/{magic_num % 6 if isinstance(magic_num, int) else magic_num}", "r", encoding="utf-8") as fd: print(fd.read()) magic_num = 3 * magic_num + 1 if magic_num % 2 else magic_num // 2
|
重點有兩個
magic_num = int(sys.argv[1]) if sys.argv[1].isdigit() else sys.argv[1]
with open(f"fakelog/{magic_num % 6 if isinstance(magic_num, int) else magic_num}", "r", encoding="utf-8") as fd:
他不會檢查 magic number
是文字,而且在他是文字的時候他還會直接讓我們讀取檔案,所以我們可以利用這個漏洞來做
path traversal
又可以從 Hint 的 dockerfile 中知道有個叫 main.py
是主程式,拿出來看看
1 2 3 4 5 6 7 8 9 10 11 12
| FROM python:3.10 RUN curl -sSL https://install.python-poetry.org | POETRY_HOME=/etc/poetry python3 - WORKDIR /app
COPY pyproject.toml poetry.lock . RUN /etc/poetry/bin/poetry config virtualenvs.create false && \ /etc/poetry/bin/poetry install COPY . . ARG FLAG RUN echo $FLAG > /app/flag_`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1` USER daemon ENTRYPOINT ["python", "/app/main.py"]
|
Image
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| result: from flask import Flask, render_template, request, send_file import subprocess
app = Flask(__name__)
@app.route('/') def home(): return render_template('home.html')
@app.route('/howtogen') def howtogen(): return send_file('gen.py', mimetype='text/plain', as_attachment=False)
@app.route('/hint') def hint(): return send_file('Dockerfile', mimetype='text/plain', as_attachment=False)
@app.route('/gen', methods=['GET', 'POST']) def get_input(): message = None if request.method == 'POST': user_input = request.form['user_input'] if " " in user_input: result = "evil input" else: result = subprocess.run( f"python gen.py {user_input}", shell=True, capture_output=True, text=True).stdout.replace('\', '') message = f"result: {result}" return render_template('generate.html', message=message)
if __name__ == "__main__": app.run(host='0.0.0.0', port=5050)
|
可以知道不能輸入空白,另外還有他執行程式的方法是
1 2
| subprocess.run( f"python gen.py {user_input}", shell=True, capture_output=True, text=True).stdout.replace('\', '')
|
可以讓我們利用類似 ;id
這樣的方式來達到 RCE,空白就用
${IFS}
來代替,隨便戳戳看之後就能拿到 Flag 了
Image
Image
Image
參考資料