Tags: sqli web injection 

Rating:

If we download the file, we see that it's a ZIP archive. If we unzip it, we see that it has the source code of the server, Let's look at the source code of the main server source code file, which is `main.py`:
```python3
import sqlite3
from flask import Flask, render_template, render_template_string, redirect, url_for, request

con = sqlite3.connect('data.db', check_same_thread=False)
app = Flask(__name__)

cur = con.cursor()
# comment
cur.execute('''DROP TABLE IF EXISTS pokemon''')
cur.execute('''CREATE TABLE pokemon (names text)''')
cur.execute(
'''INSERT INTO pokemon (names) VALUES ("[FLAG REDACTED]") '''
)

@app.route('/', methods=['GET', 'POST'])
def login():
if request.method == 'POST':

name = request.form['name']

if ("'" in name or "\\" in name or '"' in name):
return render_template('login.html', error="no quotes or backslashes:)")
elif (name == "names"):
return render_template('login.html', error="you are wrong :<")

try:
cur.execute("SELECT * FROM pokemon WHERE names=" + name + "")
except:
render_template('login.html', error="you are wrong :3")



rows = cur.fetchall()


if len(rows) > 0:
return render_template('login.html',
error="Correct! The poekmon was " +
rows[0][0])
else:
return render_template('login.html', error="you are wrong :<")

return render_template('login.html', error="")
```
Now notice that in the `login` method, when we run `cur.execute`, the user input isn't filtered. What this means is that we can send arbitrary commands and expressions to the SQL database.

So the code will execute the sql command `SELECT * FROM pokemon WHERE names=[INSERT USER INPUT]`. Notice how there aren't quotes around `[INSERT USER INPUT]`, so we need something like a number (i.e. `1`) that doesn't need to be wrapped in quotes. But how do we get it so that it returns any data?

Since we don't know what's inside the database, we can `OR` the condition with a always true statement like `1=1` so that the condition will be true. So our payload is `1 OR 1=1`, and when it gets executed the command that's actually executed is `SELECT * FROM pokemon WHERE names=1 OR 1=1`.

When we do this, we get this output:
> Correct! The poekmon was LITCTF{flagr3l4t3dt0pok3m0n0rsom3th1ng1dk}

Notice how it wasn't possible to do it just by guessing random pokemons without quotes (which would arguably count as SQL injection since it's modify the SQL command) because the pokemon was a string but there weren't quotes around it in the SQL command. Finally, we have that the flag is `LITCTF{flagr3l4t3dt0pok3m0n0rsom3th1ng1dk}`.