Logo name

Ipb 2.1:Improving GD Anti-Spam Image

From IpbWiki

  • Currently0.00/5
Jump to: navigation, search

Contents

Introduction

This article will discuss how to increase the security of the default GD Anti-Spam image. This is in no way fool proof but it is a lot stronger than the default setup.

Step. 1

First step is to create a folder in the ./ directory of IPB called fonts and upload some clean .ttf fonts. Arial and Comic Sans MS look good with this mod.

Step. 2

Open ./sources/ipsclass.php

Find:

CODE
function show_gd_img($content="")
   {
       $content = '  '. preg_replace( "/(\w)/", "\\1 ", $content ) .' ';
       
       @header("Content-Type: image/jpeg");
       
       $tmp_x = 140;
       $tmp_y = 20;
       
       $image_x = 210;
       $image_y = 65;
       
       $circles = 3;
       
       if ( $this->vars['gd_version'] == 1 )
       {
           $tmp = imagecreate($tmp_x, $tmp_y);
           $im  = imagecreate($image_x, $image_y);
       }
       else
       {
           $tmp = imagecreatetruecolor($tmp_x, $tmp_y);
           $im  = imagecreatetruecolor($image_x, $image_y);
       }
       
       $white  = ImageColorAllocate($tmp, 255, 255, 255);
       $black  = ImageColorAllocate($tmp, 0, 0, 0);
       $grey   = ImageColorAllocate($tmp, 210, 210, 210 );
       
       imagefill($tmp, 0, 0, $white);
       
       for ( $i = 1; $i <= $circles; $i++ )
       {
           $values = array(
                           0  => rand(0, $tmp_x - 10),
                           1  => rand(0, $tmp_y - 3),
                           2  => rand(0, $tmp_x - 10),
                           3  => rand(0, $tmp_y - 3),
                           4  => rand(0, $tmp_x - 10),
                           5  => rand(0, $tmp_y - 3),
                           6  => rand(0, $tmp_x - 10),
                           7  => rand(0, $tmp_y - 3),
                           8  => rand(0, $tmp_x - 10),
                           9  => rand(0, $tmp_y - 3),
                           10 => rand(0, $tmp_x - 10),
                           11 => rand(0, $tmp_y - 3),
                        );
     
           $randomcolor = imagecolorallocate( $tmp, rand(100,255), rand(100,255),rand(100,255) );
           imagefilledpolygon($tmp, $values, 6, $randomcolor );
       }

       imagestring($tmp, 5, 0, 2, $content, $black);
       
       //-----------------------------------------
       // Distort by resizing
       //-----------------------------------------
       
       imagecopyresized($im, $tmp, 0, 0, 0, 0, $image_x, $image_y, $tmp_x, $tmp_y);
       
       imagedestroy($tmp);
       
       $white   = ImageColorAllocate($im, 255, 255, 255);
       $black   = ImageColorAllocate($im, 0, 0, 0);
       $grey    = ImageColorAllocate($im, 100, 100, 100 );
       
       $random_pixels = $image_x * $image_y / 10;
           
       for ($i = 0; $i < $random_pixels; $i++)
       {
           ImageSetPixel($im, rand(0, $image_x), rand(0, $image_y), $black);
       }
       
       $no_x_lines = ($image_x - 1) / 5;
       
       for ( $i = 0; $i <= $no_x_lines; $i++ )
       {
           // X lines
           
           ImageLine( $im, $i * $no_x_lines, 0, $i * $no_x_lines, $image_y, $grey );
           
           // Diag lines
           
           ImageLine( $im, $i * $no_x_lines, 0, ($i * $no_x_lines)+$no_x_lines, $image_y, $grey );
       }
       
       $no_y_lines = ($image_y - 1) / 5;
       
       for ( $i = 0; $i <= $no_y_lines; $i++ )
       {
           ImageLine( $im, 0, $i * $no_y_lines, $image_x, $i * $no_y_lines, $grey );
       }
       
       ImageJPEG($im);
       ImageDestroy($im);
       
       exit();
   }

Replace With:

