"Que tal um truque de mágica?" HAHAHAHAHA
BOITA{Xpl01t1ng_Xt3ns10n5}

O desafio começa nos dando uma aplicação web que nos fornece um código de uma extensão que consome a API da aplicação. Sendo o código da aplicação:

from flask import Flask, jsonify, request, render_template, send_file
from flask_cors import CORS
from waitress import serve
import requests, re, os
 
app = Flask(__name__)
CORS(app)
 
def getContent(url):
    try:
        response = requests.get(url)
        if response.status_code == 200:
            return(response.text)
        else:
            print(f"Failed to retrieve content. Status code: {response.status_code}")
    except requests.exceptions.RequestException as e:
        print(f"An error occurred: {e}")
  
@app.route('/api/', methods=['GET'])
def get_template_files():
    template_dir = './shaco/templates'  
    template_files = [f for f in os.listdir(template_dir) if f.endswith('.html')]
    return jsonify(template_files)
  
@app.route('/api/', methods=['POST'])
def post_data():
    url = request.json.get('url')
    content = getContent(url)
    title_match = re.search(r'<title>(.*?)</title>', content, re.IGNORECASE)
  
    if title_match:
        title = title_match.group(1)
    else:
        title = 'null'
 
    fileTitle = re.sub(r' ', '_', title)
    fullPath = f'./shaco/templates/{fileTitle}'
 
  
 
    if os.path.exists(fullPath):
        with open(fullPath, 'r', encoding='utf-8') as file:
            return jsonify({'message': 'File already exist', 'content': file.read()}), 200
    else:
        with open(fullPath+'.html', 'a', encoding='utf-8') as file:
            file.write(content)
            return jsonify({'message': 'File does not existe', 'content': f'File created: {fullPath}'}), 200
            
@app.route("/")
def home():
    return render_template('index.html')
 
@app.route('/file/<file_name>')
def render_html(file_name):
    template_file = f"{file_name}"
    if os.path.exists(os.path.join("./shaco/templates/", template_file)):
        return render_template(template_file)
    else:
        return "File not found", 404
 
@app.route('/shaco')
def download_file():
    file_path = './shaco.zip'
    return send_file(file_path, as_attachment=True)
 
  
if __name__ == '__main__':
    print('[+]Name:   Shaco\n[+]Host:   0.0.0.0\n[+]Port:   80\n[+]Status: Up')
    os.popen("cron &")
    serve(app, host='0.0.0.0', port=80)

É possível perceber que a aplicação pega todas as requisições feitas no endpoint /api, com o parâmetro url e criando um arquivo contendo o conteúdo da página e tendo o titulo da página (contido entre tags de <title>) como nome do arquivo. Em caso que esse arquivo já exista, ele mostrará o conteúdo do arquivo. Entretanto, não existe nenhum tipo de verificação contra ataques do tipo (CWE-35) Path Transversal.

Nesse caso, temos um caso típico de Require Statement in PHP Program (PHP Remote File Inclusion), onde será possível (nesse caso) ler o conteúdo de arquivos em que já temos conhecimento do nome.

Para obter a flag, podemos criar um payload no Pastebin, contendo o seguinte conteúdo:

<title>../../flag.txt</title>

E realizando uma requisição para o endpoint /api com o parâmetro url=[PASTE_BIN_URL], assim, obtendo a flag.

center