Rýchla oprava lokálnej vmsplice() zraniteľnosti
Autor:
Ondrej Jombík
| Sekcia:
Administrácia
| Dátum: 2008-02-12
Základné info
Dňa 8. februára 2008 bola publikovaná lokálna zraniteľnosť Linuxového systému pre jadrá od 2.6.1 až po jadro 2.6.24. Chyba v systémovom volaní vmsplice() umožňuje lokálnemu používateľovi (potenciálnemu útočníkovi) prostredníctvom dostupného exploitu získať administrátorské práva na systéme.
Naša skupina Platon Group pre vás pripravila rýchlu opravu tejto vážnej zraniteľnosti. Oprava spočíva v úplnom vypnutí systémového volania vmsplice() prostredníctvom modulu, ktorý je možné vykompilovať voči aktuálnemu jadru. Nie je teda nutná rekompilácia jadra ani reštart systému!
Modul, okrem blokovania volania vmsplice() , loguje každé volanie do kernel logu. Z toho je možné zistiť, či niektorá aplikácia toto volanie používa, alebo či sa niektorí z lokálnych používateľov pokúsil o spustenie exploitu a získanie administrátorských práv.
Takto vyzerá príklad nainštalovania modulu a logovania aktivity vmsplice() :
vmsplice-EPERM.c Linux Kernel 2.6 module by Ondrej Jombik <nepto@platon.sk>
vmsplice-EPERM.c disables vmsplice() syscall for preventing local root vulnearbility
vmsplice-EPERM.c: searching for syscall table
vmsplice-EPERM.c: syscall table found at c03fc540
vmsplice-EPERM.c module installed
vmsplice-EPERM.c call attempt: fd=4, iov=bff720b8, nr_segs=1, flags=0; forcing -EPERM
Stiahnutie a inštalácia
Zdrojové kódy modulu do jadra sú dostupné na tejto adrese:
http://platon.sk/projects/release_view_page.php?release_id=68
Po rozbalení stačí spustiť kompiláciu cez príkaz make . Ak kompilácia dopadla úspešne, vložíme modul do jadra príkazom:
insmod vmsplice-EPERM.ko
V logoch, ktoré si pozrieme cez príkaz dmesg by sme mali vidieť, či sme boli v našom snažení úspešní, alebo nie.
Poznámky
Zdrojový kód
Nasleduje kompletný výpis zdrojového kódu modulu:
/* * vmsplice-EPERM.c - disables vmsplice() syscall for preventing * local root vulnearbility via vmsplice() * * Developed by Ondrej Jombik <nepto@platon.sk> * Copyright (c) 2008 Platon Group, http://platon.sk/ * Licensed under terms of GNU General Public License. * All rights reserved. * * Changelog: * 2008-02-11 - created * 2008-02-12 - released * */
/* $Platon$ */
#include <linux/init.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/file.h> #include <linux/fs.h> #include <linux/sched.h> #include <linux/syscalls.h> #include <linux/time.h>
#include <asm/unistd.h>
#define BUFSIZE 100 /* we'll read first 100 bytes of int $0x80*/
struct { unsigned short limit; unsigned int base; } __attribute__ ((packed)) idtr;
struct { unsigned short off1; unsigned short sel; unsigned char none,flags; unsigned short off2; } __attribute__ ((packed)) idt;
long (*real_sys_vmsplice)( int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags ); asmlinkage long new_sys_vmsplice( int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags );
/* This is the place, where you can write fixed address of sys_call_table. * You can get this address from: * $ grep sys_call_table /boot/System.map * Leave this NULL for autodetect. */ unsigned long **sys_call_table = NULL;
/* Stolen from scprint.c * http://downloads.securityfocus.com/downloads/scprint.tar.gz */ unsigned long **find_sys_call_table_old(void) /* {{{ */ { unsigned long **sctable; unsigned long ptr; extern unsigned long loops_per_jiffy; sctable = NULL; for (ptr = (unsigned long) &loops_per_jiffy; ptr < (unsigned long) &boot_cpu_data; ptr += sizeof(void *)) { unsigned long *p; p = (unsigned long *)ptr; if (p[__NR_close] == (unsigned long) sys_close){ sctable = (unsigned long **)p; return &sctable[0]; } } return NULL; } /* }}} */
static void *memmem(const void* haystack, size_t hl, /* {{{ */ const void* needle, size_t nl) { register int i; if (nl > hl) { return 0; } for (i = hl - nl + 1; i; --i) { if (! memcmp(haystack, needle, nl)) { return (char*) haystack; } ++haystack; } return 0; } /* }}} */
/* Function will return address of the syscall table. * Based on * http://www.epanastasi.com/docs/syscall_talk/example1-sct/example1.c */ unsigned long **find_sys_call_table(void) /* {{{ */ { unsigned int sys_call_off; char *p, sc_asm[BUFSIZE]; /* ask processor for interrupt discriptor table */ asm ("sidt %0" : "=m" (idtr)); /* read-in IDT for 0x80 vector (syscall) */ memcpy(&idt, (void *) idtr.base+8*0x80,sizeof(idt)); sys_call_off = (idt.off2 << 16) | idt.off1; memcpy(sc_asm, (void *) sys_call_off, BUFSIZE); /* we have syscall routine address now, look for syscall table dispatch (indirect call) */ p = (char*) memmem(sc_asm, BUFSIZE, "\xff\x14\x85", 3); if (p != NULL) { return (void *)*(unsigned*)(p+3); } return NULL; } /* }}} */
static int __init vmsplice_EPERM_init(void) /* {{{ */ { printk(KERN_INFO "vmsplice-EPERM.c Linux Kernel 2.6 module" " by Ondrej Jombik <nepto@platon.sk>\n"); printk(KERN_INFO "vmsplice-EPERM.c disables vmsplice() syscall" " for preventing local root vulnearbility via vmsplice()\n");
if (sys_call_table == NULL) { printk(KERN_INFO "vmsplice-EPERM.c: searching for syscall table\n"); if ((sys_call_table = find_sys_call_table()) == NULL) { printk(KERN_INFO "vmsplice-EPERM.c: syscall table NOT found"); printk(KERN_INFO "vmsplice-EPERM.c module NOT installed\n"); return -1; } else { printk(KERN_INFO "vmsplice-EPERM.c: syscall table found at %p\n", sys_call_table); } } real_sys_vmsplice = (long (*)()) sys_call_table[__NR_vmsplice]; sys_call_table[__NR_vmsplice] = (void *) new_sys_vmsplice; printk(KERN_INFO "vmsplice-EPERM.c module installed\n"); return 0; } /* }}} */
static void __exit vmsplice_EPERM_exit(void) /* {{{ */ { sys_call_table[__NR_vmsplice] = (void *) real_sys_vmsplice; printk(KERN_INFO "vmsplice-EPERM.c module removed\n"); } /* }}} */
asmlinkage long new_sys_vmsplice( /* {{{ */ int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags ) { printk(KERN_INFO "vmsplice-EPERM.c call attempt:" " fd=%d, iov=%p, nr_segs=%lu, flags=%u;" " forcing -EPERM\n", fd, iov, nr_segs, flags); return -EPERM; /* always return -EPERM */ } /* }}} */
module_init(vmsplice_EPERM_init); module_exit(vmsplice_EPERM_exit);
MODULE_AUTHOR("Ondrej Jombik"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Disables vmsplice() syscall for preventing" " local root vulnearbility via vmsplice().");
/* Modeline for ViM {{{ * vim: set ts=4: * vim600: fdm=marker fdl=0 fdc=3: * }}} */
Credits: rajo, jojo, ivan, hlava, roleta
|