Summary
The /monitor/run_test/ API endpoint in spug v3.4.0 passes a user-supplied monitor address directly into a shell command without sanitization. When the monitor type is 5 (ping), the value is interpolated into ping -c 1 -W 3 {addr} and executed with shell=True. An authenticated user holding the monitor.monitor.add or monitor.monitor.edit permission can inject shell metacharacters to execute arbitrary OS commands on the spug server, bypassing all host-level access controls.
Technical detail
Vulnerable function (spug_api/apps/monitor/executors.py):
def ping_check(addr):
if platform.system().lower() == 'windows':
command = f'ping -n 1 -w 3000 {addr}'
else:
command = f'ping -c 1 -W 3 {addr}'
task = subprocess.run(command, shell=True, stdout=subprocess.PIPE)
if task.returncode == 0:
return True, 'Ping检测正常'
else:
return False, 'Ping检测失败'
addr is directly interpolated into the shell command string with no escaping or validation.
Call path (spug_api/apps/monitor/views.py, line 97–107):
@auth('monitor.monitor.add|monitor.monitor.edit')
def run_test(request):
form, error = JsonParser(
Argument('type', help='请选择监控类型'),
Argument('targets', type=list, filter=lambda x: len(x), help='请输入监控地址'),
Argument('extra', required=False)
).parse(request.body)
if error is None:
is_success, message = dispatch(form.type, form.targets[0], form.extra)
return json_response({'is_success': is_success, 'message': message})
form.targets[0] comes directly from the JSON request body. When form.type == '5', dispatch calls ping_check(form.targets[0]) — no validation occurs between the request and the shell invocation.
The monitor.monitor.add permission is routinely granted to operations staff who need to configure health checks, as opposed to the admin superuser role. This means a non-administrator authenticated user with this standard operational permission can achieve OS-level code execution on the spug management server.
Proof of Concept
(available upon request)
Impact
An authenticated user with the monitor.monitor.add or monitor.monitor.edit permission — a common operational permission not restricted to administrators — can execute arbitrary OS commands as the spug process user. The spug server holds:
- SSH private keys for all managed servers (in the database and
AppSetting)
- Database credentials and application secrets
- Full access to all deployed application configurations
Exploitation escalates privilege from "operations staff with monitor permissions" to "full control of the spug management server and all servers it manages."
Remediation
Replace the shell-based ping with a safe equivalent that does not use shell=True:
import subprocess, platform, ipaddress, socket
def ping_check(addr):
# Validate addr is a hostname or IP before constructing the command
args = ['-n', '1', '-w', '3000'] if platform.system().lower() == 'windows' else ['-c', '1', '-W', '3']
try:
task = subprocess.run(
['ping'] + args + [addr], # no shell=True; each arg is a separate element
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=10
)
return task.returncode == 0, 'Ping检测正常' if task.returncode == 0 else 'Ping检测失败'
except Exception as e:
return False, f'异常信息:{e}'
Passing addr as a list element to subprocess.run (without shell=True) prevents shell interpretation entirely, regardless of the content of addr.
Summary
The
/monitor/run_test/API endpoint in spug v3.4.0 passes a user-supplied monitor address directly into a shell command without sanitization. When the monitor type is5(ping), the value is interpolated intoping -c 1 -W 3 {addr}and executed withshell=True. An authenticated user holding themonitor.monitor.addormonitor.monitor.editpermission can inject shell metacharacters to execute arbitrary OS commands on the spug server, bypassing all host-level access controls.Technical detail
Vulnerable function (
spug_api/apps/monitor/executors.py):addris directly interpolated into the shell command string with no escaping or validation.Call path (
spug_api/apps/monitor/views.py, line 97–107):form.targets[0]comes directly from the JSON request body. Whenform.type == '5',dispatchcallsping_check(form.targets[0])— no validation occurs between the request and the shell invocation.The
monitor.monitor.addpermission is routinely granted to operations staff who need to configure health checks, as opposed to theadminsuperuser role. This means a non-administrator authenticated user with this standard operational permission can achieve OS-level code execution on the spug management server.Proof of Concept
(available upon request)
Impact
An authenticated user with the
monitor.monitor.addormonitor.monitor.editpermission — a common operational permission not restricted to administrators — can execute arbitrary OS commands as the spug process user. The spug server holds:AppSetting)Exploitation escalates privilege from "operations staff with monitor permissions" to "full control of the spug management server and all servers it manages."
Remediation
Replace the shell-based ping with a safe equivalent that does not use
shell=True:Passing
addras a list element tosubprocess.run(withoutshell=True) prevents shell interpretation entirely, regardless of the content ofaddr.