SQL-Injection-Filter

Thema wurde von Avenger, 14. April 2015 erstellt.

  1. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Da in den letzten Tagen vermehrt Versuche mit "SQL-Injections" festgestellt wurden, möchte ich die aktuelle Version meines "SQL-Injection-Filters" noch mal vorstellen.

    Dieser erweitert den Standard-Gambio "Input"-Filter, und untersucht "GET"-und "POST"-Parameter auf typische Muster solcher "SQL-Injections"-Versuche.

    Wenn ein solches Muster gefunden wird, dann wird das aus dem Parameter entfernt.

    Der Admin erhält einen entsprechenden Hinweis per eMail.

    Und die IP wird automatisch in die "GProtector"-Blacklist-Datei eingestellt, so dass der Angreifer nur einen Versuch hat!

    Ob der Filter allen Versuchen standhält kann ich nicht garantieren, der Erfindungsreichtum der Hacker ist enorm.

    Aber besser als nichts ist das allemal.

    Evtl. kann man ja gemeinsam bessere Muster (regular expressions) finden, um solche Versuche besser zu erkennen, auch wenn die Hacker sich Mühe geben, die möglichst zu verschleiern...

    Den Inhalt des anhängenden Archivs in die Shop-Root kopieren.

    Wie immer gilt:

    • Anwendung auf das ausschließliche Risiko des Shopbetreibers.
    • Es gibt keinerlei Gewährleistung.
    • Erst in einem Testshop testen.
     

    Anhänge:

  2. Züli

    Züli Erfahrener Benutzer

    Registriert seit:
    5. Mai 2014
    Beiträge:
    61
    Danke erhalten:
    8
    Danke vergeben:
    71
    Zuerst Danke !!!
    Dann eine kurze Frage: Für welche ShopVersionen ist der Filter einsetzbar?
     
  3. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Der sollte eigentlich ab 2.0 für alle passen.
     
  4. Nonito (Gambio)

    Nonito (Gambio) Administrator

    Registriert seit:
    21. April 2011
    Beiträge:
    279
    Danke erhalten:
    134
    Danke vergeben:
    52
    Das System ist so auf jeden Fall schon sehr gut, um die Scanner oder manuelles Herumprobieren auszubremsen. Wenn die Leute aber anfangen ihre SQL-Schlüsselwörter gezielt herumzukodieren, könnte das schwierig werden. Aber da müssen wir gemeinsam, wie du schon sagst, mit der Zeit noch ein paar Muster draufpacken. Was dagegen, wenn wir das so in den Core übernehmen?
     
  5. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Ich denke, dass man über regläre Ausdrücke das sehr verbessern kann.

    Statt nur auf "select" zu testen, könnte man mit der regex "/s.*e.*l.*e.*c.*t.* /i" ein "select" auch erkennen, wenn da Leer- oder andere Zeichen eingestreut werden, was diese Hacker ja auch gerne machen..

    Nein.
     
  6. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Ich habe das mal umgestellt auf die Untersuchung der Parameter mit "regular expressions" statt reinem Textvergleich...

    Man kann dabei nach wie vor die Suchtexte normal definieren

    PHP:
        $this->sqlCommands=array(
          
    'select ',
          
    'select(',
          
    'union ',
          
    'from(',
          
    'concat(',
          
    'convert('
        
    );
    die Umwandlung in einen regulären Ausdruck wird automatisch gemacht.

    Damit kann man schon eine ganze Reihe weiterer Verschleierungen mit eingestreuten Leerzeichen in die SQL-Kommandos erkennen.
     

    Anhänge:

  7. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Eine verbesserte Version....
     

    Anhänge:

  8. Steffen (indiv-style.de)

    Steffen (indiv-style.de) G-WARD 2013/14/15/16

    Registriert seit:
    30. Juni 2011
    Beiträge:
    5.143
    Danke erhalten:
    1.466
    Danke vergeben:
    452
    Beruf:
    Systemadmin, Webentwickler bei Indiv-Style
    Ort:
    PhpStorm
    Läuft das auch unter 2.1 bzw 2.2 ??? (ich denke ja aber fragen kostet ja nix... ;) )
     
  9. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Ja, sollte es...
     
  10. Steffen (indiv-style.de)

    Steffen (indiv-style.de) G-WARD 2013/14/15/16

    Registriert seit:
    30. Juni 2011
    Beiträge:
    5.143
    Danke erhalten:
    1.466
    Danke vergeben:
    452
    Beruf:
    Systemadmin, Webentwickler bei Indiv-Style
    Ort:
    PhpStorm
    Mhhh, so richtig nicht!

    V2.2 Artikeldetailseite!

    http://www.indiv-style.de/de/Module/Gambio-GX2-PDF-Katalog-Deluxe-GX2-V2-1-2-2.html
     
  11. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Wo er Recht hat, hat er Recht...


    Versuche bitte mal diese Version:

    PHP:
    <?php
    /* --------------------------------------------------------------
    pt_sqli_InputFilter.php 2015-04-14 Avenger
    Gambio GmbH
    http://www.gambio.de
    Copyright (c) 2013 Gambio Gambio

    Copyright (c) 2015 Avenger, apprentice@gmx.de
    Remove SQL injection code from parameters

    Released under the GNU General Public License
    --------------------------------------------------------------
    */

    class pt_sqli_InputFilter extends pt_sqli_InputFilter_parent
    {
      var 
    $sqlPatterns;

      function 
    __construct($tagsArray = array (), $attrArray = array (), $tagsMethod 0$attrMethod 0$xssAuto 1)
      {
        
    $user_agent=$_SERVER['HTTP_USER_AGENT'];
        if (
    stripos($user_agent,'sqlmap/')!==false)
        {
          exit();
        }
        
    $this->pattern_separator='.*';
        
    $this->sqlPatterns=array(
          
    'select ',
          
    'select(',
          
    'union ',
          
    'from(',
          
    'concat(',
          
    'convert('
        
    );

        
    //Convert search strings to regex patterns...
        
    foreach ($this->sqlPatterns as $index=>$sqlPattern)
        {
          
    $pattern='';
          for (
    $i=0;$i<strlen($sqlPattern);$i++)
          {
            
    $c=$sqlPattern[$i];
            
    $pattern.=$c.'.*';
          }
          
    $this->sqlPatterns[$index]=str_replace('(','\(',$pattern);
        }
        
    parent::__construct($tagsArray$attrArray$tagsMethod$attrMethod$xssAuto);
      }

      function 
    process($source$get=false)
      {
        
    // clean all elements in this array
        
    foreach ($source as $key=>$values)
        {
          if (!
    is_array($values))
          {
            
    $values=array($values);
          }
          foreach (
    $values as $value)
          {
            
    $value=urldecode($value);
            foreach (
    $this->sqlPatterns as $index=>$sqlPattern)
            {
              
    $found_sql=preg_match('#'.$sqlPattern.'#i',$value);
              if (
    $found_sql)
              {
                
    //Auto-block IP!
                
    if (class_exists('GProtector'))
                {
                  
    $gprotector=new GProtector();
                  
    $ip=$gprotector->get_user_ip();;
                  if (
    $ip<>'127.0.0.1')
                  {
                    if (!
    IS_LOCAL_HOST)
                    {
                      require_once (
    DIR_FS_CATALOG.'includes/classes/class.phpmailer.php');
                      require_once (
    DIR_FS_INC.'xtc_php_mail.inc.php');
                    }
                    if (
    $get)
                    {
                      
    $source_parameter='GET';
                    }
                    else
                    {
                      
    $source_parameter='POST';
                    }
                    
    $two_eol=PHP_EOL.PHP_EOL;
                    
    $mail_body=
                      
    date('d.m.Y, H:i:s').$two_eol.
                      
    "SQL-Injection-Versuch von IP: $ip (".gethostbyaddr($ip).")".$two_eol.
                      
    "In $source_parameter-Paramter '$key=$value;'";
                    
    $gprotector_blacklist_file=DIR_FS_DOCUMENT_ROOT.'GProtector/ip_blacklist.txt';
                    if (
    is_file($gprotector_blacklist_file))
                    {
                      
    $gprotector_blacklist_content=trim(file_get_contents($gprotector_blacklist_file));
                      
    $add_to_blacklist=strpos($gprotector_blacklist_content,$ip)===false;
                    }
                    else
                    {
                      
    $add_to_blacklist=true;
                      
    $gprotector_blacklist_content='';
                    }
                    if (
    $add_to_blacklist)
                    {
                      if (
    $gprotector_blacklist_content)
                      {
                        
    $gprotector_blacklist_content.=PHP_EOL;
                      }
                      
    file_put_contents($gprotector_blacklist_file,$gprotector_blacklist_content.$ip);
                      
    $mail_body.=$two_eol."Die IP '$ip' wurde in der Datei '$gprotector_blacklist_file' blockiert.";
                      
    $mail_body.=$two_eol."Um diese Blockierung aufzuheben, den IP-Eintrag für '$ip' in der Datei '$gprotector_blacklist_file' entfernen.";
                    }
                    if (!
    IS_LOCAL_HOST)
                    {
                      
    $email_address=EMAIL_BILLING_ADDRESS;
                      
    $email_billing_name=EMAIL_BILLING_NAME;
                      
    $gm_mail_status xtc_php_mail(EMAIL_BILLING_ADDRESSEMAIL_BILLING_NAME$email_address$email_billing_name''$email_address$email_billing_name,
                        
    '''''SQL-Injection-Versuch!!!'$mail_body$mail_body);
                    }
                    exit();   
    //Terminate processing
                  
    }
                }
                unset(
    $source[$key]);
              }
            }
          }
        }
        return 
    parent::process($source,$get);
      }
    }
     
  12. Steffen (indiv-style.de)

    Steffen (indiv-style.de) G-WARD 2013/14/15/16

    Registriert seit:
    30. Juni 2011
    Beiträge:
    5.143
    Danke erhalten:
    1.466
    Danke vergeben:
    452
    Beruf:
    Systemadmin, Webentwickler bei Indiv-Style
    Ort:
    PhpStorm
    So funzt das prächtig!!! :)
     
  13. Kai Schoelzke

    Kai Schoelzke Beta-Held

    Registriert seit:
    30. März 2016
    Beiträge:
    3.804
    Danke erhalten:
    548
    Danke vergeben:
    248
  14. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Gut dann hier noch mal die verbesserte Version...
     

    Anhänge:

  15. Kai Schoelzke

    Kai Schoelzke Beta-Held

    Registriert seit:
    30. März 2016
    Beiträge:
    3.804
    Danke erhalten:
    548
    Danke vergeben:
    248
    @ Avenger
    ich habe mal die vorletzte Version in den 2.0.15.1 installiert, eben kam folgender Debug Report.
    Code:
    Level: WARNING(2)
    Message: urldecode() expects parameter 1 to be string, array given
      in /www/htdocs/xxxxxx/gambio/user_classes/overloads/InputFilter/pt_sqli_InputFilter.php:55
    Backtrace: 
    #0  urldecode called at [/www/htdocs/xxxxxx/gambio/user_classes/overloads/InputFilter/pt_sqli_InputFilter.php:55]
    #1  (#pt_sqli_InputFilter) process called at [/www/htdocs/xxxxxx/gambio/includes/application_top.php:231]
    #2  require called at [/www/htdocs/xxxxxx/gambio/gm_ajax.php:14]
    
    Context: Array
    (
        [source] => Array
            (
                [id] => Array
                    (
                        [18] => 60
                    )
    
                [products_qty] => 1
                [products_id] => 128
                [submit_target] => cart
            )
    
        [get] => 
        [key] => id
        [value] => Array
            (
                [18] => 60
            )
    
    )
    
    
    Session: No Session
    
     
  16. Kai Schoelzke

    Kai Schoelzke Beta-Held

    Registriert seit:
    30. März 2016
    Beiträge:
    3.804
    Danke erhalten:
    548
    Danke vergeben:
    248
    Das Problem hat sich mit der neusten Version erledigt, war bei Artikeln mit Attributen.
     
  17. René (Kids-Inhouse)

    René (Kids-Inhouse) Erfahrener Benutzer

    Registriert seit:
    26. September 2011
    Beiträge:
    344
    Danke erhalten:
    67
    Danke vergeben:
    60
    Hi!

    Meine Shop-Version 2.1.5.2, mit Mobile Candy 1.0.8

    Artikel mit Attributen, wenn ich solch einen Artikel in den Warenkorb lege und dann die Anzahl des zu bestellenden Artikels ändere und auf "aktualisieren" klicke, kommt bei mir folgende Fehlermeldung:

    Fehlermeldung.JPG

    Nehme ich den Input-Filter wieder raus, kommt die Fehlermeldung nicht mehr...
     
  18. Steffen (indiv-style.de)

    Steffen (indiv-style.de) G-WARD 2013/14/15/16

    Registriert seit:
    30. Juni 2011
    Beiträge:
    5.143
    Danke erhalten:
    1.466
    Danke vergeben:
    452
    Beruf:
    Systemadmin, Webentwickler bei Indiv-Style
    Ort:
    PhpStorm
    Kann ich bestätigen! Soweit hatte ich noch nicht getestet!
     
  19. Kai Schoelzke

    Kai Schoelzke Beta-Held

    Registriert seit:
    30. März 2016
    Beiträge:
    3.804
    Danke erhalten:
    548
    Danke vergeben:
    248
  20. Avenger

    Avenger G-WARD 2012/13/14/15

    Registriert seit:
    26. April 2011
    Beiträge:
    4.771
    Danke erhalten:
    1.478
    Danke vergeben:
    89
    Wie ist es mit dieser Version:

    PHP:
    <?php
    /* --------------------------------------------------------------
    pt_sqli_InputFilter.php 2015-04-14 Avenger
    Gambio GmbH
    http://www.gambio.de
    Copyright (c) 2013 Gambio Gambio

    Copyright (c) 2015 Avenger, apprentice@gmx.de
    Remove SQL injection code from parameters

    Released under the GNU General Public License
    --------------------------------------------------------------
    */

    class pt_sqli_InputFilter extends pt_sqli_InputFilter_parent
    {
      var 
    $sqlPatterns;

      function 
    __construct($tagsArray = array (), $attrArray = array (), $tagsMethod 0$attrMethod 0$xssAuto 1)
      {
        
    $user_agent=$_SERVER['HTTP_USER_AGENT'];
        if (
    stripos($user_agent,'sqlmap/')!==false)
        {
          exit();
        }
        
    $this->pattern_separator='.*';
        
    $this->sqlPatterns=array();
        
    $this->sqlStrings=array(
          
    'select ',
          
    'select(',
          
    'union ',
          
    'from(',
          
    'concat(',
          
    'convert('
        
    );

        
    //Convert search strings to regex patterns...
        
    foreach ($this->sqlStrings as $index=>$sqlPattern)
        {
          
    $pattern='';
          for (
    $i=0;$i<strlen($sqlPattern);$i++)
          {
            
    $c=$sqlPattern[$i];
            
    $pattern.=$c.'.*';
          }
          
    $this->sqlPatterns[$index]=str_replace('(','\(',$pattern);
        }
        
    parent::__construct($tagsArray$attrArray$tagsMethod$attrMethod$xssAuto);
      }

      function 
    process($source$get=false)
      {
        
    // clean all elements in this array
        
    foreach ($source as $key=>$values)
        {
          if (!
    is_array($values))
          {
            
    $values=array($values);
          }
          foreach (
    $values as $value)
          {
            if (
    is_array($value))
            {
              continue;
            }
            
    $value=urldecode($value);
            foreach (
    $this->sqlPatterns as $index=>$sqlPattern)
            {
              
    $found_sql=preg_match('#'.$sqlPattern.'#i',$value);
              if (
    $found_sql)
              {
                
    //Auto-block IP!
                
    if (class_exists('GProtector'))
                {
                  
    $gprotector=new GProtector();
                  
    $ip=$gprotector->get_user_ip();;
                  if (
    $ip<>'127.0.0.1')
                  {
                    if (!
    IS_LOCAL_HOST)
                    {
                      require_once (
    DIR_FS_CATALOG.'includes/classes/class.phpmailer.php');
                      require_once (
    DIR_FS_INC.'xtc_php_mail.inc.php');
                    }
                    if (
    $get)
                    {
                      
    $source_parameter='GET';
                    }
                    else
                    {
                      
    $source_parameter='POST';
                    }
                    
    $two_eol=PHP_EOL.PHP_EOL;
                    
    $mail_body=
                      
    date('d.m.Y, H:i:s').$two_eol.
                      
    "SQL-Injection-Versuch von IP: $ip (".gethostbyaddr($ip).")".$two_eol.
                      
    "In $source_parameter-Paramter '$key=$value;'";
                    
    $gprotector_blacklist_file=DIR_FS_DOCUMENT_ROOT.'GProtector/ip_blacklist.txt';
                    if (
    is_file($gprotector_blacklist_file))
                    {
                      
    $gprotector_blacklist_content=trim(file_get_contents($gprotector_blacklist_file));
                      
    $add_to_blacklist=strpos($gprotector_blacklist_content,$ip)===false;
                    }
                    else
                    {
                      
    $add_to_blacklist=true;
                      
    $gprotector_blacklist_content='';
                    }
                    if (
    $add_to_blacklist)
                    {
                      if (
    $gprotector_blacklist_content)
                      {
                        
    $gprotector_blacklist_content.=PHP_EOL;
                      }
                      
    file_put_contents($gprotector_blacklist_file,$gprotector_blacklist_content.$ip);
                      
    $mail_body.=$two_eol."Die IP '$ip' wurde in der Datei '$gprotector_blacklist_file' blockiert.";
                      
    $mail_body.=$two_eol."Um diese Blockierung aufzuheben, den IP-Eintrag für '$ip' in der Datei '$gprotector_blacklist_file' entfernen.";
                    }
                    if (!
    IS_LOCAL_HOST)
                    {
                      
    $email_address=EMAIL_BILLING_ADDRESS;
                      
    $email_billing_name=EMAIL_BILLING_NAME;
                      
    $gm_mail_status xtc_php_mail(EMAIL_BILLING_ADDRESSEMAIL_BILLING_NAME$email_address$email_billing_name''$email_address$email_billing_name,
                        
    '''''SQL-Injection-Versuch!!!'$mail_body$mail_body);
                    }
                    exit();   
    //Terminate processing
                  
    }
                }
                unset(
    $source[$key]);
              }
            }
          }
        }
        return 
    parent::process($source,$get);
      }
    }