Consegui parte do código de uma aplicação que eu sei que esta rodando em https://socketfeaver-7jktu72cma-uc.a.run.app/, sera que consigo fazer algo com isso?
BOITA{f4_S2_55t1}
Primeiramente, ao entrar no site podemos se deparar com a seguinte aplicação:
E o código da aplicação sendo:
import sqlite3, random
from flask import Flask, render_template, render_template_string, redirect, request, session
from waitress import serve
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.secret_key = 'slakjkjkj'
socketio = SocketIO(app)
def AntiSqli(login, senha):
blacklist = ["'", "-", '"']
if login != '' and senha != '':
for char in blacklist:
if char in login or char in senha:
return 1
else:
pass
return 0
else:
return 1
def loginApp(login, senha):
protect = AntiSqli(login, senha)
if protect == 0:
banco = sqlite3.connect('f4ctf.db')
cursor = banco.cursor()
cursor.execute(f"SELECT * FROM users WHERE nome = '{login}' AND senha = '{senha}'")
if cursor.fetchall() != []:
return 0
else:
return 1
else:
return 1
def registerApp(login, senha, nickname):
banco = sqlite3.connect('f4ctf.db')
cursor = banco.cursor()
cursor.execute(f"SELECT * FROM users WHERE nome = '{login}' AND senha = '{senha}'")
if cursor.fetchall() == []:
cursor.execute(f"INSERT INTO users(nome, senha, nickname) VALUES ('{login}', '{senha}', '{nickname}')")
banco.commit()
return 0
else:
return 1
@app.route('/')
def welcome():
return redirect('/login')
@app.route('/<alo>')
def alo(alo):
try:
if ('user' in session and session['user'] == username):
return ''
else:
nmr = (random.randint(99999,9999999))
return render_template('notfound.html', saida=nmr)
except:
nmr = (random.randint(99999,9999999))
return render_template('notfound.html', saida=nmr)
@app.route('/register', methods=['GET', 'POST'])
def register():
global username
if request.method == 'POST':
try:
username = request.form['username']
password = request.form['password']
nickname = request.form['nickname']
if registerApp(username, password, nickname) == 0:
session['nickname'] = nickname
return redirect('/login')
else:
pass
except:
return render_template('register.html')
return render_template('register.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
global username
if request.method == 'POST':
try:
username = request.form['username']
password = request.form['password']
banco = sqlite3.connect('./f4ctf.db')
cursor = banco.cursor()
cursor.execute(f"SELECT * FROM users WHERE nome = '{username}'")
result = cursor.fetchall()
if loginApp(username, password) == 0:
session['user'] = username
session['nickname'] = str(result[0][2])
return redirect('/chat')
else:
pass
except:
return render_template('index.html')
return render_template('index.html')
@app.route('/chat', methods=['GET', 'POST'])
def chat():
try:
if ('user' in session and session['user'] == username):
nick = render_template_string(session['nickname'])
return render_template('socket.html', uname=nick)
else:
nmr = (random.randint(99999,9999999))
return render_template('notfound.html', saida=nmr)
except Exception as error:
print(error)
nmr = (random.randint(99999,9999999))
return render_template('notfound.html', saida=nmr)
@socketio.on('username')
def handle_message(data):
socketio.username = data
@socketio.on('message')
def handle_message(data):
emit('message', {'username': socketio.username, 'message': data}, broadcast=True)
@app.route('/logout', methods=['GET'])
def logout():
try:
if ('user' in session and session['user'] == username):
resp = redirect('/login')
resp.delete_cookie("session")
return resp
else:
pass
except:
nmr = (random.randint(99999,9999999))
return render_template('notfound.html', saida=nmr)
if __name__ == '__main__':
print('[+]Name: SocketFeaver\n[+]Host: 0.0.0.0\n[+]Port: 80\n[+]Status: Up')
serve(app, host='0.0.0.0', port=80)
Em uma primeira análise, podemos descartar a possibilidade de ataques do tipo (CWE-89) SQL Injection nos campo de login. E, após executar testes automatizados utilizando o SQLMap nos parâmetros de inscrição, percebemos que todos os parâmetros são falsos-positivos.
Dessa maneira, somos obrigados a procurar outro ponto de exploração nessa aplicação.
Criando uma conta nesse sistema, podemos perceber que o parâmetro nickname
reflete diretamente na página após o login:
Juntando o fato de que temos uma aplicação construída em Python sobre o framework Flask, há uma grande desconfiança que possa existir algum tipo de (CWE-1336) Server-Side Template Injection (SSTI) nessa plataforma. Assim, para testar, iremos criar uma nova conta com o nickname {{ 7*7 }}
.
É notório agora que temos um (CWE-1336) Server-Side Template Injection (SSTI). Podemos então inserir um payload malicioso para ler o conteúdo da flag. O payload que usaremos será:
{{request.application.__globals__.__builtins__.__import__("os").popen("cat flag.txt").read()}}
O payload funciona da seguinte forma:
- Ele pega o atributo global do
flask
application
- Desse atributo, ele pega o atributo global do Python
__globals__
- Desse atributo, ele chamada os builtins do Python com
__builtins__
- Esse atributo, por sua vez, importa a biblioteca
os
- É chamada a função
popen
para conseguir um Arbitrary Command Execution - O conteúdo do comando é lido pelo método
read()
E assim, conseguimos pegar a flag em questão.