
Buffer overflow basato su stack in R 3.4.4. Sfruttamento completo su x86, ma solo controllo di RIP con analisi dei gadget su x64 a causa dei vincoli del programma. La stessa vulnerabilità su due architetture, che porta a diversi percorsi di sfruttamento.
Buffer overflow basato su stack in R 3.4.4. Sfruttamento completo su x86, ma solo controllo di RIP con analisi dei gadget su x64 a causa dei vincoli del programma. La stessa vulnerabilità su due architetture, che porta a percorsi di sfruttamento diversi.
Questo repository fa parte del materiale che uso quando insegno lo sfruttamento della corruzione della memoria (oltre al mio lavoro abituale, insegno anche in diversi corsi di cybersecurity dove aiuto a formare la prossima generazione di reverse engineer).
CVE-2019-25485 è il caso che uso quando voglio che gli studenti affrontino la stessa vulnerabilità su due architetture diverse e vedano di persona cosa cambia tra di esse. R 3.4.4 è disponibile sia in versione x86 che x64, e lo stesso identico overflow esiste in entrambe: lo stesso campo della GUI, lo stesso gestore di input, lo stesso crash. Entrambe sono documentate e sfruttate qui come esercizi separati:
R 3.4.4 è un'applicazione di calcolo statistico, non un servizio di rete o un browser. L'overflow viene innescato tramite un campo della GUI desktop, il che significa che la superficie d'attacco è completamente diversa da ogni altro caso che insegno. Ciò che rende questo caso utile per l'insegnamento:
R è un ambiente di calcolo statistico e grafica disponibile per Windows, macOS e Linux. La vulnerabilità si trova nella finestra di dialogo delle Preferenze della GUI, in particolare nel campo Language for menus and messages, che copia l'input dell'utente in un buffer di stack a dimensione fissa senza validarne la lunghezza.
Dettagli tecnici chiave:
R 3.4.4 elabora il campo Language for menus and messages copiando la stringa fornita in un buffer di stack a dimensione fissa senza controllarne la lunghezza. Una versione semplificata della logica vulnerabile è questa:
char language_buffer[256];
strcpy(language_buffer, user_input);
L'invio di una stringa sufficientemente lunga fa sì che la copia scriva oltre la fine del buffer, corrompendo lo stack fino a sovrascrivere l'indirizzo di ritorno salvato. Quando la funzione ritorna, la CPU carica il valore controllato dall'attaccante dallo stack in RIP e tenta di saltarci.
Su x64, Windows impone la validazione degli indirizzi canonici prima che avvenga qualsiasi salto. Un valore non canonico come 0x4141414141414141 innesca una violazione di accesso immediata prima che RIP venga caricato, il che significa che il crash appare diverso rispetto a x86, senza un netto RIP = 4141414141414141. L'offset deve essere trovato leggendo il pattern ciclico dallo stack dopo il crash piuttosto che direttamente da RIP.
Il crash può essere riprodotto incollando una lunga stringa nel campo della lingua. Non è richiesta alcuna autenticazione. Esempio di generazione del payload con Python:
import struct
payload = b'A' * 400
with open('payload.txt', 'wb') as f:
f.write(payload)
Open R 3.4.4 x64
Edit -> GUI Preferences
Paste contents of payload.txt into Language for menus and messages
Click OK
L'obiettivo di questo repository non è solo dimostrare il crash, ma guidare attraverso il processo di sfruttamento completo su entrambe le architetture, documentando cosa funziona su x86, cosa si rompe su x64 e, cosa più importante, perché.
Per mantenere pulito il README principale, le note dettagliate sullo sfruttamento, gli script e i passaggi del debugger sono inseriti nella cartella Vulnerability 📂 di questo repository, organizzati in sottocartelle separate per x86 e x64.
Lì troverai il flusso di lavoro completo per entrambe le architetture:
x86 - Sfruttamento completo:
x64 - Controllo di RIP e analisi dello sfruttamento: