Domanda

Attualmente stiamo costruendo un'applicazione che esegue una serie di strumenti esterni.Spesso dobbiamo trasmettere a questi strumenti le informazioni immesse nel nostro sistema dagli utenti.

Ovviamente, questo è un grande incubo per la sicurezza in attesa di accadere.

Sfortunatamente, non abbiamo ancora trovato alcuna classe in .NET Framework che esegua programmi da riga di comando fornendo allo stesso tempo lo stesso tipo di protezione contro gli attacchi di tipo injection degli oggetti IDbCommand per i database.

In questo momento stiamo utilizzando una sostituzione di stringa molto primitiva che sospetto sia piuttosto insufficiente:

protected virtual string Escape(string value)
{
      return value
        .Replace(@"\", @"\\")
        .Replace(@"$", @"\$")
        .Replace(@"""", @"\""")
        .Replace("`", "'")
      ;
}

Cosa fate per prevenire attacchi di injection da riga di comando?Stiamo progettando di implementare un'espressione regolare che sia molto rigorosa e consenta solo il passaggio di un sottoinsieme molto piccolo di caratteri, ma mi chiedevo se esistesse un modo migliore.

Alcuni chiarimenti:

  • Alcuni di questi strumenti non dispongono di API su cui possiamo programmare.Se lo facessero non avremmo questo problema.
  • Gli utenti non scelgono gli strumenti da eseguire, inseriscono i metadati utilizzati dagli strumenti che abbiamo scelto (ad esempio, inserendo metadati come avvisi di copyright nei file di destinazione).
È stato utile?

Soluzione

Stai eseguendo i programmi direttamente o passando attraverso la shell?Se avvii sempre un programma esterno fornendo il nome del percorso completo all'eseguibile e lasciando la shell fuori dall'equazione, non sei realmente suscettibile a nessun tipo di iniezione della riga di comando.

MODIFICARE:DrFloyd, la shell è responsabile della valutazione di cose come il backtick.Nessuna shell, nessuna valutazione della shell.Ovviamente, devi comunque essere consapevole di eventuali potenziali trucchi di sicurezza nei programmi che stai chiamando, ma non credo che questa domanda riguardi questo.

Altri suggerimenti

Quando tu Processo.Avvio un nuovo processo, fornisci i parametri nell'argomento Parametri invece di creare tu stesso l'intera riga di comando.

Non ho tempo per un test vero e proprio, ma penso che questo dovrebbe aiutare a mantenerlo a un certo livello.

Lo proverò domani.

MODIFICARE: Ah, qualcuno mi ha preceduto di nuovo.Ma ecco un altro punto:Prova a utilizzare Console.InputStream (non ricordo il nome esatto) per fornire dati invece di passare parametri, è una soluzione possibile?come correggere il comando in modo che legga dal dispositivo CON e quindi fornire i dati tramite il flusso di input.

In C++ in poi finestre, basta eseguire l'escape \ e " dove necessario, citare l'argomento e ShellExecute.Quindi, tutto ciò che è racchiuso tra virgolette dovrebbe essere trattato come testo.

Questo dovrebbe illustrare:


#include <iostream>
#include <string>
#include <windows.h>
#include <cstdlib>
using namespace std;

// Escape and quote string for use as Windows command line argument
string qEscape(const string& s) {
    string result("\"");
    for (string::const_iterator i = s.begin(); i != s.end(); ++i) {
        const char c = *i;
        const string::const_iterator next = i + 1;
        if (c == '"' || (c == '\\' && (next == s.end() || *next == '"'))) {
            result += '\\';
        }
        result += c;
    }
    result += '"';
    return result;
}

int main() {
    // Argument value to pass: c:\program files\test\test.exe
    const string safe_program = qEscape("c:\\program files\\test\\test.exe");
    cout << safe_program << " ";

    // Argument value to pass: You're the "best" around.
    const string safe_arg0 = qEscape("You're the \"best\" around.");

    // Argument value to pass: "Nothing's" gonna ever keep you down.
    const string safe_arg1 = qEscape("\"Nothing's\" gonna ever keep you down.");

    const string safe_args = safe_arg0 + " " + safe_arg1;
    cout << safe_args << "\n\n";

    // c:\program files\test\  to pass.
    const string bs_at_end_example = qEscape("c:\\program files\\test\\");
    cout << bs_at_end_example << "\n\n";

    const int result = reinterpret_cast<int>(ShellExecute(NULL, "open", safe_program.c_str(), safe_args.c_str(), NULL, SW_SHOWNORMAL));
    if (result < 33) {
        cout << "ShellExecute failed with Error code " << result << "\n";
        return EXIT_FAILURE;
    }
}

Ma, con qualsiasi metodo tu usi, dovresti testarlo a fondo per vedere che previene davvero l'iniezione.

Non utilizzare una lista nera per prevenire le iniezioni.Se ci sono N modi per iniettare il codice, a cui penserai n-m Dove m > 0.

Utilizza una lista bianca di parametri (o modelli) accettati.È molto più restrittivo per natura, ma questa è la natura della sicurezza.

Bene, se puoi richiamare gli strumenti a livello di codice senza la riga di comando, questa sarebbe probabilmente la soluzione migliore.Altrimenti, potresti potenzialmente eseguire lo strumento da riga di comando tramite un utente che non ha assolutamente accesso per fare nulla (tranne forse una singola directory con cui non può fare alcun danno)...anche se ciò potrebbe finire per rompere lo strumento, a seconda di cosa fa lo strumento.

Tieni presente che non ho mai dovuto affrontare questo problema, perché non ho mai dovuto invocare uno strumento da riga di comando da un'applicazione rivolta all'esterno in cui lo strumento richiede input da parte dell'utente.

Hmm...

Sembra che tu abbia un elenco di comandi validi che gli utenti sono in grado di eseguire.Ma non vuoi che li giustizino tutti.

Potresti provare a prendere la riga di comando effettiva e verificare che il file esista almeno nella posizione "sicura".

Potresti anche risolvere il problema con più interfaccia, fornire un elenco a discesa di comandi e parametri che potrebbero utilizzare.È più lavoro da parte tua, ma alla fine aiuta gli utenti.

Stai eseguendo i programmi direttamente o passando attraverso la shell?Se avvii sempre un programma esterno fornendo il nome del percorso completo all'eseguibile e lasciando la shell fuori dall'equazione, non sei realmente suscettibile a nessun tipo di iniezione della riga di comando.

@Curt Hagenlocher Il backtick può ucciderti.Se il sistema Windows è impostato in modo "sbagliato", o il sistema UNIX lo consente, una directory &bt;del *&bt;eseguirà prima il comando del * quindi utilizzerà l'output al posto di del *, che in questo caso non avrà importanza perché non c'è niente da dir (o ls)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top