[C] system()

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • [C] system()

    Huhu, ich habe folgendes Probelm. Ich möchte ein Programm schreiben, welches eine leere Datei erstellen soll, durch den UNIX Befehl "touch", man soll aber auch die Wahl haben den Namen der Datei zu bestimmen.

    Ich habe folgendes ausprobiert

    Quellcode

    1. printf(": ");
    2. scanf("%s",&dateiName);
    3. strcat(systemEingabe, "touch ~/Desktop/");
    4. strcat(systemEingabe, dateiName);
    5. system("%s", systemEingabe);


    Nur leider wird "%s" als Befehl genommen und nicht das was in der "systemEingabe" eingespeichert wurde. Wie könnte ich diese Problem lösen. Könntet es mir jemand erklären, weil ich habe erst vor kurzem angefangen in C und auch allgemein zu programmieren.
  • 1. Es kann sein, dass du die Tilde im Pfad auslösen musst.
    2. system erwartet doch eh nur ein Argument. system(systemEingabe) funktioniert nicht?
    3. system sollte man nicht verwenden, da großes Sicherheitsrisiko.
    4. Um eine Datei zu erstellen kannst du auf die entsprechenden C-Funktionen zurückgreifen.
    Die Objective-Cloud ist fertig wenn sie fertig ist. Beta heißt Beta.

    Objective-C und Cocoa Band 2: Fortgeschrittene
    Cocoa/Objective-C Seminare von [co coa:ding].
  • Original von MrKacuklav
    oke, mit "system(systemEingabe)" hat es funktioniert. Wie wäre der Befehl in C und warum ist es durch system ein hohes Scihertheitsrisiko ??


    Ganz einfach. Du liest mit

    Quellcode

    1. scanf("%s",&dateiName);


    einen Dateinamen ein. Was, wenn der Benutzer nicht nur einen Dateinamen sondern etwas mehr eingibt?

    Angenommen der Benutzer gibt ein:

    einDateiname & rm -R /

    Dann wird eine leere Datei namens "einDateiname" erstellt und noch der Befehl "rm -R /" ausgeführt, der bei entsprechenden Rechten die Festplatte löscht.

    Du musst da höllisch aufpassen.
    Die Objective-Cloud ist fertig wenn sie fertig ist. Beta heißt Beta.

    Objective-C und Cocoa Band 2: Fortgeschrittene
    Cocoa/Objective-C Seminare von [co coa:ding].
  • Hier ein Beispiel mit Foundation:

    Quellcode

    1. #import <Foundation/Foundation.h>
    2. int main()
    3. { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    4. int retCode=1;
    5. NSString *pathWithTilde=@"~/temp/myFairLady";
    6. NSArray *argArray=[NSArray arrayWithObject:[pathWithTilde stringByExpandingTildeInPath]];
    7. NSTask *newTask = nil;
    8. if ( argArray != nil )
    9. {
    10. newTask = [NSTask launchedTaskWithLaunchPath:@"/usr/bin/touch" arguments:argArray];
    11. if ( newTask )
    12. retCode=0;
    13. }
    14. [pool release];
    15. return retCode;
    16. }
    Alles anzeigen


    Sicherheitsrisiken sind bei Shell exits immer gegeben (obiges Beispiel ist KEIN Shellexit !).

    Nehmen wir jetzt das Systemcommando. Ein Programmierer hat sich informiert und baut folgendes kleines Programm.

    C-Quellcode

    1. #include <stdlib.h>
    2. #include <string.h>
    3. int main(int argc, char **argString)
    4. { char tempBuffer[1024];
    5. int exitCode=1;
    6. if ( argc > 1 && strlen(argString[1]) < 512 )
    7. {
    8. strcpy( tempBuffer,"/usr/bin/touch " );
    9. strcat( tempBuffer, argString[1]);
    10. exitCode=system( tempBuffer );
    11. }
    12. return exitCode;
    13. }
    Alles anzeigen


    Sieht alles wunderprächtig aus, scheinbar jedes Problem wird vermieden (zB. die gefürchteten buffer overrun). Das Programm ist sicher!

    Tja, leider ist da ein Parameter, der von einem Benutzer eingegeben werden darf. Nehmen wir nun mal an, daß dieses Programm von einem Benutzer mit Adminrechten ausgeführt wird, weil es eine Datei in einem geschützen Verzeichnis anlegen soll (zB. /Library/Application Support). Als Parameter wird vom Benutzer der Namen der Datei abgegefragt:
    Dieser gibt nun folgenden String ein:

    Quellcode

    1. YouAreHacked\;echo\ $(pwd)


    Und schon hat man verloren. Weil System eine Shell startet kann man auf der Commandline auch komplette Programme übergeben. Der Phantasie sind hier keine Grenzen gesetzt (und ich meine das tatsächlich so, auch wenn obiges Beispiel extrem harmlos aussieht).

    Deswegen: FINGER WEG VON SHELL EXITS

    Edith meint: jetzt gibt es halt 2 Erklärungen, warum Shellexits böse sind.
    Es gibt genau 10 Sorten von Menschen.
    Die eine kennt das binaere Zahlensystem, die andere nicht.
  • Original von mac_held

    C-Quellcode

    1. #include <stdlib.h>
    2. #include <string.h>
    3. int main(int argc, char **argString)
    4. { char tempBuffer[1024];
    5. int exitCode=1;
    6. if ( argc > 1 && strlen(argString[1]) < 512 )
    7. {
    8. strcpy( tempBuffer,"/usr/bin/touch " );
    9. strcat( tempBuffer, argString[1]);
    10. exitCode=system( tempBuffer );
    11. }
    12. return exitCode;
    13. }
    14. }
    Alles anzeigen


    Erinnert mich etwas an PHP/SQL Injunctions, deshalb die blöde Frage: nicht alphanumerische Zeichen außer ' /\_-' aus Eingabestring wegwerfen behebt dieses Problem nicht?

    Dann würde aus der Eingabe nämlich
    YouAreHacked\echo\pwd
    und alles ist gut.
    Wenn man davon absieht, dass 'system()' eventuell nen Fehler ausspuckt, weil ihm das ESC-Zeichen nicht gefällt... Aber irgendwie muss man ja die Leerzeichen in Pfaden ausklammern...

    Dass Benutzereingaben immer ordentlich gefiltert gehören erklärt sich eigentlich von selbst.
    Zugegeben, bei vielen meiner ersten C/C++ Programme war ich auch nachlässig, aber die hat ja auch niemand außer mir. ;)
    (Auf Platz 3 der Topliste der nachlässigsten Ausreden, gleich hinter 'Der Fehler ist sooo bekannt, da rechnet keiner mehr mit!' und 'Der Nutzer wird schon keinen Blödsinn damit machen.')
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Original von Lucas de Vil
    Wenn man davon absieht, dass 'system()' eventuell nen Fehler ausspuckt,

    Es empfiehlt sich grundsätzlich die fork exec Kombination zu verwenden, da wird keine Shell mehr aufgerufen, und ein Programm direkt gestartet, und die Parameter werden auch als solche garantiert übergeben.
  • Original von tjp
    Original von Lucas de Vil
    Wenn man davon absieht, dass 'system()' eventuell nen Fehler ausspuckt,

    Es empfiehlt sich grundsätzlich die fork exec Kombination zu verwenden, da wird keine Shell mehr aufgerufen, und ein Programm direkt gestartet, und die Parameter werden auch als solche garantiert übergeben.


    noch besser ist aber einfache c-funtkionen zu verwenden sofern vorhanden!
  • So nebenbei, warum wegen eines "touch" die system() Funktion benutzen und der Command Injection Tür und Tor öffnen?

    Quellcode

    1. FILE *file;
    2. file = fopen("/Users/manfred/Desktop/hello", "w");
    3. /* open a text file for writing */
    4. if(file==NULL) {
    5. printf("Error: can't open file.\n");
    6. /* do additional stuff */
    7. }
    8. else {
    9. printf("File opened. Now closing it...\n");
    10. fclose(file);
    11. }
    Alles anzeigen
    Seminare, Artikel, Code. ObjectiveCeeds - alles für die Apfelzucht.
  • Ich denke, system() lässt sich in dem gewünschten Fall hinreichend gegenüber möglichen Gefahren durch simples "Quoten" des Dateinamens umgehen.
    Single-Quotes (') verhindert ausserdem noch die Auflösung von $variablen (gibt der Nutzer beispielsweise $USER an, wird eine Datei mit dem derzeitigen Nutzernamen erstellt, was auch unter Umständen ein Sicherheitsrisiko darstellen könnte). Generell sollte man möglichst sein environ bereinigen, bevor man fremde Dinge exec-t.

    Also:
    1. Alle single-quotes in der Nutzereingabe escapen -> \'
    2. Nutzereingabe in Single-Quotes packen
    3. system() aufrufen

    So oder so sollte man aber in so einem Beispiel immer lieber auf system() bzw. exec() verzichten :)
    C++