Hans: Perl als "Hackersprache" - konkrete historische Beispiele?

Hallo Leute,

ich habe neulich etwas über Perl querlesen wollen, unter anderem in einer alten Selfhtml-Version. Dabei bin ich über folgenden Satz gestolpert "Perl gilt als Hacker-Sprache, als eine Sprache, in der man unglaubliche Dinge in einer einzigen Programmanweisung erledigen kann [...]" http://www.aip.de/groups/soe/local/handbuch/html/tebb.htm (z.B. hier abrufbar).

Mich würde interessieren, was mit einer solchen Aussage konkret gemeint sein könnte, auch in den folgenden Sätzen.

Vor ca. 15 Jahren habe ich mich zum ersten Mal mit Perl beschäftigt. Mir ist nichts über den Weg gelaufen, was ich darunter hätte verstehen können. Allerdings kenne ich die Anfänge von Perl und auch des Internets zu wenig. Würde mich freuen, wenn jemand mich historisch aufklären oder konkrete Beispiele nennen könnte. In neueren Dokumenten (z.B. Wiki) habe ich ebenfalls kaum etwas gefunden, das eine so besondere Bewertung von Perl bestätigt. Der Umstand, dass dieses Selfdokument ziemlich alt ist, spielt ja erstmal keine Rolle.

