A flaw was found in MRTG. When the MRTG daemon is started as a root user and subsequently drops privileges, a local, low-privileged attacker can exploit a symbolic link (symlink) following vulnerability. By influencing or pre-placing a symlink in the process ID (PID) file path, the attacker can trick the root process into changing the ownership of an arbitrary existing file to the daemon user. This can lead to local privilege escalation, allowing unauthorized access to or modification of sensitive files.
AI_ONLY_REPORT
package: mrtg-2.17.10-12.el10
------
Summary: Symlink-based arbitrary file clobber/chown via --pid-file when run
as root in daemon mode: MRTG creates and `chown`s the PID file before
dropping privileges, allowing an attacker who can influence or pre-place
the PID path to make root follow a symlink and transfer ownership of an
arbitrary existing file to the daemon user; the accompanying `create_pid()`
logic also carries limited TOCTOU / non-existent-target clobber risk.
Requirements to exploit: The attacker needs local low-privileged access on
the target and a deployment where MRTG is started as root with `--daemon`
and later drops privileges to another user. The attacker must be able to
influence the PID file path, control the config-derived PID path, or
pre-place a symlink at that path in a writable location before startup.
This issue is not remotely reachable, and starts that already execute MRTG
as an unprivileged user do not expose the root-side `chown` primitive.
Component affected: MRTG daemon startup logic in `bin/mrtg.socket6` and
`lib/mrtg2/MRTG_lib.pm` (the same pre-drop PID-file logic is also present
in `bin/mrtg`)
Version affected: 2.17.10-12.el10 (confirmed in the available source
checkout). The full upstream introduction range is unknown from the
available history; in the local clone, the pre-drop `create_pid()` +
`chown` block is present from commit `2ca68627078a..HEAD`, while the unsafe
`create_pid()` pattern is present from base commit `767bce1636bc..HEAD`.
Patch available: no
Version fixed (if any already): unknown
Upstream coordination: Not yet notified. The source material includes a
draft disclosure email to the MRTG maintainers.
CVSS: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N - 7.1 (HIGH)
AV:L - Local access to the affected host is required.
AC:L - Once MRTG is started as root in an affected daemon deployment and
the attacker can control or pre-place the PID path, exploitation is
straightforward.
PR:L - Low privileges are needed to control a writable PID path or plant
the symlink in affected setups.
UI:N - No additional user interaction is required after the vulnerable
service start.
S:U - The vulnerable code and impacted files are within the same
operating-system security scope.
C:H - Ownership takeover of a sensitive file can expose data that
should remain root-only.
I:H - Ownership takeover of a sensitive file can allow direct
modification and privilege escalation.
A:N - The primary demonstrated primitive is file ownership takeover;
direct availability impact is secondary and configuration-dependent.
Impact: Important. In affected root-start daemon deployments, this is a
local privilege-escalation / file-ownership-takeover issue: a
low-privileged local attacker who can influence or pre-place the PID file
path can make root `chown` an arbitrary existing file to the daemon user
before privileges are dropped. The issue is narrower than a generic local
root exploit because it depends on root-started daemon mode and attacker
control over the PID path, but the resulting confidentiality and integrity
impact can still be high.
Embargo: yes
Reason: This is a plausible local privilege-escalation issue in a
supported daemon-start path, and no upstream fix is known from the source
material. Coordinated disclosure is preferable so PID-file handling can be
corrected before publication.
Acknowledgement: Aisle Research
Steps to reproduce:
1. Prepare a root-owned target file and a symlinked PID path:
```bash
sudo rm -f /tmp/mrtg.pid /tmp/owned_by_root
sudo touch /tmp/owned_by_root
sudo chown root:root /tmp/owned_by_root
ln -s /tmp/owned_by_root /tmp/mrtg.pid
```
2. Start MRTG as root in daemon mode, dropping privileges:
```bash
sudo /usr/bin/mrtg --daemon --pid-file=/tmp/mrtg.pid --user=nobody
/etc/mrtg/mrtg.cfg
```
3. Verify ownership of the symlink target changed:
```bash
ls -l /tmp/owned_by_root
```
4. Expected result: the target file becomes owned by `nobody` (or the
selected drop user/group), confirming that root followed the symlink during
the pre-drop `chown`.
Mitigation:
Do not start MRTG as root with `--daemon` unless it is strictly
necessary; prefer starting it directly as the intended service user.
Do not place the PID file in attacker-writable locations and do not allow
untrusted users to influence `--pid-file` or the config-derived PID path.
Keep any PID-file directory root-owned and not writable by unprivileged
users if root startup is unavoidable.
Refuse symlinks for PID files and create them securely with `sysopen(...,
O_WRONLY|O_CREAT|O_EXCL, 0644)` or equivalent.
Prefer creating the PID file only after privileges have been dropped.
Vulnerability details:
```perl
bin/mrtg.socket6
if (defined $opts{"daemon"}) {
Create a pidfile, then chown it so we can use it once we change user
&create_pid($pidfile);
chown $uid, $gid, $pidfile;
}
($(,$)) = ($gid,$gid);
($<,$>) = ($uid,$uid);
```
```perl
lib/mrtg2/MRTG_lib.pm
sub create_pid ($) {
my $pidfile = shift;
return if ($OS eq 'NT' );
return if -e $pidfile;
if ( open(PIDFILE,">$pidfile")) {
close PIDFILE;
}
}
```
The most reliable demonstrated primitive is symlink-following `chown` on an
existing target file. The `create_pid()` `-e`/`open(">...")` sequence is
still unsafe and introduces TOCTOU / non-existent-target clobber risk, but
direct clobber of an already existing file is not the primary demonstrated
behavior because of the `-e` guard.
Most relevant CWEs:
CWE-59: Improper Link Resolution Before File Access
CWE-367: Time-of-check Time-of-use race condition
Proposed fix:
```diff
diff --git a/bin/mrtg.socket6 b/bin/mrtg.socket6
@@
if (defined $opts{"daemon"}) {
# Create a pidfile, then chown it so we can use it once we change
user
&create_pid($pidfile);
chown $uid, $gid, $pidfile;
}
+ # Do not create/chown pidfile as root on user-influenced path.
diff --git a/bin/mrtg b/bin/mrtg
@@
if (defined $opts{"daemon"}) {
# Create a pidfile, then chown it so we can use it once we change
user
&create_pid($pidfile);
chown $uid, $gid, $pidfile;
}
+ # Do not create/chown pidfile as root on user-influenced path.
diff --git a/lib/mrtg2/MRTG_lib.pm b/lib/mrtg2/MRTG_lib.pm
@@
+use Fcntl qw(O_WRONLY O_CREAT O_EXCL);
@@
sub create_pid ($) {
my $pidfile = shift;
return if ($OS eq 'NT' );
return if -e $pidfile;
if ( open(PIDFILE,">$pidfile")) {
close PIDFILE;
} else {
warn "cannot write to $pidfile: $!\n";
}
+ if (lstat($pidfile)) {
+ die "Refusing symlink pid file: $pidfile\n" if -l _;
+ return;
+ }
+ sysopen(my $fh, $pidfile, O_WRONLY|O_CREAT|O_EXCL, 0644)
+ or die "cannot securely create pid file $pidfile: $!\n";
+ close($fh) or die "cannot close pid file $pidfile: $!\n";
}
```
------
This report was generated using AI technology. Always review AI-generated
content prior to use
AI_ONLY_REPORT package: mrtg-2.17.10-12.el10 ------ Summary: Symlink-based arbitrary file clobber/chown via --pid-file when run as root in daemon mode: MRTG creates and `chown`s the PID file before dropping privileges, allowing an attacker who can influence or pre-place the PID path to make root follow a symlink and transfer ownership of an arbitrary existing file to the daemon user; the accompanying `create_pid()` logic also carries limited TOCTOU / non-existent-target clobber risk. Requirements to exploit: The attacker needs local low-privileged access on the target and a deployment where MRTG is started as root with `--daemon` and later drops privileges to another user. The attacker must be able to influence the PID file path, control the config-derived PID path, or pre-place a symlink at that path in a writable location before startup. This issue is not remotely reachable, and starts that already execute MRTG as an unprivileged user do not expose the root-side `chown` primitive. Component affected: MRTG daemon startup logic in `bin/mrtg.socket6` and `lib/mrtg2/MRTG_lib.pm` (the same pre-drop PID-file logic is also present in `bin/mrtg`) Version affected: 2.17.10-12.el10 (confirmed in the available source checkout). The full upstream introduction range is unknown from the available history; in the local clone, the pre-drop `create_pid()` + `chown` block is present from commit `2ca68627078a..HEAD`, while the unsafe `create_pid()` pattern is present from base commit `767bce1636bc..HEAD`. Patch available: no Version fixed (if any already): unknown Upstream coordination: Not yet notified. The source material includes a draft disclosure email to the MRTG maintainers. CVSS: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N - 7.1 (HIGH) AV:L - Local access to the affected host is required. AC:L - Once MRTG is started as root in an affected daemon deployment and the attacker can control or pre-place the PID path, exploitation is straightforward. PR:L - Low privileges are needed to control a writable PID path or plant the symlink in affected setups. UI:N - No additional user interaction is required after the vulnerable service start. S:U - The vulnerable code and impacted files are within the same operating-system security scope. C:H - Ownership takeover of a sensitive file can expose data that should remain root-only. I:H - Ownership takeover of a sensitive file can allow direct modification and privilege escalation. A:N - The primary demonstrated primitive is file ownership takeover; direct availability impact is secondary and configuration-dependent. Impact: Important. In affected root-start daemon deployments, this is a local privilege-escalation / file-ownership-takeover issue: a low-privileged local attacker who can influence or pre-place the PID file path can make root `chown` an arbitrary existing file to the daemon user before privileges are dropped. The issue is narrower than a generic local root exploit because it depends on root-started daemon mode and attacker control over the PID path, but the resulting confidentiality and integrity impact can still be high. Embargo: yes Reason: This is a plausible local privilege-escalation issue in a supported daemon-start path, and no upstream fix is known from the source material. Coordinated disclosure is preferable so PID-file handling can be corrected before publication. Acknowledgement: Aisle Research Steps to reproduce: 1. Prepare a root-owned target file and a symlinked PID path: ```bash sudo rm -f /tmp/mrtg.pid /tmp/owned_by_root sudo touch /tmp/owned_by_root sudo chown root:root /tmp/owned_by_root ln -s /tmp/owned_by_root /tmp/mrtg.pid ``` 2. Start MRTG as root in daemon mode, dropping privileges: ```bash sudo /usr/bin/mrtg --daemon --pid-file=/tmp/mrtg.pid --user=nobody /etc/mrtg/mrtg.cfg ``` 3. Verify ownership of the symlink target changed: ```bash ls -l /tmp/owned_by_root ``` 4. Expected result: the target file becomes owned by `nobody` (or the selected drop user/group), confirming that root followed the symlink during the pre-drop `chown`. Mitigation: Do not start MRTG as root with `--daemon` unless it is strictly necessary; prefer starting it directly as the intended service user. Do not place the PID file in attacker-writable locations and do not allow untrusted users to influence `--pid-file` or the config-derived PID path. Keep any PID-file directory root-owned and not writable by unprivileged users if root startup is unavoidable. Refuse symlinks for PID files and create them securely with `sysopen(..., O_WRONLY|O_CREAT|O_EXCL, 0644)` or equivalent. Prefer creating the PID file only after privileges have been dropped. Vulnerability details: ```perl bin/mrtg.socket6 if (defined $opts{"daemon"}) { Create a pidfile, then chown it so we can use it once we change user &create_pid($pidfile); chown $uid, $gid, $pidfile; } ($(,$)) = ($gid,$gid); ($<,$>) = ($uid,$uid); ``` ```perl lib/mrtg2/MRTG_lib.pm sub create_pid ($) { my $pidfile = shift; return if ($OS eq 'NT' ); return if -e $pidfile; if ( open(PIDFILE,">$pidfile")) { close PIDFILE; } } ``` The most reliable demonstrated primitive is symlink-following `chown` on an existing target file. The `create_pid()` `-e`/`open(">...")` sequence is still unsafe and introduces TOCTOU / non-existent-target clobber risk, but direct clobber of an already existing file is not the primary demonstrated behavior because of the `-e` guard. Most relevant CWEs: CWE-59: Improper Link Resolution Before File Access CWE-367: Time-of-check Time-of-use race condition Proposed fix: ```diff diff --git a/bin/mrtg.socket6 b/bin/mrtg.socket6 @@ if (defined $opts{"daemon"}) { # Create a pidfile, then chown it so we can use it once we change user &create_pid($pidfile); chown $uid, $gid, $pidfile; } + # Do not create/chown pidfile as root on user-influenced path. diff --git a/bin/mrtg b/bin/mrtg @@ if (defined $opts{"daemon"}) { # Create a pidfile, then chown it so we can use it once we change user &create_pid($pidfile); chown $uid, $gid, $pidfile; } + # Do not create/chown pidfile as root on user-influenced path. diff --git a/lib/mrtg2/MRTG_lib.pm b/lib/mrtg2/MRTG_lib.pm @@ +use Fcntl qw(O_WRONLY O_CREAT O_EXCL); @@ sub create_pid ($) { my $pidfile = shift; return if ($OS eq 'NT' ); return if -e $pidfile; if ( open(PIDFILE,">$pidfile")) { close PIDFILE; } else { warn "cannot write to $pidfile: $!\n"; } + if (lstat($pidfile)) { + die "Refusing symlink pid file: $pidfile\n" if -l _; + return; + } + sysopen(my $fh, $pidfile, O_WRONLY|O_CREAT|O_EXCL, 0644) + or die "cannot securely create pid file $pidfile: $!\n"; + close($fh) or die "cannot close pid file $pidfile: $!\n"; } ``` ------ This report was generated using AI technology. Always review AI-generated content prior to use