环境变量信息泄露
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 下使用


连上了之后就再也连不上了。 不搞了 这题真的浪费时间