FrankS: (PERL)

Hallo allerseits,

ich will hier kurz einen Scriptausschnitt (Formmailer) zur Diskussion stellen und damit nochmal an alle appelieren, ihre Scripts auf Löcher zu untersuchen. Ich war lange Zeit der Meinung, keinem Angreifer eine Möglichkeit zum Mißbrauch zu geben, bis ich eines besseren belehrt wurde.

<codeschnipsel>
use CGI;
use CheckRFC;

#mailTo fest codiert
my $mailTo = "mail@domain.de";
my $mailprog   = '/usr/lib/sendmail';

#Formular-Parameter lesen
[...]

#Parameter $mailFrom überprüfen mittels CheckRFC
if ( !is_email($mailFrom) ){ &errorMsg("From-Adresse fehlerhaft\n") ; }

#Parameter Subject wird ungeprüft genutzt
open (MAIL, "|$mailprog -t") || die "Can't open $mailprog $!\n";

print MAIL "To: $mailTo\n";
print MAIL "From: $from\n";
print MAIL "Subject: $subject\n\n";
print MAIL "$body\n";

close (MAIL);
</codeschnipsel>

Eigentlich sollte das Script (hier stark gekürzt) so fehlerfrei und sicher arbeiten. Tut es aber nicht, es kann von bösartigen Zeitgenossen als SpamRelay genutzt werden. Wie? Ganz einfach: Man füllt das Feld $subject mit folgendem Inhalt: 'Das ist ein offenes Scheunentor! \nTo: bla@domain.de,blubb@domain.de'

Damit bekommt sendmail folgende Parameter (nehmen wir an, daß die From-Adresse folgende war und damit der Prüfung standgehalten hat: fjhvdsmnfdtz@hotmail.com). Das \n im Feld $subject beendet dabei den Parameter Subject, der Rest wird als neue Zeile im Header interpretiert. In diesem Fall eine weitere To-Zeile.

To: mail@domain.de
From: fjhvdsmnfdtz@hotmail.com
Subject: Das ist ein offenes Scheunentor!
To: bla@domain.de,blubb@domain.de

Und schon geht die Mail an diverse Adressen. Mit dem diesem Verfahren wurden von meinem Account viele tausend Mails verschickt, ohne daß ich dies wirklich bemerkt habe (pro Aufruf etwa 500). Natürlich habe ich auch bei jeder Nutzung des Scripts eine Mail bekommen (ist ja schließlich fest codiert), die hat mein Spamfilter aber immer gleich aussortiert.

Fazit: es reicht bei weitem nicht aus, die Mail-Adressen auf richtige Syntax zu überprüfen und die -t von sendmail Option zu nutzen. Auch alle anderen Parameter, die dann im Header landen, müssen überprüft werden. Eine andere Lösung zum Verhindern des Mißbrauchs ist folgende: Alle Parameter für den MailHeader werden fest im Script codiert, alle von Formular übertragenen Parameter werden als Text in den MailBody geschrieben.

