Chop-Sui: PHP-Skript deaktiviert / Spam durch mail()-method !?!?!?

Hi Leute,

also mein Provider hat mir gemeldet, dass eine bestimmte datei deaktiviert werden soll, weil darüber angbelich spam verschickt wird. Dabei geht es um ein Registrierungsformular. Nach der Registrierung kann der Administrator dann den Eintrag freischalten oder löschen.

Ich verstehe jetzt nicht genau, wie die mail()-Funktion zum spammen benutzt werden kann. Es ist ja nicht so ein Kontaktformular, wo man die Zieladresse oder so eingeben kann. Außerdem gibt es nicht eine Datei, an welche die Daten übergeben werden sondern, sprich, man kann diese Datei nicht einfach separat ansprechen und irgendeinen mist abschicken....

Also, wie kann man die mail()-Funktion zum spammen benutzen und wie kann ich das verhindern?

Danke!

chop-sui

  1. Hi chop-sui

    Also, wie kann man die mail()-Funktion zum spammen benutzen und wie kann ich das verhindern?

    Fast gar nicht. Wenn er das tun will, hast Du Pech....
    Aber: Lies mal in Deinen Bedingungen nach, ob er das überhaupt machen _darf_.

    Nearby: Manchmal erkennt man selbst nicht, dass es eine Einbruchslücke gibt:
    Z.B. wenn sich mehrere Bedingungen überschneiden tritt die nächste in Kraft... Eine Software ist _nie_ fehlerlos!

    Wichtig bei der mail()-Funktion: Niemals die "AN"-Adresse über das Formular übergeben lassen, auch nicht als hidden-Field o.ä. Immer hart-codiert im Quelltext hinterlegen.
    Zusätzlich schränkt das Abschalten der globalen Variablen den Handlungsspielraum der Einbrecher gewaltig ein!

    Grüße

    1. Moin

      Also, wie kann man die mail()-Funktion zum spammen benutzen und wie kann ich das verhindern?
      Fast gar nicht. Wenn er das tun will, hast Du Pech....

      Was meinst Du damit?
      Spam verhindern kann er nicht?
      Natürlich...

      Aber: Lies mal in Deinen Bedingungen nach, ob er das überhaupt machen _darf_.

      Was machen darf?
      Als ob das einen Spamer aus Brasilien interessiert.

      Nearby: Manchmal erkennt man selbst nicht, dass es eine Einbruchslücke gibt:
      Z.B. wenn sich mehrere Bedingungen überschneiden tritt die nächste in Kraft... Eine Software ist _nie_ fehlerlos!

      Hast Du nochmals überdacht was Du dort schreibst?
      Es gibt ein paar Regeln, wenn man sich daran hält, dann kann nichts passieren, z.Bsp Variablen auf Gültigkeit überprüfen.

      Wichtig bei der mail()-Funktion: Niemals die "AN"-Adresse über das Formular übergeben lassen, auch nicht als hidden-Field o.ä. Immer hart-codiert im Quelltext hinterlegen.

      Auch das übergeben einer Mailladresse stellt kein Problem dar, wenn man vorher prüft ob diese Mailadresse eine zulässige ist.

      Zusätzlich schränkt das Abschalten der globalen Variablen den Handlungsspielraum der Einbrecher gewaltig ein!

      Register_Globals off gaukelt oft eine Sicherheit vor die keine ist.
      Man kann ein Formular mit und ohne Register_Globals unsicher machen.
      Zu Beispiel, kann man Headerinformationen auch über Register globals Off hervorragend ins Formular schleusen, wenn eine Überprüfung nicht statfindet.

      TomIRL

      1. Hallo TomIRL,

        Aber: Lies mal in Deinen Bedingungen nach, ob er das überhaupt machen _darf_.

        Was machen darf?

        Er meint das Abschalten des Scriptes.

        Es gibt ein paar Regeln, wenn man sich daran hält, dann kann nichts passieren, z.Bsp Variablen auf Gültigkeit überprüfen.

        Insbesondere alle Parameter, die ins Script gelangen können.
        Und manchmal überschreiben diese Parmater (vorzugsweide per URi übergeben) interne Variablen des Scriptes.

        Auch das übergeben einer Mailladresse stellt kein Problem dar, wenn man vorher prüft ob diese Mailadresse eine zulässige ist.

        Da könnte man aber wieder in den Bereich der "Mitstörerhaftung" kommen. Wozu soll es auch möglich sein, über mein Kontaktformualar emails an Fremde zu senden?

        Zusätzlich schränkt das Abschalten der globalen Variablen den Handlungsspielraum der Einbrecher gewaltig ein!

        Aber nur, wenn man dann nicht z.B. extract() benutzt. Das macht das Ganze noch schlimmer. Über so ein Script hatte ich neulich hier berichtet...

        Zu Beispiel, kann man Headerinformationen auch über Register globals Off hervorragend ins Formular schleusen, wenn eine Überprüfung nicht statfindet.

        Ja, genau darum ging es hier. "Subject" und "From" sind die bevorzugten Felder im Formular für solche Lücken.

        LG
        Chris

        1. Moin,

          Insbesondere alle Parameter, die ins Script gelangen können.
          Und manchmal überschreiben diese Parmater (vorzugsweide per URi übergeben) interne Variablen des Scriptes.

          Ausnahmslos alle Variablen sollten überprüft werden alles andere macht in der Regel nur Probleme.

          Auch das übergeben einer Mailladresse stellt kein Problem dar, wenn man vorher prüft ob diese Mailadresse eine zulässige ist.

          Da könnte man aber wieder in den Bereich der "Mitstörerhaftung" kommen. Wozu soll es auch möglich sein, über mein Kontaktformualar emails an Fremde zu senden?

          Wieso an Fremde?
          An verschieden bekannte!

          Zusätzlich schränkt das Abschalten der globalen Variablen den Handlungsspielraum der Einbrecher gewaltig ein!

          Aber nur, wenn man dann nicht z.B. extract() benutzt. Das macht das Ganze noch schlimmer. Über so ein Script hatte ich neulich hier berichtet...

          Zu Beispiel, kann man Headerinformationen auch über Register globals Off hervorragend ins Formular schleusen, wenn eine Überprüfung nicht statfindet.

          Ja, genau darum ging es hier. "Subject" und "From" sind die bevorzugten Felder im Formular für solche Lücken.

          Die namen der Felder spielen so gut wie keine Rolle.
          Wenn Du ein entsprechend beschissenes Skript hast dann bekommst Du die Header über jedes Feld rein.

          TomIRl

          1. Hallo,

            Insbesondere alle Parameter, die ins Script gelangen können.
            Und manchmal überschreiben diese Parmater (vorzugsweide per URi übergeben) interne Variablen des Scriptes.

            Ausnahmslos alle Variablen sollten überprüft werden alles andere macht in der Regel nur Probleme.

            Wie soll das funktionieren?
            Man muss sich ein Scope schaffen, in dem von außen keine Manipulationen möglich sind. Anders geht es nicht, oder?

            LG
            Chris

      2. Hi TomIRL

        ich habe ja auch nicht geschrieben, dass mit register_globals=off alles gut ist, aber vieles ist besser/sicherer!

        Selbstverständlich meinte ich nicht den Spammer damit, ob er das machen darf, wenn Du aber das vorangegangene Posting gelesen hättest würdest Du wissen, dass ich den Provider und die mail()-Abschaltung damit gemeint habe!

        Grüße

        1. Moin

          ich habe ja auch nicht geschrieben, dass mit register_globals=off alles gut ist, aber vieles ist besser/sicherer!

          Nochmals... Register Globals OFF löst keine Sicherheitsprobleme.
          Wenn jemand sich einen ordentlichen Stil angeöhnt hat, dann ist es völlig unerheblich ob register Globals auf off stehen.
          Anderseits halte ich die ganze Diskussion nicht zielführend.
          Häufig geistert hier die Meinung rum, dass man sicher ist, wenn man die Variable mit $_POST[''] abfragt als mit $var.
          Dieser Thread zeigt meiner Meinung nach recht deutlich, dass der Endnutzer eigentlich gar keine Ahnung von dem hat was er dort tut.
          Wenn man in diesem Forum an anderer Stelle liest, das beim Error Logín Notice mitgelogt werden, dann frage ich mich warum er die Skripte nicht einfach so umbaut, dass  die Notice nicht mehr auftauchen....
          U.s.w. es ist eben nicht alles so einfach wie man denkt.
          Wichtig ist, dass man endlich einsieht, dass Webprogrammierung nicht etwas ist was man mal eben den Nachbarsjungen machen läst, sondern in die Hand von wirklichen Profis gehört.

          Viele Grüße tomIRL

          1. Hallo TomIRL,

            [...] (alles wichtig!)
            (Nachfolgendes redigiert)

            Wenn man in diesem Forum an anderer Stelle liest, das beim Error Log 'Notices' logged werden, dann frage ich mich warum er die Skripte nicht einfach so umbaut, dass  die Notices nicht mehr auftauchen....

            Genau DAS sollte endlich mal thematisiert werden.
            Notices gehöhen zu den wichtigsten Fehlermeldungen in PHP, das die Scripte trotz Notice weiterlaufen. Genauso wichtig ist das Verhalten von PHP nach einem misslungenen include(). Auch hier läuft das Script weiter.

            Entweder, die PHP-Entwickler führen einen "kick-off"-Mode als Default ein, der alle Scripte bereits nach dem kleinsten unbehandelten Fehler verabschiedet, oder wir müssen zumindest immer wieder dafür plädieren, alle Fehler anzeigen zu lassen!

            Das Netz wird mit jedem "wieso, es funzt doch"-Kandidaten unbrauchbarer!

            LG
            Chris

  2. Hallo Chop-Sui,

    ohne Kenntnis des Quelltextes Deines Scriptes kann man nur Allegemenblabla verbreiten:

    Alle Daten, die von außen in die Header der email Einzug halten, müssen genauestens geprüft werden. Die Header der email steuern den Versand.

    Du musst also nicht nur den Inhalt von "To:" überprüfen, sondern auch den des Feldes "From: xxxxxx", wenn es denn direkt im Header auftaucht, und nicht mur als "mailto: xxxxxx" im Body der email.

    Der Body ist meines Erachtens nach nicht gefährdend.

    LG
    Chris

    1. Im Quelltext ist der Empänger und der Absender "hart-kodiert". Daher verstehe ich nicht, wo dort eine Lücke sein soll....

      ---------------------------------

      Hallo, hier ist der Code:

      function cms_send_mail($mail_to,$mail_subject,$mail_body,$mail_type,$reply_email)

      {

      $mail_parts["mail_type"] = $mail_type;
         $mail_parts["mail_to"] = $mail_to;

      $mail_parts["mail_from"] = $reply_email;

      $mail_parts["mail_reply_to"] = $reply_email;
         $mail_parts["mail_subject"] = trim($mail_subject);
         $mail_parts["mail_body"] = $mail_body;

      if(cms_my_mail($mail_parts))
            return true;
         else
            return false;

      }

      function cms_my_mail($mail_parts)
      {

      $mail_to = $mail_parts["mail_to"];
         $mail_from = $mail_parts["mail_from"];
         $mail_reply_to = $mail_parts["mail_reply_to"];
         $mail_subject = $mail_parts["mail_subject"];
         $mail_body = $mail_parts["mail_body"];
         $mail_type = $mail_parts["mail_type"];
         $mail_to = str_replace(";", ",", $mail_to);
         $mail_headers = '';

      if(!empty($mail_from)) $mail_headers .= "From: $mail_from\n";
         if(!empty($mail_reply_to)) $mail_headers .= "Reply-to: $mail_reply_to\n";
         if(!empty($mail_cc))
                  $mail_headers .= "Cc: " . str_replace(";", ",", $mail_cc) . "\n";
         if(!empty($mail_bcc))
                  $mail_headers .= "Bcc: " . str_replace(";", ",", $mail_bcc) . "\n";

      $mail_subject = stripslashes($mail_subject);
         $mail_body = stripslashes($mail_body);

      if($mail_type == "html")
         {
            $mail_headers .= "Content-type: text/html; charset=us-ascii\r\n";
         }
         return mail($mail_to,$mail_subject,$mail_body,$mail_headers,"-f ".$mail_from);
      }

      1. hi,

        Im Quelltext ist der Empänger und der Absender "hart-kodiert". Daher verstehe ich nicht, wo dort eine Lücke sein soll....

        Die Header sind aber nicht fest kodiert, wie's aussieht.

        if(!empty($mail_from)) $mail_headers .= "From: $mail_from\n";
           if(!empty($mail_reply_to)) $mail_headers .= "Reply-to: $mail_reply_to\n";
           if(!empty($mail_cc))
                    $mail_headers .= "Cc: " . str_replace(";", ",", $mail_cc) . "\n";
           if(!empty($mail_bcc))
                    $mail_headers .= "Bcc: " . str_replace(";", ",", $mail_bcc) . "\n";

        Wenn die dort verwendeten Variablen von außerhalb kommen ...

        gruß,
        wahsaga

        --
        /voodoo.css:
        #GeorgeWBush { position:absolute; bottom:-6ft; }
        1. Der Aufruf ist aber fest-kodiert.

          Es wird ein Inhalt generiert (ergibt sich aus den Eingabedaten) und dann wird es an eine feste Adresse geschickt. Das ganze ist dort so aufgebaut, weil ich das auch bei anderen Sachen verwende. Aber in diesem Projekt ist der aufruf dann folgender:

          cms_send_mail($mail_to(fest),$mail_subject(fest),$mail_body(dyn),$mail_type(fest),$reply_email(fest))

          tja... so ist das... Irgendeine Idee? Es kann natürlich sein, dass die mir mist erzählen und dass es eigentlich an Ihnen hängt.

          Gruß
          Chop

          1. Hallo Chop,

            Es wird ein Inhalt generiert (ergibt sich aus den Eingabedaten) und dann wird es an eine feste Adresse geschickt. Das ganze ist dort so aufgebaut, weil ich das auch bei anderen Sachen verwende. Aber in diesem Projekt ist der aufruf dann folgender:

            cms_send_mail($mail_to(fest),$mail_subject(fest),$mail_body(dyn),$mail_type(fest),$reply_email(fest))

            Wie sieht das gesamte Script aus? Wie sind die Einstellungen der php.ini?

            Lass Dir bitte nicht jeden Wurm[1] einzeln aus der Nase ziehen.

            [1] könnte es ja auch noch sein. Welches OS läuft denn beim Provider?

            LG
            Chris

          2. Hallo

            Der Aufruf ist aber fest-kodiert.

            Es wird ein Inhalt generiert (ergibt sich aus den Eingabedaten) und dann wird es an eine feste Adresse geschickt. Das ganze ist dort so aufgebaut, weil ich das auch bei anderen Sachen verwende.

            if(!empty($mail_cc))
                        $mail_headers .= "Cc: " . str_replace(";", ",", $mail_cc) . "\n";
               if(!empty($mail_bcc))
                        $mail_headers .= "Bcc: " . str_replace(";", ",", $mail_bcc) . "\n";

            Und wo kommen $mail_bcc und $mail_cc her?

            Tschö, Auge

            --
            Die Musik drückt aus, was nicht gesagt werden kann und worüber es unmöglich ist zu schweigen.
            (Victor Hugo)
            Veranstaltungsdatenbank Vdb 0.1
      2. Hallo,

        wie gelangen die Parameter ins Script?
        Ist register_globals = ON
        oder noch schlimmer: wird mit extract() gearbeitet?

        Woher kommt $mail_subject?
        Woher kommt $reply_email?

        Das sind die Lücken, die ich spontan vermute und "sehe".

        LG
        Chris

        1. Ist register_globals = ON

          Nein

          Allerdings habe ich eine interne Struktur aufgebaut, die dem register_globals relativ ähnlich kommt... Ich wrappe die GET,POST,und FILE - Arrays und packe sie in eine Klasse. Diese Klasse ruf dann die entsprechenden Methoden auf ,wird über die Variable "$intern" gesteuert. Allerdings gibt es auch sicherungsmechanismen, sprich prüfungen von werten etc...

          Woher kommt $mail_subject?
          Woher kommt $reply_email?

          Ist auch fest , (Siehe das Posting auf wahsagga)

          Gruß
          Chop

          1. Hi Chop,

            Allerdings habe ich eine interne Struktur aufgebaut, die dem register_globals relativ ähnlich kommt... Ich wrappe die GET,POST,und FILE - Arrays und packe sie in eine Klasse.

            Solange Du sie nicht auspackst, also mit extract() oder ähnlichen Mechanismen in "lose" Scriptvariablen überführst, sehe ich da kein Problem.

            Die Script-eigenen Variablen (Konfiguraionsparameter) sollten immer höchst privat bleiben. Ich habe sie bei einigen Scripten allerdings sogar in ein gemeinsames Array gepackt. Das wird man von außen wohl nicht manipulieren können.

            Oder eben mit Konstanten arbeiten. Die können zur Laufzeit nur genau einmal gesetzt werden und bis Scriptende nicht wieder geändert.

            LG
            Chris

            1. ok... vielen Dank für die ganze Hilfe!

              Ich war mir nicht sicher, ob es da eventuell Lücken gibt, die man so normalerweise nicht kennt....

              Ich habe schon von anfang an gedacht, dass das eigentlich nicht so richtig sein kann....

              Ich werd mal sehen, wie und ob sie das belegen können.

              Gruß
              Chop

      3. Moin!

        Im Quelltext ist der Empänger und der Absender "hart-kodiert". Daher verstehe ich nicht, wo dort eine Lücke sein soll....

        Grundsätzlich sind die "Additional Header", also der vierte Parameter der mail()-Funktion, dein Feind. Hier kann man, wenn man in der Lage ist, zusätzliche ZEILEN in den String einzufügen, sowohl weitere Empfänger einfügen, eventuell sogar neuen Mailcontent.

        Denn in diesem String ist das natürliche Trennzeichen für mehrere Header ja auch "\r\n" bzw. "\n" - schafft man es, durch geschickte Inhaltsbelegung der Formularfelder, eine neue Zeile einzufügen, hat der Spammer gewonnen.

        Ein harmlos wirkendes

          
        mail("hartcodiert@example.com", "Betreff: Hartcodiert", "Textinhalt: Hartcodiert", "Cc: $variable_aus_form");  
        
        

        kann fatal werden, wenn man manipuliert, so dass

          
        $variable_aus_form="nr-zwei@example.com\r\nBcc: spammeropfer@example.net";  
        
        

        Dein angegebener Code ist deshalb unvollständig, weil man nicht bis exakt zum Anfang zurückverfolgen kann, welche Inhalte in deinem Mailbefehl

          
        mail($mail_to,$mail_subject,$mail_body,$mail_headers,"-f ".$mail_from);  
        
        

        wirklich durchkommen.

        $mail_headers ist die fragliche Variable, um die es mindestens geht. Ich hatte auch den zweiten Parameter selbst gerade geprüft, dort eingeschmuggelte Zeilenumbrüche wurden aber von meiner PHP-Version in Leerzeichen gewandelt und somit nicht ausgeführt. Das kann aber durchaus bei anderen Versionen oder anderen Mailservern auch schlechter gehandhabt werden - es ist also ein weiteres
        potentielles Angriffsziel.

        $mail_headers setzt sich zusammen aus:

          
            $mail_headers = '';  
            if(!empty($mail_from)) $mail_headers .= "From: $mail_from\n";  
            if(!empty($mail_reply_to)) $mail_headers .= "Reply-to: $mail_reply_to\n";  
            if(!empty($mail_cc)) $mail_headers .= "Cc: " . str_replace(";", ",", $mail_cc) . "\n";  
            if(!empty($mail_bcc)) $mail_headers .= "Bcc: " . str_replace(";", ",", $mail_bcc) . "\n";  
        
        

        Wie man sieht: Es wird richtig eklig, weil jeder der hier verwendeten Variablen, nämlich $mail_from, $mail_reply_to, $mail_cc und $mail_bcc, unbedingt auf eingeschleppte Zeilenschaltungen geprüft werden muß.

        Das ganze sinnlose Ins-Array-Ein-und-wieder-ausgepacke treibt die Unübersichtlichkeit des Codes dabei natürlich noch in die Höhe.

        Entscheidend ist daher eigentlich nur:
        Woher kommen im Funktionsaufruf von
        cms_send_mail($mail_to,$mail_subject,$mail_body,$mail_type,$reply_email)
        die übergebenen Parameter? Insbesondere $mail_to und $reply_email.

        - Sven Rautenberg

        --
        My sssignature, my preciousssss!
        1. Lieber Sven,

          Ein harmlos wirkendes

          mail("hartcodiert@example.com", "Betreff: Hartcodiert", "Textinhalt: Hartcodiert", "Cc: $variable_aus_form");

          
          > kann fatal werden, wenn man manipuliert, so dass  
          > ~~~php
            
          
          > $variable_aus_form="nr-zwei@example.com\r\nBcc: spammeropfer@example.net";
          
          

          AHAA! Jetzt wird mir so manches klarer! Das ist sehr wichtig und sollte unbedingt in den Feature-Artikeln zum Formmailer hinzugefügt werden!

          $mail_headers setzt sich zusammen aus:

          $mail_headers = '';
              if(!empty($mail_from)) $mail_headers .= "From: $mail_from\n";
              if(!empty($mail_reply_to)) $mail_headers .= "Reply-to: $mail_reply_to\n";
              if(!empty($mail_cc)) $mail_headers .= "Cc: " . str_replace(";", ",", $mail_cc) . "\n";
              if(!empty($mail_bcc)) $mail_headers .= "Bcc: " . str_replace(";", ",", $mail_bcc) . "\n";

          
          > Wie man sieht: Es wird richtig eklig, weil jeder der hier verwendeten Variablen, nämlich $mail\_from, $mail\_reply\_to, $mail\_cc und $mail\_bcc, unbedingt auf eingeschleppte Zeilenschaltungen geprüft werden muß.  
            
          Dieser Mechanismus ist vielen Scriptautoren sicherlich nicht genügend klar! Daher sollte man den [Tipps&Tricks-Artikel von Stefan Münz (Perl)](http://aktuell.de.selfhtml.org/tippstricks/cgiperl/form-mail/index.htm), als auch [die PHP-Version von Patrick Canterino](http://aktuell.de.selfhtml.org/tippstricks/php/form-mail/index.htm) diesbezüglich erweitern! Für mein Email-Skript hatte ich nämlich letzteren herangezogen, ohne um die echten Gefahren zu wissen. Glücklicherweise habe ich den Formmailer wegen Beschimpfungs-Spam nie wirklich in Betrieb genommen, sodass sich diese Sicherheitslücke nie auftat. Aber sicherlich verwenden einige die oben genannten Artikel als Grundlage für ihre Skripte.  
            
          Ich sehe, dass auch die Mail-Funktion von [my little forum](http://www.mylittlehomepage.net/my_little_forum) (welches ich im Einsatz habe) eben diese Prüfungen nicht vornimmt. Werde dem Autor mal eine Mail schicken. Vielleicht tut sich da ja was. ;-)  
            
          Diese Spam-Flut wird ja nicht weniger... deshalb sollte man gehörig auf der Hut sein!  
            
          Liebe Grüße aus [Ellwangen](http://www.ellwangen.de/),  
            
          Felix Riesterer.