
Snipe-IT PoC exploit for CVE-2025-59712 and CVE-2025-59713
Este PoC fornece um script automatizado para explorar CVE-2025-59712 (XSS no cabeçalho User-Agent) e CVE-2025-59713 (desserialização insegura).
Estas duas vulnerabilidades foram descobertas pela Synacktiv durante uma pesquisa de vulnerabilidades no software Snipe-IT. O Snipe-IT é um sistema de gestão de ativos open-source baseado em Laravel, projetado para ajudar organizações a rastrear e gerir seus ativos físicos e digitais.
Um artigo técnico pode ser encontrado no aviso de segurança dedicado no site da Synacktiv.
Este script fornece três subcomandos, correspondentes aos modos de exploração: xss, rce e fullchain.
Este subcomando explora a CVE-2025-59712, que permite a um utilizador com privilégios reduzidos injetar JavaScript arbitrário na página HTML renderizada ao aceder à rota /reports/activity. Isto só pode ser feito por um administrador ou por um utilizador com permissões explícitas de visualização de relatórios. A injeção é possível devido à sanitização inadequada do campo User-Agent quando um utilizador atualiza as suas informações de perfil.
Para isso, fará primeiro login como o utilizador com privilégios reduzidos e depois injetará o código JavaScript definido no ficheiro fornecido através da flag --javascript.
$ python3 exploit.py xss --help
Usage: exploit.py xss [OPTIONS]
Execute XSS attack only with custom JavaScript payload
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ * --url -u TEXT Target Snipe-IT URL [required] │
│ * --login -l TEXT Low-privileged username [required] │
│ * --password -p TEXT Low-privileged password [required] │
│ * --new-name -n TEXT New name for low-privileged user [required] │
│ * --javascript -js TEXT Path to custom JavaScript file [required] │
│ --proxy -x TEXT HTTP proxy (http://ip:port) │
│ --verbose -v [quiet|normal|verbose] Logging verbosity [default: normal] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
[!IMPORTANTE]
Durante a pesquisa de segurança, os testes foram realizados numa versão do Snipe-IT que, por predefinição, exibia o campoUser-Agentno qual o JavaScript malicioso é injetado. Desde o commit 10e5d88, a propriedadeUser-Agentnão é exibida por predefinição quando a tabela de registo de ações é renderizada. O administrador que irá acionar o XSS precisa, portanto, de ter marcado a caixaUser-Agentnas opções de visualização para versões do Snipe-IT posteriores a este commit.
Este subcomando explora a CVE-2025-59713, que permite execução remota de código quando são conhecidas as credenciais de um administrador ou superadministrador. Para tal, são executados os seguintes passos:
db-dumps/mysql-snipeit.sql, que criam um novo campo personalizado e editam o último registo de ação com um objeto JSON contendo a cadeia de pop do Laravel durante a restauração.[!DICA] Por predefinição, o Snipe-IT inclui o ficheiro
.envna cópia de segurança. Se o script o detetar, o valor deAPP_KEYé exibido e o ficheiro.envé guardado no diretório./output(pode ser especificada uma localização personalizada para esse ficheiro com--output-dir).
[!CUIDADO] Restaurar uma cópia de segurança desconecta todos os utilizadores ligados à instância.
/api/v1/reports/activity é chamada, o que aciona a desserialização e executa a cadeia de pop do Laravel.$ python3 exploit.py rce --help
Usage: exploit.py rce [OPTIONS]
Execute RCE attack only (requires existing admin account)
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ * --url -u TEXT Target Snipe-IT URL [required] │
│ * --admin-user -au TEXT Admin username [required] │
│ * --admin-pass -ap TEXT Admin password [required] │
│ --output-dir -od PATH Output dir for .env file [default: /home/ninja/Téléchargements/snipe-it-advisory/exploit/output] │
│ --shell-ip -si TEXT Reverse shell IP address │
│ --shell-port -sp INTEGER Reverse shell port │
│ --command -c TEXT Custom command (overrides reverse shell) │
│ --proxy -x TEXT HTTP proxy (http://ip:port) │
│ --verbose -v [quiet|normal|verbose] Logging verbosity [default: normal] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
O subcomando fullchain tem como objetivo encadear ambas as vulnerabilidades XSS e RCE. Corresponde a um cenário em que apenas tem acesso a um utilizador com privilégios reduzidos e pretende obter execução remota de código. Isto só funcionará se o utilizador que visitar a página /reports/activity for um administrador ou superadministrador. De facto, apenas estes papéis têm direitos para criar e restaurar uma cópia de segurança, o que é necessário para envenenar a base de dados e acionar posteriormente a cadeia de pop do Laravel.
Para isso, o script irá:
--command, tal como no modo RCE).User-Agent com uma tag <script> para forçar o navegador da vítima a carregar o modelo JavaScript malicioso./reports/activity, o XSS é acionado e o JavaScript malicioso é carregado e executado pelo navegador da vítima. A partir daí, são executados os mesmos passos que no módulo RCE, mas em JavaScript.Este modo utiliza várias bibliotecas JavaScript adicionais, todos os créditos vão para os seus respetivos autores:
$ python3 exploit.py fullchain --help
Usage: exploit.py fullchain [OPTIONS]
Execute full attack chain: XSS -> Backup manipulation -> RCE
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ * --url -u TEXT Target Snipe-IT URL [required] │
│ * --login -l TEXT Low-privileged user's username [required] │
│ * --password -p TEXT Low-privileged user's password [required] │
│ * --new-name -n TEXT New name for low-privileged user [required] │
│ --ip -i TEXT HTTP server IP address (default: auto-detect) │
│ * --port -P INTEGER HTTP server port [required] │
│ --admin-user -au TEXT Admin username to create [default: admin_rce] │
│ --admin-pass -ap TEXT Admin password to create [default: password123] │
│ --shell-ip -si TEXT Reverse shell IP address │
│ --shell-port -sp INTEGER Reverse shell port │
│ --command -c TEXT Custom command (overrides reverse shell) │
│ --proxy -x TEXT HTTP proxy (http://ip:port) │
│ --verbose -v [quiet|normal|verbose] Logging verbosity [default: normal] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Para executar este script, execute os seguintes comandos:
$ git clone https://github.com/synacktiv/CVE-2025-59712_CVE-2025-59713
$ cd CVE-2025-59712_CVE-2025-59713
$ python3 -m venv .venv && source .venv/bin/activate
$ python3 -m pip install -r requirements.txt
Também é fornecido um Dockerfile para experimentar o script e reproduzir a exploração da vulnerabilidade. Ele puxa uma versão vulnerável do Snipe-IT, configura a base de dados com php artisan e define dois utilizadores:
admin com uma palavra-passe predefinida AdminPassword123!lowpriv com uma palavra-passe predefinida LowPrivUser123!Antes de executar o contentor, os ficheiros .env e snipe-it.conf precisam de ser atualizados com o URL da instância Snipe-IT:
$ sed -i 's|^APP_URL=.*|APP_URL=http://<IP>:<PORT>|' .env
$ sed -i 's|\(ServerName\s*\).*|\1http://<IP>:<PORT>|' snipe-it.conf
O contentor pode então ser executado:
$ docker build . -t "snipe-it-cve"
$ docker run -p 80:80 --name "snipe-it-debian" snipe-it-cve:latest