• HFCTF-2021-Final-easyflask


    考点:

    环境变量信息泄露

    pickle 反序列化RCE

    Flask_seesion 伪造

    __ruduce__魔术方法利用

    思路:

    反序列化肯定包含 创建新对象的操作,如果__reduce__里包含攻击代码就可以实现RCE,但是被反序列化的输出储存在session里,需要知道密钥进行伪造。

    密钥获得途径:一般都可以在 代码里、配置文件里(app.config)、环境变量里(/proc/self/environ)获得。这题属于第三者。

     首先拿到secret_key=glzjin22948575858jfjfjufirijidjitg3uiiuuhOLDPWD

    /app/source源码信息:

    1. #!/usr/bin/python3.6
    2. import os
    3. import pickle
    4. from base64 import b64decode
    5. from flask import Flask, request, render_template, session
    6. app = Flask(__name__)
    7. app.config["SECRET_KEY"] = "*******"
    8. User = type('User', (object,), {
    9. 'uname': 'test',
    10. 'is_admin': 0,
    11. '__repr__': lambda o: o.uname,
    12. })
    13. @app.route('/', methods=('GET',))
    14. def index_handler():
    15. if not session.get('u'):
    16. u = pickle.dumps(User())
    17. session['u'] = u
    18. return "/file?file=index.js"
    19. @app.route('/file', methods=('GET',))
    20. def file_handler():
    21. path = request.args.get('file')
    22. path = os.path.join('static', path)
    23. if not os.path.exists(path) or os.path.isdir(path) \
    24. or '.py' in path or '.sh' in path or '..' in path or "flag" in path:
    25. return 'disallowed'
    26. with open(path, 'r') as fp:
    27. content = fp.read()
    28. return content
    29. @app.route('/admin', methods=('GET',))
    30. def admin_handler():
    31. try:
    32. u = session.get('u')
    33. if isinstance(u, dict):#如果u对应的值是字典,会读取 u.b
    34. u = b64decode(u.get('b'))
    35. u = pickle.loads(u)#pickle反序列化
    36. except Exception:
    37. return 'uhh?'
    38. if u.is_admin == 1:
    39. return 'welcome, admin'
    40. else:
    41. return 'who are you?'
    42. if __name__ == '__main__':
    43. app.run('0.0.0.0', port=80, debug=False)

    因为需要伪造 session  但是我在kali 用 flask-session-cookie-manager  加密后的session 没有 反弹shell 成功。 在 window 用的脚本 也没成功。

    看到别的师傅用这个脚本,试一下:

    1. """ Flask Session Cookie Decoder/Encoder """
    2. __author__ = 'Wilson Sumanang, Alexandre ZANNI'
    3. # standard imports
    4. import sys
    5. import zlib
    6. from itsdangerous import base64_decode
    7. import ast
    8. # Abstract Base Classes (PEP 3119)
    9. if sys.version_info[0] < 3: # < 3.0
    10. raise Exception('Must be using at least Python 3')
    11. elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    12. from abc import ABCMeta, abstractmethod
    13. else: # > 3.4
    14. from abc import ABC, abstractmethod
    15. # Lib for argument parsing
    16. import argparse
    17. # external Imports
    18. from flask.sessions import SecureCookieSessionInterface
    19. class MockApp(object):
    20. def __init__(self, secret_key):
    21. self.secret_key = secret_key
    22. if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
    23. class FSCM(metaclass=ABCMeta):
    24. def encode(secret_key, session_cookie_structure):
    25. """ Encode a Flask session cookie """
    26. try:
    27. app = MockApp(secret_key)
    28. session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
    29. si = SecureCookieSessionInterface()
    30. s = si.get_signing_serializer(app)
    31. return s.dumps(session_cookie_structure)
    32. except Exception as e:
    33. return "[Encoding error] {}".format(e)
    34. raise e
    35. def decode(session_cookie_value, secret_key=None):
    36. """ Decode a Flask cookie """
    37. try:
    38. if(secret_key==None):
    39. compressed = False
    40. payload = session_cookie_value
    41. if payload.startswith('.'):
    42. compressed = True
    43. payload = payload[1:]
    44. data = payload.split(".")[0]
    45. data = base64_decode(data)
    46. if compressed:
    47. data = zlib.decompress(data)
    48. return data
    49. else:
    50. app = MockApp(secret_key)
    51. si = SecureCookieSessionInterface()
    52. s = si.get_signing_serializer(app)
    53. return s.loads(session_cookie_value)
    54. except Exception as e:
    55. return "[Decoding error] {}".format(e)
    56. raise e
    57. else: # > 3.4
    58. class FSCM(ABC):
    59. def encode(secret_key, session_cookie_structure):
    60. """ Encode a Flask session cookie """
    61. try:
    62. app = MockApp(secret_key)
    63. session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
    64. si = SecureCookieSessionInterface()
    65. s = si.get_signing_serializer(app)
    66. return s.dumps(session_cookie_structure)
    67. except Exception as e:
    68. return "[Encoding error] {}".format(e)
    69. raise e
    70. def decode(session_cookie_value, secret_key=None):
    71. """ Decode a Flask cookie """
    72. try:
    73. if(secret_key==None):
    74. compressed = False
    75. payload = session_cookie_value
    76. if payload.startswith('.'):
    77. compressed = True
    78. payload = payload[1:]
    79. data = payload.split(".")[0]
    80. data = base64_decode(data)
    81. if compressed:
    82. data = zlib.decompress(data)
    83. return data
    84. else:
    85. app = MockApp(secret_key)
    86. si = SecureCookieSessionInterface()
    87. s = si.get_signing_serializer(app)
    88. return s.loads(session_cookie_value)
    89. except Exception as e:
    90. return "[Decoding error] {}".format(e)
    91. raise e
    92. if __name__ == "__main__":
    93. # Args are only relevant for __main__ usage
    94. ## Description for help
    95. parser = argparse.ArgumentParser(
    96. description='Flask Session Cookie Decoder/Encoder',
    97. epilog="Author : Wilson Sumanang, Alexandre ZANNI")
    98. ## prepare sub commands
    99. subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')
    100. ## create the parser for the encode command
    101. parser_encode = subparsers.add_parser('encode', help='encode')
    102. parser_encode.add_argument('-s', '--secret-key', metavar='',
    103. help='Secret key', required=True)
    104. parser_encode.add_argument('-t', '--cookie-structure', metavar='',
    105. help='Session cookie structure', required=True)
    106. ## create the parser for the decode command
    107. parser_decode = subparsers.add_parser('decode', help='decode')
    108. parser_decode.add_argument('-s', '--secret-key', metavar='',
    109. help='Secret key', required=False)
    110. parser_decode.add_argument('-c', '--cookie-value', metavar='',
    111. help='Session cookie value', required=True)
    112. ## get args
    113. args = parser.parse_args()
    114. ## find the option chosen
    115. if(args.subcommand == 'encode'):
    116. if(args.secret_key is not None and args.cookie_structure is not None):
    117. print(FSCM.encode(args.secret_key, args.cookie_structure))
    118. elif(args.subcommand == 'decode'):
    119. if(args.secret_key is not None and args.cookie_value is not None):
    120. print(FSCM.decode(args.cookie_value,args.secret_key))
    121. elif(args.cookie_value is not None):
    122. print(FSCM.decode(args.cookie_value))

    同样是在linux 下使用

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

     

  • 相关阅读:
    linux系统安装Mysql 快捷方式
    云计算认证哪个好?考什么内容?
    【无标题】
    linux文件相关命令
    Redis最佳实践(上)
    微信小程序登录问题(思路简略笔记)
    恒生Ptrade——盘口扫单功能介绍
    企业级流程平台的全功能链路说明
    Jmeter(五十三) - 从入门到精通高级篇 - 懒人教你在Linux系统中安装Jmeter(详解教程)
    Paimon读取流程
  • 原文地址:https://blog.csdn.net/snowlyzz/article/details/126683978