COMMAND
klogd
SYSTEMS AFFECTED
Linux with klogd 1.3-22...25...29
PROBLEM
Michal Zalewski found following buffer overflow in Linux klogd
daemon from sysklogd-1.3 package (up to release 22 - affects Red
Hat 5.x and Slackware 3.x, no data about other distributions).
This does appear to affect a (fairly) stock RH5.2 box also. In
tests, the supplied module code did cause klogd to die... So,
This problem is also present in klogd 1.3-25 which ships with
RedHat 5.2.
Kernel messages are stored in 4 kB cyclic printk ring. Klogd reads
this buffer using /proc/kmsg to 4 kB long buffer, that's good.
But then, data is split into lines, by copying data until '\n' is
reached. What a pity, line buffer is only 1 kB long - sometimes,
it's not enough... Exploitable? Could be... To exploit this
security hole, we have to generate very long kernel message (or a
lot of short messages with no '\n' inside). There are two
potential ways of doing this:
a) In kernel source (or any of installed modules), find printk not
terminated with '\n'. There are some old, obscure messages both
in 2.0.xx and 2.1.xxx. Yep, but what now? You have to generate
it :-S It's especially easy when poking with strange network
packets (so it's possible to perform remote DoS attack).
Unfortunately, DoS if probably all you can do - enjoy SEGV in
klogd daemon, or (better?), by overwriting fd to /proc/kmsg
lyingo on the stack, increase LA and generate enormous amount
of error messages like 'Cannot read /proc filesystem',
apparently from kernel.
b) ...or, in kernel (2.1.xxx is more interesting), locate any
printk with %s in format string, where substituted string
depends in some way on luser (process/filename?). Then, you
should be able to parse arbitrary shellcode into buffer,
obtaining root privledges.
Quick vunerability test:
-- gcc -c -O3 test.c; insmod test; rmmod test --
#define MODULE
#define __KERNEL__
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/malloc.h>
#include <asm/unistd.h>
#include <linux/version.h>
#include <asm/string.h>
int init_module(void) {
printk("INSERT_ABOUT_2000_BYTES_OF_JUNK_HERE\n"); return 0;
}
void cleanup_module(void) {}
Modify this source by increasing amount of junk after printk,
compile, insmod and watch out what happened to klogd.
SOLUTION
This bug was fixed *two* years ago, but some Linuxes are still
shipping vulnerable old versions. Please upgrade. Additionally
the most recent stable version may also be found on SunSITE at:
ftp://sunsite.unc/edu/pub/Linux/system/daemons/
In klog.c, at the beginning, there are two '#define's. First one
is responsible for main buffer size - don't change it, 4096
should be ok. The next one is line buffer size - hmm, replace
1024 with 4096, for example... Or, better, implement some range
checking.
Here's some range checking that will patch to the latest versions:
--- klogd.c.orig Wed Nov 11 12:47:16 1998
+++ klogd.c Wed Nov 11 13:03:20 1998
@@ -465,6 +465,11 @@
if ( index == 0 )
memset(line, '\0', sizeof(line));
+
+ if (len >= sizeof(line)) {
+ len = sizeof (line) - 1;
+ *(ptr + len) = '\0';
+ }
while (len) {
nl = strpbrk(ptr, "\r\n"); /* Find first line terminator */
RedHat immediately issued a "fix" to their current package:
sysklogd-1.3-26. This "fix" is merely patch by Cory Visi. His
patch does not fix the problem. The the bug is fixed in the
latest sysklogd package (1.3-30). In fact, the bug was fixed in
1996. What this comes down to is that any Linux distribution
running an old sysklogd package (namely RedHat all versions)
still has a potential (rather obscure) buffer overflow. They need
to upgrade to the latest version ASAP.