Gruß Hans

  1. Tach!

    Dabei bin ich über folgenden Satz gestolpert "Perl gilt als Hacker-Sprache, als eine Sprache, in der man unglaubliche Dinge in einer einzigen Programmanweisung erledigen kann [...]" http://www.aip.de/groups/soe/local/handbuch/html/tebb.htm (z.B. hier abrufbar).

    Das ist nicht umsonst von unserer Seite aus depubliziert worden. Such dir lieber aktuelle Literatur.

    Mich würde interessieren, was mit einer solchen Aussage konkret gemeint sein könnte, auch in den folgenden Sätzen.

    Man kann damit sehr kompakt Code schreiben, den kein Mensch mehr lesen kann. Such mal nach Code Golf, um Beispiele für solchen Code (auch in andere Sprachen) zu finden. Hacken hat nicht unbedingt was mit Computerkriminalität zu tun. Eigentlich steht der Begriff allgemein für Code schreiben, ihn in die Tastatur hacken. Zur Unterscheidung dazu gibts den Begriff Cracken. Aber oftmals wird von den Laien Hacken als Cracken angesehen. In dem Artikel wird wohl die eigentliche Bedeutung gemeint sein.

    dedlfix.

  2. hi,

    die Schwartzsche Transformation ist typisch Perl: Zeitlos schön 😉

    Ansonsten: Im Umgang mit Handles, Sockets lässt es sich mit Perl gut arbeiten. Perl hat über Jahrzehnte hinweg einen konstanten Grundbestand von ca 100 Builtinfunktionen. Was z.B. in PHP das ArrayMerge, geht mit Perl so %c = (%a, %b); und dann wären evntl. noch die HashSlices zu nennen womit man ganze Listen von Keys in einem Hash mit einer Anweisung anlegen oder löschen kann.

    Meine Perlerfahrungen gehen zurück bis v3, mit Perl kann man wachsen ohne Anwendungen komplett verwerfen zu müssen. Deprecated Functions oder Feaatures gibts kaum.

    Ich werf Dir einfach mal was aktuelles hin und Du sagst dann mal ob Du den Code verstehst:

    my $control = sub{
        my $self = shift;
        if($self->param('dice')){
            my $mode = $self->param('mode') || 'dec2hex';
            my $zahl = $self->ziehung;
            $self->{CONTENT} = $mode eq 'hex2dec' ? sprintf("%02X", $zahl) : sprintf("%03d", $zahl); 
            $self->header('Content-Type','text/plain');
        }
        elsif(my $gegeben = $self->param('gegeben')){
            my $user = $self->trim($self->param('user'));
            if($self->param('mode') eq 'hex2dec'){
                $self->{CONTENT} = eval{
                    $gegeben = hex($gegeben);   
                    $gegeben == $user ? "$user ist Richtig!" : "Falsch! ($gegeben)";
                } || "Alles Falsch!";
            }
            elsif($self->param('mode') eq 'dec2hex'){
                $self->{CONTENT} = eval{
                    my $xuser = $user;
                    my $xgegeben = sprintf "%02X", $gegeben;
                    $user = hex($user);
                    $gegeben == $user ? "$xuser ist Richtig!" : "Falsch! ($xgegeben)";
                } || "Alles Falsch!";
            }
        }
        else{
            die "Parameter nicht zulässig!\n";
        }
    };
    
    

    Und das ist auch so richtig typisch Perl 😉

    Wenn's Dir jedoch nicht gefällt, fang am besten gar nicht erst an damit.

    MfG

    PS: Achja, Typeglobs nicht vergessen. Feine Sache!

    1. $self->{CONTENT} = eval{
          $gegeben = hex($gegeben);   
          $gegeben == $user ? "$user ist Richtig!" : "Falsch! ($gegeben)";
      } || "Alles Falsch!";
      

      Du maskierst nicht kontextgerecht, der Code is anfällig für Cross-site-scripting-Attacken.

      1. $self->{CONTENT} = eval{
            $gegeben = hex($gegeben);   
            $gegeben == $user ? "$user ist Richtig!" : "Falsch! ($gegeben)";
        } || "Alles Falsch!";
        

        Du maskierst nicht kontextgerecht,

        Was müsste denn maskiert werden?

        der Code is anfällig für Cross-site-scripting-Attacken.

        Bitte ganz genau begründen! MfG

      2. $self->{CONTENT} = eval{
            $gegeben = hex($gegeben);   
            $gegeben == $user ? "$user ist Richtig!" : "Falsch! ($gegeben)";
        } || "Alles Falsch!";
        

        Du maskierst nicht kontextgerecht, der Code is anfällig für Cross-site-scripting-Attacken.

        Das ist weder fachlich noch sachlich begründet!

        1. Hallo pl,

          $self->{CONTENT} = eval{
              $gegeben = hex($gegeben);   
              $gegeben == $user ? "$user ist Richtig!" : "Falsch! ($gegeben)";
          } || "Alles Falsch!";
          

          Du maskierst nicht kontextgerecht, der Code is anfällig für Cross-site-scripting-Attacken.

          Das ist weder fachlich noch sachlich begründet!

          Was hat das mit "zu diesem Forum" zu tun?

          Du hast vor knapp einer Stunde nach einer Begründung gefragt, also gibt es keinen Grund zu drängeln.

          Bis demnächst
          Matthias

          --
          Rosen sind rot.
        2. $self->{CONTENT} = eval{
              $gegeben = hex($gegeben);   
              $gegeben == $user ? "$user ist Richtig!" : "Falsch! ($gegeben)";
          } || "Alles Falsch!";
          

          Du maskierst nicht kontextgerecht, der Code is anfällig für Cross-site-scripting-Attacken.

          Das ist weder fachlich noch sachlich begründet!

          Wenn $gegeben die Zahl 0 ist, dann gibt der Vergleich $gegeben == $user auf jeden Fall true zurück. In dem Fall wird die Variable $user unmaskiert ausgegeben. Mehr Details findest du in unserem Kontextwechsel-Artikel im Wiki.

          1. $self->{CONTENT} = eval{
                $gegeben = hex($gegeben);   
                $gegeben == $user ? "$user ist Richtig!" : "Falsch! ($gegeben)";
            } || "Alles Falsch!";
            

            Du maskierst nicht kontextgerecht, der Code is anfällig für Cross-site-scripting-Attacken.

            Das ist weder fachlich noch sachlich begründet!

            Wenn $gegeben die Zahl 0 ist, dann gibt der Vergleich $gegeben == $user auf jeden Fall true zurück. In dem Fall wird die Variable $user unmaskiert ausgegeben.

            Nein. Und da wird nichts unmaskiert ausgegeben. Weil der Operator == einen numerischen Vergleich einfordert. So wird der ganze Block zu undef und ausgegeben wird "Alles Falsch!"

            MfG

            1. Nein. Und da wird nichts unmaskiert ausgegeben. Weil der Operator == einen numerischen Vergleich einfordert. So wird der ganze Block zu undef und ausgegeben wird "Alles Falsch!"

              Da irrst du dich: http://tpcg.io/totSMv. Wenn einer der beiden Operanden von == ein String ist, wird dieser als numerischer Wert 0 interpretiert. Dadruch ergibt der Vergleich 0 == "iregendwas" immmer true.

              1. Nein. Und da wird nichts unmaskiert ausgegeben. Weil der Operator == einen numerischen Vergleich einfordert. So wird der ganze Block zu undef und ausgegeben wird "Alles Falsch!"

                Da irrst du dich: http://tpcg.io/totSMv. Wenn einer der beiden Operanden von == ein String ist, wird dieser als numerischer Wert 0 interpretiert. Dadruch ergibt der Vergleich 0 == "iregendwas" immmer true.

                Ja: Wenn man alle Warnungen abschaltet. Das ist jedoch nicht empfehlenswert! Vielmehr werden sämtliche Wanungen in den Status einer Exception erhoben, so daß man mit eval{} arbeiten kann, was einem try{}Block entspricht also auf Exceptions prüft.

                Im Übrigen habe ich ja nicht umsonst genau dieses Stückchen CODE gezeigt. Denn die Frage zielte ja in Richtung Hack. So erledigt der eval{}Block gleich mehrere Dinge womit man sich Einiges an Prüfungen valider Benutzereingaben sparen kann. Der Code compiliert schon dann nicht, wenn der hex() Funktion unzulässige Zeichen übergeben wurden. Und natürlich auch dann nicht wenn am Vergleichsoperator Strings ankommen.

                MfG

                PS: Ich habe Dir dies alles auch schon mehrfach erklärt. Es ist nicht zielführend wenn Du immer wieder damit anfängst und dabei jedesmal nur manifestierst daß Du es nicht verstanden hast!

            2. hallo

              So wird der ganze Block zu undef und ausgegeben wird "Alles Falsch!"

              was glaubst du, was dies ausgibt?

              eval{ undef;0; 0=="a"?1:2  } || 42;  # Ausgabe: 1
              
              --
              Neu im Forum! Signaturen kann man ausblenden!
              1. was glaubst du, was dies ausgibt?

                eval{ undef;0; 0=="a"?1:2  } || 42;  # Ausgabe: 1
                

                Bei mir kommt 42 raus und weißt Du auch warum!?

                1. hallo

                  was glaubst du, was dies ausgibt?

                  eval{ undef;0; 0=="a"?1:2  } || 42;  # Ausgabe: 1
                  

                  Bei mir kommt 42 raus und weißt Du auch warum!?

                  Weil dein Perl kaputt ist?

                  --
                  Neu im Forum! Signaturen kann man ausblenden!
                  1. hallo

                    was glaubst du, was dies ausgibt?

                    eval{ undef;0; 0=="a"?1:2  } || 42;  # Ausgabe: 1
                    

                    Bei mir kommt 42 raus und weißt Du auch warum!?

                    Weil dein Perl kaputt ist?

                    Vermutlich weil pl use warnings; eingeschaltet hat (was gut ist), dann aber mit $SIG{__WARN__} = sub{ die @_ }; aus Warnungen Silent Failures macht. Kann man schon so machen, ist dann halt kacke.

                    1. was glaubst du, was dies ausgibt?

                      eval{ undef;0; 0=="a"?1:2  } || 42;  # Ausgabe: 1
                      

                      Bei mir kommt 42 raus und weißt Du auch warum!?

                      Weil dein Perl kaputt ist?

                      Vermutlich weil pl use warnings; eingeschaltet hat (was gut ist),

                      Hat keinen Einfluss auf die Ausgabe 1.

                      natürlich bekommt man die warnung.

                      dann aber mit $SIG{__WARN__} = sub{ die @_ }; aus Warnungen Silent Failures macht. Kann man schon so machen, ist dann halt kacke.

                      habs mal eingefügt:

                      BEGIN {
                      	use CGI::Carp qw(carpout);
                      	open(my $log, ">","error.log") or die("error.log $!\n");
                      	carpout($log);
                      	$SIG{__WARN__} = sub{ die @_ };
                      }
                      

                      Ausgabe wird 42.

                      Das ist tatsächlich kaputtes Perl!

                      --
                      Neu im Forum! Signaturen kann man ausblenden!
                      1. use CGI::Carp qw(carpout);

                        Carp erzeugt einen Backtrace. Wenn es darum geht, Benutzereingaben zu bearbeiten und zu prüfen macht Carp überhaupt keinen Sinn. Der Benutzer will wissen was er falsch gemacht hat und nicht die Zeile wo sich sein Fehler auswirkt!

                        MfG

                        1. use CGI::Carp qw(carpout);
                          

                          Carp erzeugt einen Backtrace. Wenn es darum geht, Benutzereingaben zu bearbeiten und zu prüfen macht Carp überhaupt keinen Sinn. Der Benutzer will wissen was er falsch gemacht hat und nicht die Zeile wo sich sein Fehler auswirkt!

                          Carp gibt einen guten Grund, schlechte Programmierer zu feuern!

                          --
                          Neu im Forum! Signaturen kann man ausblenden!
                  2. hallo

                    was glaubst du, was dies ausgibt?

                    eval{ undef;0; 0=="a"?1:2  } || 42;  # Ausgabe: 1
                    

                    Bei mir kommt 42 raus und weißt Du auch warum!?

                    Weil dein Perl kaputt ist?

                    Ne, weil ich, im Gegensatz zu Dir, genau weiß was ich tu! Und ein eval{}Block macht überhaupt keinen Sinn wenn die Warnungen ausgeschaltet sind!

                    MfG

                    1. was glaubst du, was dies ausgibt?

                      eval{ undef;0; 0=="a"?1:2  } || 42;  # Ausgabe: 1
                      

                      Bei mir kommt 42 raus und weißt Du auch warum!?

                      Weil dein Perl kaputt ist?

                      Ne, weil ich, im Gegensatz zu Dir, genau weiß was ich tu! Und ein eval{}Block macht überhaupt keinen Sinn wenn die Warnungen ausgeschaltet sind!

                      Du, ich habe warnings immer an.

                      Aber es steht dir natürlich frei, das Verhalten deines Perl so zu manipulieren, dass keiner mehr deinen Code nachvollziehen kann.

                      --
                      Neu im Forum! Signaturen kann man ausblenden!
                      1. @beatovich

                        Aber es steht dir natürlich frei, das Verhalten deines Perl so zu manipulieren, dass keiner mehr deinen Code nachvollziehen kann.

                        Darum gehts hier gar nicht. Ich versuche hier nur, Dir den Sinn eines eavl{}Block zu erklären und wie man sowas benutzt, seinen Code zu vereinfachen.

                        Und wer das einmal verstanden hat, kann auch den Code nachvollziehen!

                        MfG

                        1. hallo

                          Darum gehts hier gar nicht. Ich versuche hier nur, Dir den Sinn eines eavl{}Block zu erklären und wie man sowas benutzt, seinen Code zu vereinfachen.

                          Nein das tust du eben nicht!

                          --
                          Neu im Forum! Signaturen kann man ausblenden!
                    2. Ne, weil ich, im Gegensatz zu Dir, genau weiß was ich tu!

                      Woher sollen wir auch wissen was du tust, wenn du es nicht kommunizierst? Der Code, den du hier vorgelegt hast, hat einen Bug, der sogar eine Sicherheitslücke zur Folge hat. Das ist ja erstmal Fakt. Du behauptest nun, dass du irgendwas getan hast, damit das nicht so ist, erklärst aber auch nicht was. Das behebt den Fehler in deinem Code natürlich nicht.

                      1. Hallo 1unitedpower,

                        aber haben wir so nicht prima gezeigt, dass Perl eine Hackersprache ist?

                        Rolf

                        --
                        sumpsi - posui - clusi
                        1. hallo

                          aber haben wir so nicht prima gezeigt, dass Perl eine Hackersprache ist?

                          Es gibt Dinge in anderen Sprachen, die mich erschrecken.

                          In Javascript kannst du versehentlich interne oder DOM Methoden oder Objekte überschreiben. Das kann dir in Perl nicht passieren.

                          Wären die Browserkonsolen nicht so mächtig, wärst du heute echt aufgeschmissen. Dahingegen ist es in Perl und anderen Sprachen recht einfach, Kontrollen auszugeben und zu verwalten, und das seit es diese Sprachen gibt.

                          --
                          Neu im Forum! Signaturen kann man ausblenden!
                        2. @Rolf B

                          aber haben wir so nicht prima gezeigt, dass Perl eine Hackersprache ist?

                          Genau darauf wollte ich hinaus: Es gibt Perlcode der sieht buggy aus, in Fakt jedoch alles Andere als buggy ist! Und das Warum habe ich auch erklärt, hab sogar einen Artikel darüber geschrieben, der den Kern der Sache trifft!

                          Und wer den Anspruch erhebt, hier ein Fachforum betreiben zu wollen, sollte das auch erkennen!

                          MfG

                          1. Genau darauf wollte ich hinaus: Es gibt Perlcode der sieht buggy aus, in Fakt jedoch alles Andere als buggy ist!

                            Dann ist dein Beispiel schlecht gewählt. Denn es sieht nicht nur so aus, es hat tatsächlich eine Sicherheitslücke.

                          2. @Rolf B

                            aber haben wir so nicht prima gezeigt, dass Perl eine Hackersprache ist?

                            Genau darauf wollte ich hinaus: Es gibt Perlcode der sieht buggy aus, in Fakt jedoch alles Andere als buggy ist!

                            Und noch ein neueres Beispiel:

                            print JSON->new->utf8(0)->encode($hunt);
                            

                            Wer nicht genau weiß wie Perl mit UTF-8 umgeht, könnte anhand dieser Zeile meinen, daß da kein UTF-8 ausgegeben wird, indes: Weit gefehlt!! Und ganz im Gegenteil: Man muss das sogar so notieren wenn vorher mit UTF-8-kodierten Zeichenketten operiert wurde! Weil print() nach STDOUT geht und da gibt es eben keine Kodierung sondern nur noch Bytes.

                            Schönes Beispiel 😉

                            Aber so richig neu isses auch nicht, es zieht sich durch Perl seit v5.8 in etwa. Und das ist auch schon wieder 10 Jahre her.

    2. problematische Seite

      Da die Diskussion mal wieder sinnlos ausufert, hier eine Erklärung, was den Sinn dieses Konstruktes ausmacht, wie es zu verstehen ist und wie es benutzt wird:

      my $x = 'FF';
      my $d = '255';
      
      print eval{
          $x =~ /^[0-9a-fA-F]+$/ or die "Wrong format for hex!\n";
          $d =~ /^\d+$/ or die "Wrong format for decimal!\n";
          $x = hex($x);
          $x == $d ? "Even" : "Odd";
      } || $@;
      

      Fällt in einem eval{}Block eine Exception, ist die Rückgabe nicht näher definiert und der zur Exception gehörige Fehlertext ist in $@ zu finden. Damit kann man den Code vereinfachen dadurch daß einfach eine Exception geworfen wird anstatt alle Prüfungen in eine Kontrollstuktur zu setzen.

      Obenstehender Code hat also Benutzereingaben zu prüfen, insbesondere ob die Zahlen im richtigen Format sind. Sollte das nicht der Fall sein, wird eine Ex geworfen bspw. die "Wrong format for hex!\n"; wobei der angehängte Zeilenvorschub bewirkt, daß kein Backtrace erzeugt wird.

      Im Fehlerfall an $x geht also Wrong format for hex! in die print()-Ausgabe. Analog wird mit der anderen Zahl verfahren. Sofern beide Zahlen im richtigen Format vorliegen, gibt der eav{}Block das Ergebnis der in diesem Block notierten letzten Zeile zurück, bei Gleichheit also Even ansonsten Odd.

      Wenn man sicherstellen kann, daß sich Funktionen erwartungsgemäß verhalten kann man die Prüfung auch der Funktion selbst überlassen:

      my $x = 'x';
      my $d = '255';
      
      print eval{
          $d =~ /^\d+$/ or die "Wrong format for decimal!\n";
          $x = hex($x) or die "Wrong format for hex!\n";
          $x == $d ? "Even" : "Odd";
      } || $@;
      

      und den Code damit weiter vereinfachen. Mit die() geworfene Exceptions werden also aufgefangen, das Programm endet mit status 0. Wer seine Module aus der Hand gibt, sollte anstelle die() jedoch Carp::croak() oder ::confess() verwenden womit in jedem Fall ein Backtrace erzeugt wird der für den Anwender gedacht ist. Authoren ungezählter Module, die auf CPAN zu finden sind, setzen Konstrukte dieser Art erfolgreich ein.

      MfG

      Artikel

      1. problematische Seite

        hallo

        Wenn man sicherstellen kann, daß sich Funktionen erwartungsgemäß verhalten kann man die Prüfung auch der Funktion selbst überlassen:

        Ich möchte den Output einer Funktion nun nicht dahingehend parsen müssen, ob der Rückgabewert eine Errormessage ist.

        Wenn Funktionen Errorstatus ausgeben, dann sollen sie das getrennt vom Content tun.

        --
        Neu im Forum! Signaturen kann man ausblenden!
        1. problematische Seite

          hallo

          Wenn man sicherstellen kann, daß sich Funktionen erwartungsgemäß verhalten kann man die Prüfung auch der Funktion selbst überlassen:

          Ich möchte den Output einer Funktion nun nicht dahingehend parsen müssen, ob der Rückgabewert eine Errormessage ist.

          Wenn Funktionen Errorstatus ausgeben, dann sollen sie das getrennt vom Content tun.

          Genau das kannst Du mit dem hier gezeigten Konstrukt bestens tun! MfG

      2. problematische Seite

        Da die Diskussion mal wieder sinnlos ausufert, hier eine Erklärung, was den Sinn dieses Konstruktes ausmacht, wie es zu verstehen ist und wie es benutzt wird:

        Ausufernd finde ich nur dieses Posting. Anstatt die Sicherheitslücke in deinem ersten Beispiel zu diskutieren, bringst du nun ein völlig neues Code-Beispiel. Niemand hat generelle Einwände gegen Perl oder eval erhoben, es ging hier nur um den gezeigten Code – der buggy ist.

    3. Hallo,

      so recht den Durchblick habe ich nicht, was die Lesbarkeit angeht. Aber darin war ich noch nie der Beste.

      Gruß Hans

      1. problematische Seite

        Moin,

        nun, die Lesbarkeit obliegt stets einer eigenen Entscheidung. Ein schöner Hack ist die Vorbelegung von Funktionsargumenten mit Default-Values, in Perl ist das ganz einfach:

        use strict;
        use warnings;
        use Carp;
        
        sub new{
            my $class = shift;
            # Numbers decimal, hexadecimal
            my %nr = (
                dec => 0,
                hex => 0,
            @_);
        
            return eval{
                croak "Wrong format for hexadecimal number!"
                    unless $nr{hex} =~ /^[0-9a-fA-F]+$/;
                croak "Wrong format for decimal number!"
                    unless $nr{dec} =~ /^\d+$/;
                my $self = bless{
                    hex => hex($nr{hex}),
                    dec => $nr{dec}
                }, $class;
                $self->compare() or carp "The numbers are not equal!";
                $self;
            };
        }
        
        sub compare{
            my $self = shift;
            $self->{hex} == $self->{dec};
        }
        
        my $m = main->new( hex => 'FF', dec => 255 ) or die $@;
        

        Also eine kontextgerechte Verwendung der Perlinternen Variable @_ die sehr vielgestaltig sein kann. Es gibt eine ganze Reihe vordefinierter Variablen die u.a. auch das Verhalten nachgelagerter Funktionen bestimmen, Beispiel:

            $,      The output field separator for the print operator. If defined,
                    this value is printed between each of print's arguments. Default
                    is "undef".
        
        
        
        local $, = "\n";
        print 1, 2, 3;
        

        Was bewirkt, daß im Listenkontext von print() jedes Element auf einer eigenen Zeile ausgegeben wird. perldoc perlvar gibt diese vordefinierten Variablen samt Beschreibung aus.

        Nochn Hack:

        $, = "\n";
        print stat($0), stat(_) ;
        

        Ausgegeben wird 2x dasselbe, nämlich das was stat() für das eigene Script ermittelt was mit vollständiger Pfadangabe in $0 zu finden ist. Beim 2. Aufruf der stat() wird jedoch anstelle $0 das UnderscoreHandle _ verwendet, was nunmehr auf $0 zeigt.

        Aber bei _ wie auch bei $_ muss man schon sehr genau hingucken, daß da auch daß drinsteht was man erwartet.

        Hash Slice

        my %stat = ();
        @stat{qw(dev ino mode nlink uid gid rdev size atime mtime ctime blkize blocks)} =
            stat($0);
        
        print ''.localtime $stat{mtime};
        

        MfG