Gruß Frank

  1. Ich nochmal!

    Habe ich doch das eigentliche Thema vergessen *Kopfschüttel*

    Gruß Frank

  2. Hi Frank,

    ich verwende (noch) folgenden code:

    ################################################

    $mail = qq~To: $recipient
    From: $email;
    Subject: $subject

    Nachricht:
    $message
    ~;

    open(MAIL,"|$mailprog -t") || die "Fehler ... ";
       print MAIL $mail;
    close(MAIL) || die "Fehler ... ";

    ################################################

    Das von Dir erwähnte Scheunentor funktioniert dabei anscheinend nicht.

    Grüße von Tom C

    1. vielmehr kommt als Betreff folgendes an:

      Das Scheunentor \nTo: my.email@example.com

      1. Halihallo Tom

        vielmehr kommt als Betreff folgendes an:
        Das Scheunentor \nTo: my.email@example.com

        Äm. Beide Aussagen sind falsch :-)

        Beim Posting vorhin:
        Das "Scheunentor" ist auch da vorhanden, wenn man...

        Beim jetztigen Posting:
        ... es richtig macht und \n nicht hardkodiert, sondern wirklich als
        CRLF übermittelt.

        Dein Democode stopft das Sicherheitsloch nicht, im Gegenteil: du
        verschlimmerst es.

        Viele Grüsse

        Philipp

        --
        M$: Patches - don't.
  3. Hallo Frank,

    [...] nur keine Panik. Es kommt ganz darauf an, wie ein \n und ein darauf folgendes To: <> , was im Subject - Feld eingegeben wurde, innerhalb des Scripts geparst wird, so dass es wirksam wird oder nicht. Auf jeden Fall jedoch sollte der Anwender das im Einzelfall prüfen.

    Viele Grüße, Rolf

    --
    KnowHow veröffentlichen statt Patentieren!
    1. Halihallo Rolf

      [...] nur keine Panik.

      Wie bitte? - Panik ist manchmal ein guter Indikator dafür, dass etwas
      wichtiges geändert werden muss... Wie etwa in diesem Problem-Kontext.

      Es kommt ganz darauf an, wie ein \n und ein darauf folgendes To: <> , was im Subject - Feld eingegeben wurde, innerhalb des Scripts geparst wird, so dass es wirksam wird oder nicht.

      Und du hälst Spammer und Angreifer natürlich nicht für so schlau,
      nicht wahr?
      Es existiert - wie FrankS richtig sagt - eine Hintertür und diese
      zu schliessen ist wichtig (alles andere wäre Beihilfe zu einer
      Straftat); denn eines sei dir stets gewiss: wenn es Lücken gibt,
      werden sie auch gefunden!

      Auf jeden Fall jedoch sollte der Anwender das im Einzelfall prüfen.

      Kann es sein, dass du das Ursprungsposting nicht verstanden hast?
      Das ist ein ernst zu nehmendes Thema und es ist richtig von FrankS
      andere darauf aufmerksam zu machen.

      Viele Grüsse

      Philipp

      --
      M$: Patches - don't.
      1. hi,

        Kann es sein, dass du das Ursprungsposting nicht verstanden hast?

        Doch , hab ich durchaus. Mich hat zu genau diesem Thema ein Webworker bereits vor einem Jahr mal angeschrieben und mir gesagt, ich solle meine Scripts prüfen. Selbstverständlich hab ich das auch gemacht mit dem Ergebnis, dass sein Hinweis auf meine Scripts nicht zutraf. Deswegen komme ich zu dem Schluss, dass das im Einzelfall halt geprüft werden sollte.

        Im Übrigen finde ich es ganz toll, hier in diesem Forum zu meinen Postings immer irgendwelche Erklärungen abgeben zu müssen ;-)

        Mach ich doch gerne, weil Du's bist mein Freund!

        Rolf

        --
        KnowHow veröffentlichen statt Patentieren!
        1. Halihallo Rolf

          Kann es sein, dass du das Ursprungsposting nicht verstanden hast?
          Doch , hab ich durchaus. Mich hat zu genau diesem Thema ein Webworker bereits vor einem Jahr mal angeschrieben und mir gesagt, ich solle meine Scripts prüfen. Selbstverständlich hab ich das auch gemacht mit dem Ergebnis, dass sein Hinweis auf meine Scripts nicht zutraf. Deswegen komme ich zu dem Schluss, dass das im Einzelfall halt geprüft werden sollte.

          Nicht im Einzelfall, sondern in Jedemfall :-)
          Es besitzt keiner eine Glaskugel, die ihm sagt, dass er eben
          zum Einzelfall gehört oder nicht. Prüfen muss jeder, *jeder*.

          Es ist natürlich gut, wenn der Verdacht bei deinem Beispiel nicht
          erhärtet werden kann, aber deine Stellungnahme "... Keine Panik..."
          war IMHO deplatziert. FrankS will andere auf potenzielle
          Sicherheitslücken aufmerksam machen und du sagst sowas wie: "Och
          Freunde, ist nur halb so wild. Nur keine Panik, es kommt ja darauf
          an wie der Code aussieht und das weiss der Angreifer ja nicht, nur
          keine Sorge...". So kann man dein Posting lesen und so habe ich es
          verstanden. Vielleicht verstehst du jetzt meine Einwände.

          Dass das Script auch funktionieren kann (wenn die Kodierung etc. OK
          ist), ist ja jedem klar. Das brauchst du auch keinem mitzuteilen.
          Im Gegenteil: Man soll niemandem sagen, dass etwas auch "gut gehen"
          kann! - Derjenige, der dies liest fühlt sich dann nur in (nicht
          existenter) Sicherheit geborgen.
          In der Sicherheit muss man immer vom Worst-Case ausgehen... bla bla
          bla... der Worst-Case tritt immer ein... bla bla bla... man kann
          stets davon ausgehen, dass der Angreifer schon den gesamten Code
          kennt bla bla bla... Du kennst das ja, ich wiederhole mich nur
          einmal mehr für's Archiv.

          Im Übrigen finde ich es ganz toll, hier in diesem Forum zu meinen Postings immer irgendwelche Erklärungen abgeben zu müssen ;-)

          Du bist der Praktiker ich der Theoretiker => Meinungs-
          verschiedenheit :-)
          ... das hatten wir doch schonmal, nicht? :-)

          Mach ich doch gerne, weil Du's bist mein Freund!

          Ich doch auch :-)

          Viele Grüsse

          Philipp

          --
          if Murphy's laws are so true then why can I go to MSDN and learn someth...
          <img src="http://www.emedias.ch/jserr.gif" border="0" alt="">
      2. Moin.

        Und du hälst Spammer und Angreifer natürlich nicht für so schlau,
        nicht wahr?

        Ich brauche nur wenige Versuche, um ohne Kenntnis des Webservers zu ermitteln, wie \n zu codieren ist, damit es "richtig" interpretiert wird: 0x0a, 0x0d 0x0a... Und eigentlich brauche ist es garnicht probieren, wenn es bei einem nicht geht, nehme ich den nächsten. Ich habe verschiedene beliebige Feedback-Forms im Internet, die auf einem Perl-Script basieren, mittels eines kleinen Script, welches den HTTP-Request zusammenbaut, mit "Daten" versorgt - es gingen ALLE!!! Selbst bei einem Provier!

        Es existiert - wie FrankS richtig sagt - eine Hintertür und diese
        zu schliessen ist wichtig (alles andere wäre Beihilfe zu einer
        Straftat); denn eines sei dir stets gewiss: wenn es Lücken gibt,
        werden sie auch gefunden!

        Stimmt. Mein FormmailScript war nur kurze Zeit online - und schon mißbraucht.

        Die Lücke existiert übrigens auch in dem Formmailer, der auf selfHTML zu finden ist: http://aktuell.de.selfhtml.org/tippstricks/cgiperl/form-mail/index.htm. Ich werde Stefan mal 'ne Mail schreiben

        Gruß Frank

  4. hi,

    print MAIL "Subject: $subject\n\n";
    print MAIL "$body\n";

    das kann bei PHP so nicht passieren, da subject und to getrennte parameter des mail()-befehls sind.

    aber dafür gibt's da natürlich andere potentielle schwachpunkte ... (mir ging's ja eh eher um ein heise-mäßiges posting. aah ... das tat gut!)

    gruß,
    wahsaga

    1. Halihallo wahsaga

      Na, jetzt pass mal auf du!

      das kann bei PHP so nicht passieren, da subject und to getrennte parameter des mail()-befehls sind.

      fork and die while "you don't speak Perl!"

      Lasst das nicht durch Perl ausführen :-)

      solange "you don't speak Perl" wahr bleibt wirst du "gegabelt" und

      mit deinen Kindern sterben. Tatsache: dieser Absatz beschreibt

      sehr genau, was das Script tut :-)

      Known bugs:

      ActiveState Perl for WinXP: forking is threading => limits the

      #     number of kids that can die :-)    [at least I think so...]

      So, jetzt bin ich stolz eine anständig schlagfertige Antwort in Perl
      verfasst zu haben :-)

      Nieder mit PHP!!!!1

      while ("spaking PHP") {
         die;
      }

      um es einfach auszudrücken!

      Es lebe das Selfforum und Perl :-)

      Schön, dass es dich (Selfforum, wahsaga, alle) wieder gibt :-)

      Viele Grüsse

      Phi*sich dem Heise-Niveau anpassend*lipp

      --
      if Murphy's laws are so true then why can I go to MSDN and learn someth...
      <img src="http://www.emedias.ch/jserr.gif" border="0" alt="">
      (Hm. 404-"Not Found" wäre wohl verständlicher gewesen??? :-))
    2. Hi,

      print MAIL "Subject: $subject\n\n";
      print MAIL "$body\n";
      das kann bei PHP so nicht passieren, da subject und to getrennte parameter des mail()-befehls sind.

      Ich kanns grade nicht ausprobieren, aber:
      auch der subject-Parameter der PHP-Mail-Funktion wird ja letzten Endes in den header der Mail geschrieben.

      Prüft PHP wirklich ab, ob im subject kein Zeilenumbruch vorkommt?
      Im Manual heißt es:
      Note:  Make sure you do not have any newline characters in the to or subject, or the mail may not be sent properly.

      Keine klare Aussage, was bei einem Zeilenumbruch (hinter dem dann To:bla@example.org steht) im Subject passiert...

      cu,
      Andreas

      --
      MudGuard? Siehe http://www.Mud-Guard.de/
      Fachfragen per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
      1. Hi!

        Ich kanns grade nicht ausprobieren, aber:
        auch der subject-Parameter der PHP-Mail-Funktion wird ja letzten Endes in den header der Mail geschrieben.

        Ja, aber PHP prüft jedes Zeichen des Subject ob es ein Sonderzeichen ist:

        for(i = 0; subject[i]; i++) {
           if (iscntrl((unsigned char) subject_r[i])) {
            SKIP_LONG_HEADER_SEP(subject_r, i);
            subject_r[i] = ' ';
           }
          }

        Prüft PHP wirklich ab, ob im subject kein Zeilenumbruch vorkommt?

        ja. Wobei ich in den Kommentaren gelesen habe, dass es früher mal anders war (anno 2002).

        Im Manual heißt es:
        Note:  Make sure you do not have any newline characters in the to or subject, or the mail may not be sent properly.

        Eigentlich müsste das veraltet sein.

        Keine klare Aussage, was bei einem Zeilenumbruch (hinter dem dann To:bla@example.org steht) im Subject passiert...

        das wird  mit ins Subject geschrieben, und der Zeilenumbruch durch ein Leerzeichen ersetzt.

        Aber bei mail() gibt es einen 4. Parameter, der dafür gedacht ist eigene Header hinzuzufügen, hier muss man sehr vorsichtig sein wenn man da Variablen einfügt, denn man hat sonst genau dasselbe Problem wie bei PERL:

        <?php
        mail("nobody@example.com", "Betreff", $_POST['message'], "From: {$_POST['from']}");
        ?>

        Hiermit hätten wir dasselbe Scheunentor in PHP. Wenn ich hier sowas wie "\r\nTo:opfer1@example.com,opfer2@example.com..." angebe, dann habe ich ein wunderbares System um Spam zu versenden.

        Viele Grüße
        Andreas

        --
        SELFHTML Linkverzeichnis: http://aktuell.de.selfhtml.org/links/
        1. Hi,

          Ja, aber PHP prüft jedes Zeichen des Subject ob es ein Sonderzeichen ist:

          Ok, wird also (zumindest in aktuellen PHP-Versionen) entschärft.

          ja. Wobei ich in den Kommentaren gelesen habe, dass es früher mal anders war (anno 2002).

          Im Manual heißt es:
          Note:  Make sure you do not have any newline characters in the to or subject, or the mail may not be sent properly.
          Eigentlich müsste das veraltet sein.

          12-04-2004 steht auf der Startseite meines lokalen PHP-Manuals...

          Auch die online-Version (http://de3.php.net/manual/en/function.mail.php) enthält diese Note noch - direkt über den User Notes.

          cu,
          Andreas

          --
          MudGuard? Siehe http://www.Mud-Guard.de/
          Fachfragen per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
          1. Hi Andreas!

            ja. Wobei ich in den Kommentaren gelesen habe, dass es früher mal anders war (anno 2002).

            Im Manual heißt es:
            Note:  Make sure you do not have any newline characters in the to or subject, or the mail may not be sent properly.
            Eigentlich müsste das veraltet sein.

            12-04-2004 steht auf der Startseite meines lokalen PHP-Manuals...

            Auch die online-Version (http://de3.php.net/manual/en/function.mail.php) enthält diese Note noch - direkt über den User Notes.

            Ja, ich weiß.

            Der Bug (http://bugs.php.net/bug.php?id=17746) wurde mit dem Release von PHP 4.2.3 behoben (http://de3.php.net/ChangeLog-4.php#4.2.3).

            Naja, ich denke PHP < 4.2.3 ist noch durchaus oft im Einsatz. Ich habe  gerade mal php 4.2.2 getestet, und da besteht in der Tat dieses Problem, was sehr leicht auszunutzen ist wenn "To" oder "Subject" manipulierbar sind, z.B. über  $_GET/$_POST oder ggfs. auch bei falscher Verwendung von register globals. Bei Versionen ab PHP 4.2.3 funktioniert das wie gesagt nicht mehr, bzw. nur noch über den 4. Parameter.

            Grüße
            Andreas

            --
            SELFHTML Feature Artikel: http://aktuell.de.selfhtml.org/artikel/
    3. Hi wahsaga,

      das kann bei PHP so nicht passieren, da subject und to getrennte parameter des mail()-befehls sind.

      PHP ist eben eine Profi-Sprache!

      Viele Grüße
      Baumarktleiter Hängebank

  5. Hi,

    open (MAIL, "|$mailprog -t") || die "Can't open $mailprog $!\n";

    Ruf sendmail mal zusätzlich mit -oi auf :)

    Ciao,
      Wolfgang

    1. Hi,

      Add:

      Das -oi verhindert allerdings nur, daß man mit einem AUfruf gleich ein paar Tauend Mails rausschickt.

      Die Beste Lösung ist aber trotzdem den gesamten Header-Teil in eigene Hände zu lassen, d.h. nicht von User-Input beeinflussen zu lassen.

      Und wenn, dann natürlich nur, wenn diese über RegExps gereinigt wurden.

      Also z.B. $subject =~ s/[^a-z0-9\s]+//gi;

      Ciao,
        Wolfgang

      1. Moin.

        Das -oi verhindert allerdings nur, daß man mit einem AUfruf gleich ein paar Tauend Mails rausschickt.

        Danke, das werde ich mir mal ansehen. Im Moment kannn der User bei mir zwar alles eingeben, es landet aber nix davon im Header!

        Und wenn, dann natürlich nur, wenn diese über RegExps gereinigt wurden.

        Also z.B. $subject =~ s/[^a-z0-9\s]+//gi;

        Das macht Dein allform.pl mit $title übrigens auch nicht ;) Du fragst zwar HTTP_REFERER ab, hier im Forum habe ich aber schon oft gelesen, daß der leicht fälschbar ist.

        Gruß Frank

        1. Hi!

          Und wenn, dann natürlich nur, wenn diese über RegExps gereinigt wurden.

          Also z.B. $subject =~ s/[^a-z0-9\s]+//gi;

          Das macht Dein allform.pl mit $title übrigens auch nicht ;)

          doch, da steht was in dem web.pm, wenn ich das mit meinen spärlichen perl-Kenntnissen richtig verstehe erstezt er da einfach alle Ümbrüche, ähnlich wie es in der mail() Funktion von PHP gemacht wird (nur wird es hier gegen Leerzeichen ersetzt, und es werden diese "LONG HEADER FIELDS" (man darf z.B. \r\n\t für lange Header verwenden, aber das finde ich hier nicht so wichtig) gemäß RFC 822 berücksichtigt) ;-)

          Du fragst zwar HTTP_REFERER ab, hier im Forum habe ich aber schon oft gelesen, daß der leicht fälschbar ist.

          Hehe ;-)

          Grüße
          Andreas

          --
          SELFHTML Linkverzeichnis: http://aktuell.de.selfhtml.org/links/
          1. Moin.

            Hi!

            doch, da steht was in dem web.pm [...]

            Oh ja, erst alles lesen ;)

            Allerdings: beim ersten schnellen lesen habe ich das entsorgen von \n\r nur gesehen, wenn es sich um eine multipart - request handelt.

            Muß ich mir nochmal genau ansehen!

            Gruß Frank

          2. Hi,

            Das macht Dein allform.pl mit $title übrigens auch nicht ;)
            doch, da steht was in dem web.pm, wenn ich das mit meinen spärlichen perl-Kenntnissen richtig verstehe erstezt er da einfach alle Ümbrüche,

            Nene, da hatte Frank schon recht.
            Ich hatte da den Bug auch drin.
            Das Rauswerfen der "\n" mach ich nur dann, wenn ich Upload-Handling mache.

            Nun ja, zu meiner Entschuldigung könnte ich anbringen, daß das Skript ja schon über 5 Jahre alt ist, ich damals natürlich nicht so viel Ahnung hatte und das Skript aus meiner heutigen Sicht "a bunch of shit" ist :)

            Aber wenn man schon einige Dutzend verschiedene Skripten und Programme geschrieben hat, verliert man einfach den Überblick und hat auch keine Zeit die alle zu pflegen :/

            Ciao,
              Wolfgang