CODE
function show_gd_img($content="")
   {
       $content = preg_replace( "/(\w)/", "\\1 ", $content );

       $textarray = explode(' ', $content);

       //---------------------------
       // Options
       //---------------------------
       $super_captcha = 0;            // One of the stronger Captcha Avalible through this mod

       $use_jpg = 0;                // Only turn this off if you dont want to use JPG backgrounds, if none are uploaded this has no effect
       $use_ttf = 1;                // Use TTF fonts, if none are uploaded this has no effect
       $use_gdf = 0;                // Use GDF fonts, TTF fonts will take preferance, if none are uploaded this has no effect

       $fonts_dir = ROOT_PATH.'fonts/';    // The directory were all fonts and jpgs are uploaded to

       //---------------------------
       // No More Options to play with
       //---------------------------

       $tmp_x = 160;
       $tmp_y = 30;
       
       $image_x = 210;
       $image_y = 65;
       
       $circles = 3;

       //-----------------------------
       // Get information from folder
       //-----------------------------
       $dh = opendir( $fonts_dir );
       $fonts = array();
       while ($icon = readdir($dh)) {
           if(preg_match("/(.gdf)/",$icon) && $use_gdf) {
               if($icon != '.' || $icon  != '..') {
                   $gdf_fonts[] = $icon;
               }
           }
           if(preg_match("/(.ttf)/",$icon) && $use_ttf) {
               if($icon != '.' || $icon  != '..') {
                   $ttf_fonts[] = $icon;
               }
           }
           if(preg_match("/(.jpg)/",$icon) && $use_jpg) {
               if($icon != '.' || $icon  != '..') {
                   $jpg_files[] = $icon;
               }
           }
       }
       closedir($dh);
       
       $jpg_max = count($jpg_files) - 1;
       $gdf_max = count($gdf_fonts) - 1;
       $ttf_max = count($ttf_fonts) - 1;

       @header("Content-Type: image/jpeg");
               
       if ( $this->vars['gd_version'] == 1 ) {
           $tmp = imagecreate($tmp_x, $tmp_y);
           $im  = imagecreate($image_x, $image_y);
       } else {
           $tmp = imagecreatetruecolor($tmp_x, $tmp_y);
           $im  = imagecreatetruecolor($image_x, $image_y);
       }

       //------------------------------
       // Super Captcha
       //------------------------------
       if($super_captcha) {
           $color1 = rand(100,200);
           $color2 = rand(100,200);
           $color3 = rand(100,200);

           $color = imageColorAllocate($tmp, $color1, $color2, $color3);
           $textcolor = imageColorAllocate($tmp, $color1 - 10, $color2 - 10, $color3 - 10);

           imagefill($tmp, 0, 0, $color);

           $shadowcode = rand(20, 50);
           $shadowcolor = ImageColorAllocate($tmp, $color1 - 100, $color2 - 100, $color3 - 100 );

           foreach($textarray AS $number) {

               $rand = rand(0, $ttf_max);

               // Only Slight Changes in font size and angle
               $fontsize = rand(14,17);
               $angle = rand(-10,10);

               $aCharDetails = imageftbbox($fontsize, $angle, $fonts_dir."/".$ttf_fonts[$rand], $number);
               
               $iCharHeight = $aCharDetails[2] - $aCharDetails[5];
               $iY = $tmp_y / 2 + $iCharHeight / 4 + rand(-3, 3);

               $rand = rand(0, $ttf_max);

               $offsetx = 2;
               $offsety = 2;
                 
               imagefttext($tmp, $fontsize, $angle, $i + $offsetx, $iY + $offsety, $shadowcolor, $fonts_dir."/".$ttf_fonts[$rand], $number);
               
               imagefttext($tmp, $fontsize, $angle, $i, $iY, $textcolor, $fonts_dir."/".$ttf_fonts[$rand], $number);

               $i = $i + rand(20, 45 - $fontsize);
           }
       }else {
           if(count($jpg_files) > 0) {
               $rand = rand(0, $jpg_max);
               $temp = imagecreatefromjpeg($fonts_dir."/".$jpg_files[$rand]);
               list($width, $height) = getimagesize($fonts_dir."/".$jpg_files[$rand]);

               imagecopyresized($tmp, $temp, 0, 0, 0, 0, $tmp_x, $tmp_y, $width, $height);    
           }else{
               imagefill($tmp, 0, 0, ImageColorAllocate($tmp, rand(240,250), rand(240,250), rand(240,250)));

               for ( $i = 1; $i <= $circles; $i++ )
               {
                   $values = array(
                                   0  => rand(0, $tmp_x - 10),
                                   1  => rand(0, $tmp_y - 3),
                                   2  => rand(0, $tmp_x - 10),
                                   3  => rand(0, $tmp_y - 3),
                                   4  => rand(0, $tmp_x - 10),
                                   5  => rand(0, $tmp_y - 3),
                                   6  => rand(0, $tmp_x - 10),
                                   7  => rand(0, $tmp_y - 3),
                                   8  => rand(0, $tmp_x - 10),
                                   9  => rand(0, $tmp_y - 3),
                                   10 => rand(0, $tmp_x - 10),
                                   11 => rand(0, $tmp_y - 3),
                                );
             
                   $randomcolor = imagecolorallocate( $tmp, rand(150,200), rand(150,200),rand(150,200) );
                   imagefilledpolygon($tmp, $values, 6, $randomcolor );
               }
           }
           
           if(count($textarray) == 5) {
               $min = 30;
               $max = 40;
           }else if(count($textarray) == 6) {
               $min = 20;
               $max = 30;
           }else{
               $min = 2;
               $max = 10;
           }

           $i = rand($min, $max);
           foreach($textarray AS $number) {
               $color = ImageColorAllocate($tmp, rand(50, 150), rand(50, 150), rand(50, 150) );
               $shadowcolor = ImageColorAllocate($tmp, rand(50, 100), rand(50, 100), rand(50, 100) );

               if(count($ttf_fonts) > 0) {    
                   $rand = rand(0, $ttf_max);

                   $fontsize = rand(18, 20);
                   $angle = rand(-30, 30);

                   $aCharDetails = imageftbbox($fontsize, $angle, $fonts_dir."/".$ttf_fonts[$rand], $number);
               
                   $iCharHeight = $aCharDetails[2] - $aCharDetails[5];
                   $iY = $tmp_y / 2 + $iCharHeight / 4 + rand(-3, 3);

                   $rand = rand(0, $ttf_max);

                   $offsetx = rand(1, 2);
                   $offsety = rand(1, 2);
                 
                   imagefttext($tmp, $fontsize, $angle, $i + $offsetx, $iY + $offsety, $shadowcolor, $fonts_dir."/".$ttf_fonts[$rand], $number);
                   
                   imagefttext($tmp, $fontsize, $angle, $i, $iY, $color, $fonts_dir."/".$ttf_fonts[$rand], $number);

                   $i = $i + rand(20, 45 - $fontsize);
               }else{
                   if(count($gdf_fonts) > 0) {
                       $rand = rand(0, $gdf_max);
                       $font = imageloadfont($fonts_dir."/".$gdf_fonts[$rand]);
                   }else{
                       $font = rand(15,20);
                   }

                   $height = rand(0, 10);

                   $offsetx = rand(1, 2);
                   $offsety = rand(1, 2);

                   imagestring($tmp, $font, $i + $offsetx, $height + $offsety, $number, $shadowcolor);

                   imagestring($tmp, $font, $i, $height, $number, $color);

                   $i = $i + rand(20, 30);
               }
           }
       }

       //-----------------------------------------
       // Distort by resizing
       //-----------------------------------------
       
       imagecopyresized($im, $tmp, 0, 0, 0, 0, $image_x, $image_y, $tmp_x, $tmp_y);
       
       imagedestroy($tmp);

       if($super_captcha) {
           $grey = $shadowcolor;
       }else{
           $random = rand(0,20);
           $grey = ImageColorAllocate($im, $random, $random, $random );
       }

           
       $random_pixels = $image_x * $image_y / 10;

       for ($i = 0; $i < $random_pixels; $i++) {
           $random = rand(0, 255);
           $pixelcolor = ImageColorAllocate($im, $random, $random, $random );
           ImageSetPixel($im, rand(0, $image_x), rand(0, $image_y), $pixelcolor);
       }
       
       $no_x_lines = ($image_x - 1) / 10;
       
       for ( $i = 0; $i <= $no_x_lines; $i++ ) {
           ImageLine( $im, $i * $no_x_lines, 0, $i * $no_x_lines, $image_y, $grey );
       }
       
       $no_y_lines = ($image_y - 1) / 5;
       
       for ( $i = 0; $i <= $no_y_lines; $i++ ) {
           ImageLine( $im, 0, $i * $no_y_lines, $image_x, $i * $no_y_lines, $grey );
       }
       
       ImageJPEG($im);
       ImageDestroy($im);
       
       exit();
   }

Save & Upload!

Conclusion

Test it, and see if it works, if not reverse the steps.

The more fonts you add the hard it is to crack your anti-spam image. Some fonts don't work well and will be hard to read so watch out for that.

You will notice there is more options which I havn't covered. This will increase the security of the Anti-Spam Image, but also make it hard to read. To use Jpg upload a 210 x 65 jpg into the fonts folder and swtich the 0 to 1 on the jpg option. This will use the JPG as a background image, make sure you use light pictures or it will be impossible to see the text.

The Super option should only be used under extreme bot attacks and will stop some users from registering. It uses depth perseption and some users will not be able to read this as much as they try.

This page was last modified on 11 November 2006, at 15:08.  This page has been accessed 4,460 times.  Content is available under GNU Free Documentation License 1.2Disclaimers