
Prova de conceito local segura para a vulnerabilidade de injeção de objeto PHP no Cotonti CommentsWidget (CAN-2026-2035973 / CVE-2026-71294).
Prova de conceito local segura para o problema de injeção de objeto PHP identificado na implementação do CommentsWidget do Cotonti.
plugins/comments/inc/CommentsWidget.phpO caminho de código vulnerável aceita o parâmetro GET ci e passa dados controlados pelo atacante através de base64_decode() para o unserialize() do PHP sem restringir quais classes podem ser instanciadas.
Conceitualmente, a operação vulnerável é:
$ci = @unserialize(base64_decode($ci));
Quando um objeto serializado é fornecido, o PHP pode instanciar a classe controlada pelo atacante e invocar métodos mágicos como . Em uma aplicação maior, isso pode se tornar perigoso quando classes gadget adequadas estão disponíveis.
__wakeup()A correção submetida altera a desserialização para:
$ci = @unserialize(base64_decode($ci), ['allowed_classes' => false]);
e valida que o valor resultante possui a estrutura de array esperada antes de usá-lo.
poc.php realiza três testes locais:
unserialize() sem restrições instancia DangerousGadget e dispara seu método __wakeup().allowed_classes => false impede que a classe gadget seja instanciada e, portanto, previne o efeito colateral do __wakeup().O PoC usa /tmp/pwned_by_cotonti_poc.txt apenas como um sentinela inofensivo mostrando que __wakeup() foi executado. Ele não executa um comando do sistema operacional. A string id && whoami existe apenas como um valor placeholder na propriedade command do gadget.
serialize() / unserialize()Nenhuma instalação do Cotonti é necessária porque o comportamento de desserialização vulnerável e corrigido é reproduzido diretamente.
A partir do diretório do repositório:
php poc.php
A saída esperada é semelhante a:
[!] DangerousGadget::__wakeup() triggered
[TEST 1] VULNERABLE: __wakeup() executed during unrestricted unserialize().
[TEST 2] FIXED: object instantiation was blocked; no sentinel was created.
[TEST 3] FIXED: invalid serialized structure rejected by validation.
Summary:
- Vulnerable path allows a serialized attacker-controlled object to be instantiated and invokes __wakeup().
- Fixed path uses allowed_classes=false, preventing the gadget class from being instantiated.
- Structural validation rejects values that do not match the expected array shape.
- No real command execution is performed by this PoC; the command property is only a placeholder.
O script remove seu arquivo sentinela antes de encerrar.
Não desserialize dados controlados pelo atacante com o unserialize() do PHP sem restrições.
Para este caminho de código, a mitigação demonstrada é desabilitar a instanciação de classes:
unserialize($data, ['allowed_classes' => false]);
O valor desserializado também deve ser validado em relação à estrutura exata esperada pela aplicação antes que seu conteúdo seja usado.
Este repositório destina-se a pesquisa de segurança, verificação e testes defensivos. Execute o PoC apenas em ambientes que você possui ou está explicitamente autorizado a testar. Não o use para atacar sistemas sem permissão.
Harsh Raj Singhania — pesquisa de vulnerabilidade, prova de conceito e divulgação.