file extension restriction

  • seularts
  • Graduate
  • Graduate
  • User avatar
  • Posts: 153
  • Loc: Romania

Post 3+ Months Ago

Here is a dub question. If this code is supposed to restrict files other than jpg, png and gif, why does it do it? This is for a file browser aplication. The image has to be one of the 3 accepted file extensions.

Code: [ Select ]
$ext - is the var that reads the file extensions, such as exe and so on.

if (($ext == "jpg" || "gif" || "png") && ($_FILES["uploaded_file"]["type"] == "image/jpeg" || "image/gif" || "image/png") && ($_FILES["uploaded_file"]["size"] < 1000000)){

echo 'something';

}else(
echo 'none';
)
  1. $ext - is the var that reads the file extensions, such as exe and so on.
  2. if (($ext == "jpg" || "gif" || "png") && ($_FILES["uploaded_file"]["type"] == "image/jpeg" || "image/gif" || "image/png") && ($_FILES["uploaded_file"]["size"] < 1000000)){
  3. echo 'something';
  4. }else(
  5. echo 'none';
  6. )


I really don't see the mistake.
  • Anonymous
  • Bot
  • No Avatar
  • Posts: ?
  • Loc: Ozzuland
  • Status: Online

Post 3+ Months Ago

  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13503
  • Loc: Florida

Post 3+ Months Ago

I'm just going to forget everything I know about PHP, and try to figure out what's going on by looking up each part in the PHP source.

For starters, $ext. I need to know where it's coming from. There are multiple ways the extension could be deciphered using PHP. There's pathinfo('filename', PATHINFO_EXTENSION). I don't know how that determines the extension though. Does it just look for an extension on the filename, does it open the file and look at the contents to determine what sort of file it is ?

Since I'm on a Windows system at the moment, I'll use findstr to find the function declaration in the /ext/ directory of my copy of the PHP 5.3.3 source.

Code: [ Select ]
findstr /s /i /n /c:"pathinfo" *.c


which brings me to "standard/string.c" line 1459 to find the declaration.

C Code: [ Select ]
PHP_FUNCTION(pathinfo)
{
   zval *tmp;
   char *path, *ret = NULL;
   int path_len, have_basename;
   size_t ret_len;
   long opt = PHP_PATHINFO_ALL;
 
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &path, &path_len, &opt) == FAILURE) {
      return;
   }
 
   have_basename = ((opt & PHP_PATHINFO_BASENAME) == PHP_PATHINFO_BASENAME);
   
   MAKE_STD_ZVAL(tmp);
   array_init(tmp);
   
   if ((opt & PHP_PATHINFO_DIRNAME) == PHP_PATHINFO_DIRNAME) {
      ret = estrndup(path, path_len);
      php_dirname(ret, path_len);
      if (*ret) {
         add_assoc_string(tmp, "dirname", ret, 1);
      }
      efree(ret);
      ret = NULL;
   }
   
   if (have_basename) {
      php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
      add_assoc_stringl(tmp, "basename", ret, ret_len, 0);
   }
   
   if ((opt & PHP_PATHINFO_EXTENSION) == PHP_PATHINFO_EXTENSION) {
      char *p;
      int idx;
 
      if (!have_basename) {
         php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
      }
 
      p = zend_memrchr(ret, '.', ret_len);
 
      if (p) {
         idx = p - ret;
         add_assoc_stringl(tmp, "extension", ret + idx + 1, ret_len - idx - 1, 1);
      }
   }
   
   if ((opt & PHP_PATHINFO_FILENAME) == PHP_PATHINFO_FILENAME) {
      char *p;
      int idx;
 
      /* Have we alrady looked up the basename? */
      if (!have_basename && !ret) {
         php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
      }
 
      p = zend_memrchr(ret, '.', ret_len);
 
      idx = p ? (p - ret) : ret_len;
      add_assoc_stringl(tmp, "filename", ret, idx, 1);
   }
 
   if (!have_basename && ret) {
      efree(ret);
   }
 
   if (opt == PHP_PATHINFO_ALL) {
      RETURN_ZVAL(tmp, 0, 1);
   } else {
      zval **element;
      if (zend_hash_get_current_data(Z_ARRVAL_P(tmp), (void **) &element) == SUCCESS) {
         RETVAL_ZVAL(*element, 1, 0);
      } else {
         ZVAL_EMPTY_STRING(return_value);
      }
   }
 
   zval_ptr_dtor(&tmp);
}
  1. PHP_FUNCTION(pathinfo)
  2. {
  3.    zval *tmp;
  4.    char *path, *ret = NULL;
  5.    int path_len, have_basename;
  6.    size_t ret_len;
  7.    long opt = PHP_PATHINFO_ALL;
  8.  
  9.    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &path, &path_len, &opt) == FAILURE) {
  10.       return;
  11.    }
  12.  
  13.    have_basename = ((opt & PHP_PATHINFO_BASENAME) == PHP_PATHINFO_BASENAME);
  14.    
  15.    MAKE_STD_ZVAL(tmp);
  16.    array_init(tmp);
  17.    
  18.    if ((opt & PHP_PATHINFO_DIRNAME) == PHP_PATHINFO_DIRNAME) {
  19.       ret = estrndup(path, path_len);
  20.       php_dirname(ret, path_len);
  21.       if (*ret) {
  22.          add_assoc_string(tmp, "dirname", ret, 1);
  23.       }
  24.       efree(ret);
  25.       ret = NULL;
  26.    }
  27.    
  28.    if (have_basename) {
  29.       php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
  30.       add_assoc_stringl(tmp, "basename", ret, ret_len, 0);
  31.    }
  32.    
  33.    if ((opt & PHP_PATHINFO_EXTENSION) == PHP_PATHINFO_EXTENSION) {
  34.       char *p;
  35.       int idx;
  36.  
  37.       if (!have_basename) {
  38.          php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
  39.       }
  40.  
  41.       p = zend_memrchr(ret, '.', ret_len);
  42.  
  43.       if (p) {
  44.          idx = p - ret;
  45.          add_assoc_stringl(tmp, "extension", ret + idx + 1, ret_len - idx - 1, 1);
  46.       }
  47.    }
  48.    
  49.    if ((opt & PHP_PATHINFO_FILENAME) == PHP_PATHINFO_FILENAME) {
  50.       char *p;
  51.       int idx;
  52.  
  53.       /* Have we alrady looked up the basename? */
  54.       if (!have_basename && !ret) {
  55.          php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
  56.       }
  57.  
  58.       p = zend_memrchr(ret, '.', ret_len);
  59.  
  60.       idx = p ? (p - ret) : ret_len;
  61.       add_assoc_stringl(tmp, "filename", ret, idx, 1);
  62.    }
  63.  
  64.    if (!have_basename && ret) {
  65.       efree(ret);
  66.    }
  67.  
  68.    if (opt == PHP_PATHINFO_ALL) {
  69.       RETURN_ZVAL(tmp, 0, 1);
  70.    } else {
  71.       zval **element;
  72.       if (zend_hash_get_current_data(Z_ARRVAL_P(tmp), (void **) &element) == SUCCESS) {
  73.          RETVAL_ZVAL(*element, 1, 0);
  74.       } else {
  75.          ZVAL_EMPTY_STRING(return_value);
  76.       }
  77.    }
  78.  
  79.    zval_ptr_dtor(&tmp);
  80. }


which from the looks of it, determines the extension by tracking backwards through the filename looking for a dot.

This means that it's possible to spoof the extension determined by pathinfo by altering the filename before uploading the file.


Now, since this is images we're working with, there is another way to determine what $ext may be. That is by using the getimagesize function and passing the returned mine constant to the image_type_to_extension() function.

Again, using findstr to track down the function declaration, I'll start by finding out how that mime constant is determined.

Code: [ Select ]
findstr /s /i /n /c:getimagesize" *.c


I find my way to "standard/image.c" line 1294, which gives me this declaration.

C Code: [ Select ]
PHP_FUNCTION(getimagesize)
{
   zval **info = NULL;
   char *arg1, *temp;
   int arg1_len, itype = 0, argc = ZEND_NUM_ARGS();
   struct gfxinfo *result = NULL;
   php_stream * stream = NULL;
 
   if (zend_parse_parameters(argc TSRMLS_CC, "s|Z", &arg1, &arg1_len, &info) == FAILURE) {
      return;
   }
   
   if (argc == 2) {
      zval_dtor(*info);
      array_init(*info);
   }
 
   stream = php_stream_open_wrapper(arg1, "rb", STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|ENFORCE_SAFE_MODE, NULL);
 
   if (!stream) {
      RETURN_FALSE;
   }
 
   itype = php_getimagetype(stream, NULL TSRMLS_CC);
   switch( itype) {
      case IMAGE_FILETYPE_GIF:
         result = php_handle_gif(stream TSRMLS_CC);
         break;
      case IMAGE_FILETYPE_JPEG:
         if (info) {
            result = php_handle_jpeg(stream, *info TSRMLS_CC);
         } else {
            result = php_handle_jpeg(stream, NULL TSRMLS_CC);
         }
         break;
      case IMAGE_FILETYPE_PNG:
         result = php_handle_png(stream TSRMLS_CC);
         break;
      case IMAGE_FILETYPE_SWF:
         result = php_handle_swf(stream TSRMLS_CC);
         break;
      case IMAGE_FILETYPE_SWC:
#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
         result = php_handle_swc(stream TSRMLS_CC);
#else
         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "The image is a compressed SWF file, but you do not have a static version of the zlib extension enabled");
#endif
         break;
      case IMAGE_FILETYPE_PSD:
         result = php_handle_psd(stream TSRMLS_CC);
         break;
      case IMAGE_FILETYPE_BMP:
         result = php_handle_bmp(stream TSRMLS_CC);
         break;
      case IMAGE_FILETYPE_TIFF_II:
         result = php_handle_tiff(stream, NULL, 0 TSRMLS_CC);
         break;
      case IMAGE_FILETYPE_TIFF_MM:
         result = php_handle_tiff(stream, NULL, 1 TSRMLS_CC);
         break;
      case IMAGE_FILETYPE_JPC:
         result = php_handle_jpc(stream TSRMLS_CC);
         break;
      case IMAGE_FILETYPE_JP2:
         result = php_handle_jp2(stream TSRMLS_CC);
         break;
      case IMAGE_FILETYPE_IFF:
         result = php_handle_iff(stream TSRMLS_CC);
         break;
      case IMAGE_FILETYPE_WBMP:
         result = php_handle_wbmp(stream TSRMLS_CC);
         break;
      case IMAGE_FILETYPE_XBM:
         result = php_handle_xbm(stream TSRMLS_CC);
         break;
      case IMAGE_FILETYPE_ICO:
         result = php_handle_ico(stream TSRMLS_CC);
         break;
      default:
      case IMAGE_FILETYPE_UNKNOWN:
         break;
   }
 
   php_stream_close(stream);
 
   if (result) {
      array_init(return_value);
      add_index_long(return_value, 0, result->width);
      add_index_long(return_value, 1, result->height);
      add_index_long(return_value, 2, itype);
      spprintf(&temp, 0, "width=\"%d\" height=\"%d\"", result->width, result->height);
      add_index_string(return_value, 3, temp, 0);
 
      if (result->bits != 0) {
         add_assoc_long(return_value, "bits", result->bits);
      }
      if (result->channels != 0) {
         add_assoc_long(return_value, "channels", result->channels);
      }
      add_assoc_string(return_value, "mime", (char*)php_image_type_to_mime_type(itype), 1);
      efree(result);
   } else {
      RETURN_FALSE;
   }
}
  1. PHP_FUNCTION(getimagesize)
  2. {
  3.    zval **info = NULL;
  4.    char *arg1, *temp;
  5.    int arg1_len, itype = 0, argc = ZEND_NUM_ARGS();
  6.    struct gfxinfo *result = NULL;
  7.    php_stream * stream = NULL;
  8.  
  9.    if (zend_parse_parameters(argc TSRMLS_CC, "s|Z", &arg1, &arg1_len, &info) == FAILURE) {
  10.       return;
  11.    }
  12.    
  13.    if (argc == 2) {
  14.       zval_dtor(*info);
  15.       array_init(*info);
  16.    }
  17.  
  18.    stream = php_stream_open_wrapper(arg1, "rb", STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|ENFORCE_SAFE_MODE, NULL);
  19.  
  20.    if (!stream) {
  21.       RETURN_FALSE;
  22.    }
  23.  
  24.    itype = php_getimagetype(stream, NULL TSRMLS_CC);
  25.    switch( itype) {
  26.       case IMAGE_FILETYPE_GIF:
  27.          result = php_handle_gif(stream TSRMLS_CC);
  28.          break;
  29.       case IMAGE_FILETYPE_JPEG:
  30.          if (info) {
  31.             result = php_handle_jpeg(stream, *info TSRMLS_CC);
  32.          } else {
  33.             result = php_handle_jpeg(stream, NULL TSRMLS_CC);
  34.          }
  35.          break;
  36.       case IMAGE_FILETYPE_PNG:
  37.          result = php_handle_png(stream TSRMLS_CC);
  38.          break;
  39.       case IMAGE_FILETYPE_SWF:
  40.          result = php_handle_swf(stream TSRMLS_CC);
  41.          break;
  42.       case IMAGE_FILETYPE_SWC:
  43. #if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB)
  44.          result = php_handle_swc(stream TSRMLS_CC);
  45. #else
  46.          php_error_docref(NULL TSRMLS_CC, E_NOTICE, "The image is a compressed SWF file, but you do not have a static version of the zlib extension enabled");
  47. #endif
  48.          break;
  49.       case IMAGE_FILETYPE_PSD:
  50.          result = php_handle_psd(stream TSRMLS_CC);
  51.          break;
  52.       case IMAGE_FILETYPE_BMP:
  53.          result = php_handle_bmp(stream TSRMLS_CC);
  54.          break;
  55.       case IMAGE_FILETYPE_TIFF_II:
  56.          result = php_handle_tiff(stream, NULL, 0 TSRMLS_CC);
  57.          break;
  58.       case IMAGE_FILETYPE_TIFF_MM:
  59.          result = php_handle_tiff(stream, NULL, 1 TSRMLS_CC);
  60.          break;
  61.       case IMAGE_FILETYPE_JPC:
  62.          result = php_handle_jpc(stream TSRMLS_CC);
  63.          break;
  64.       case IMAGE_FILETYPE_JP2:
  65.          result = php_handle_jp2(stream TSRMLS_CC);
  66.          break;
  67.       case IMAGE_FILETYPE_IFF:
  68.          result = php_handle_iff(stream TSRMLS_CC);
  69.          break;
  70.       case IMAGE_FILETYPE_WBMP:
  71.          result = php_handle_wbmp(stream TSRMLS_CC);
  72.          break;
  73.       case IMAGE_FILETYPE_XBM:
  74.          result = php_handle_xbm(stream TSRMLS_CC);
  75.          break;
  76.       case IMAGE_FILETYPE_ICO:
  77.          result = php_handle_ico(stream TSRMLS_CC);
  78.          break;
  79.       default:
  80.       case IMAGE_FILETYPE_UNKNOWN:
  81.          break;
  82.    }
  83.  
  84.    php_stream_close(stream);
  85.  
  86.    if (result) {
  87.       array_init(return_value);
  88.       add_index_long(return_value, 0, result->width);
  89.       add_index_long(return_value, 1, result->height);
  90.       add_index_long(return_value, 2, itype);
  91.       spprintf(&temp, 0, "width=\"%d\" height=\"%d\"", result->width, result->height);
  92.       add_index_string(return_value, 3, temp, 0);
  93.  
  94.       if (result->bits != 0) {
  95.          add_assoc_long(return_value, "bits", result->bits);
  96.       }
  97.       if (result->channels != 0) {
  98.          add_assoc_long(return_value, "channels", result->channels);
  99.       }
  100.       add_assoc_string(return_value, "mime", (char*)php_image_type_to_mime_type(itype), 1);
  101.       efree(result);
  102.    } else {
  103.       RETURN_FALSE;
  104.    }
  105. }


So far so good, I see a mention of stream functions in this declaration, so it appears to be opening the file and looking at the contents. That doesn't necessarily mean the mime type is being determined from the contents though, better investigate further.

This part looks like a good place to start since later in the declaration the itype variable is used for generating the return values mime elements.

C Code: [ Select ]
itype = php_getimagetype(stream, NULL TSRMLS_CC);


Since this seems like a function that's relative to the "image.c" file I'm already in, I'll see if I can find the declaration there via CTRL+F before going to findstr.

Yep, same file, a few lines up on line 1219.

C Code: [ Select ]
PHPAPI int php_getimagetype(php_stream * stream, char *filetype TSRMLS_DC)
{
   char tmp[12];
 
   if ( !filetype) filetype = tmp;
   if((php_stream_read(stream, filetype, 3)) != 3) {
      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
      return IMAGE_FILETYPE_UNKNOWN;
   }
 
/* BYTES READ: 3 */
   if (!memcmp(filetype, php_sig_gif, 3)) {
      return IMAGE_FILETYPE_GIF;
   } else if (!memcmp(filetype, php_sig_jpg, 3)) {
      return IMAGE_FILETYPE_JPEG;
   } else if (!memcmp(filetype, php_sig_png, 3)) {
      if (php_stream_read(stream, filetype+3, 5) != 5) {
         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
         return IMAGE_FILETYPE_UNKNOWN;
      }
      if (!memcmp(filetype, php_sig_png, 8)) {
         return IMAGE_FILETYPE_PNG;
      } else {
         php_error_docref(NULL TSRMLS_CC, E_WARNING, "PNG file corrupted by ASCII conversion");
         return IMAGE_FILETYPE_UNKNOWN;
      }
   } else if (!memcmp(filetype, php_sig_swf, 3)) {
      return IMAGE_FILETYPE_SWF;
   } else if (!memcmp(filetype, php_sig_swc, 3)) {
      return IMAGE_FILETYPE_SWC;
   } else if (!memcmp(filetype, php_sig_psd, 3)) {
      return IMAGE_FILETYPE_PSD;
   } else if (!memcmp(filetype, php_sig_bmp, 2)) {
      return IMAGE_FILETYPE_BMP;
   } else if (!memcmp(filetype, php_sig_jpc, 3)) {
      return IMAGE_FILETYPE_JPC;
   }
 
   if (php_stream_read(stream, filetype+3, 1) != 1) {
      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
      return IMAGE_FILETYPE_UNKNOWN;
   }
/* BYTES READ: 4 */
   if (!memcmp(filetype, php_sig_tif_ii, 4)) {
      return IMAGE_FILETYPE_TIFF_II;
   } else if (!memcmp(filetype, php_sig_tif_mm, 4)) {
      return IMAGE_FILETYPE_TIFF_MM;
   } else if (!memcmp(filetype, php_sig_iff, 4)) {
      return IMAGE_FILETYPE_IFF;
   } else if (!memcmp(filetype, php_sig_ico, 3)) {
      return IMAGE_FILETYPE_ICO;
   }
 
   if (php_stream_read(stream, filetype+4, 8) != 8) {
      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
      return IMAGE_FILETYPE_UNKNOWN;
   }
/* BYTES READ: 12 */
      if (!memcmp(filetype, php_sig_jp2, 12)) {
      return IMAGE_FILETYPE_JP2;
   }
 
/* AFTER ALL ABOVE FAILED */
   if (php_get_wbmp(stream, NULL, 1 TSRMLS_CC)) {
      return IMAGE_FILETYPE_WBMP;
   }
   if (php_get_xbm(stream, NULL TSRMLS_CC)) {
      return IMAGE_FILETYPE_XBM;
   }
   return IMAGE_FILETYPE_UNKNOWN;
}
  1. PHPAPI int php_getimagetype(php_stream * stream, char *filetype TSRMLS_DC)
  2. {
  3.    char tmp[12];
  4.  
  5.    if ( !filetype) filetype = tmp;
  6.    if((php_stream_read(stream, filetype, 3)) != 3) {
  7.       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
  8.       return IMAGE_FILETYPE_UNKNOWN;
  9.    }
  10.  
  11. /* BYTES READ: 3 */
  12.    if (!memcmp(filetype, php_sig_gif, 3)) {
  13.       return IMAGE_FILETYPE_GIF;
  14.    } else if (!memcmp(filetype, php_sig_jpg, 3)) {
  15.       return IMAGE_FILETYPE_JPEG;
  16.    } else if (!memcmp(filetype, php_sig_png, 3)) {
  17.       if (php_stream_read(stream, filetype+3, 5) != 5) {
  18.          php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
  19.          return IMAGE_FILETYPE_UNKNOWN;
  20.       }
  21.       if (!memcmp(filetype, php_sig_png, 8)) {
  22.          return IMAGE_FILETYPE_PNG;
  23.       } else {
  24.          php_error_docref(NULL TSRMLS_CC, E_WARNING, "PNG file corrupted by ASCII conversion");
  25.          return IMAGE_FILETYPE_UNKNOWN;
  26.       }
  27.    } else if (!memcmp(filetype, php_sig_swf, 3)) {
  28.       return IMAGE_FILETYPE_SWF;
  29.    } else if (!memcmp(filetype, php_sig_swc, 3)) {
  30.       return IMAGE_FILETYPE_SWC;
  31.    } else if (!memcmp(filetype, php_sig_psd, 3)) {
  32.       return IMAGE_FILETYPE_PSD;
  33.    } else if (!memcmp(filetype, php_sig_bmp, 2)) {
  34.       return IMAGE_FILETYPE_BMP;
  35.    } else if (!memcmp(filetype, php_sig_jpc, 3)) {
  36.       return IMAGE_FILETYPE_JPC;
  37.    }
  38.  
  39.    if (php_stream_read(stream, filetype+3, 1) != 1) {
  40.       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
  41.       return IMAGE_FILETYPE_UNKNOWN;
  42.    }
  43. /* BYTES READ: 4 */
  44.    if (!memcmp(filetype, php_sig_tif_ii, 4)) {
  45.       return IMAGE_FILETYPE_TIFF_II;
  46.    } else if (!memcmp(filetype, php_sig_tif_mm, 4)) {
  47.       return IMAGE_FILETYPE_TIFF_MM;
  48.    } else if (!memcmp(filetype, php_sig_iff, 4)) {
  49.       return IMAGE_FILETYPE_IFF;
  50.    } else if (!memcmp(filetype, php_sig_ico, 3)) {
  51.       return IMAGE_FILETYPE_ICO;
  52.    }
  53.  
  54.    if (php_stream_read(stream, filetype+4, 8) != 8) {
  55.       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Read error!");
  56.       return IMAGE_FILETYPE_UNKNOWN;
  57.    }
  58. /* BYTES READ: 12 */
  59.       if (!memcmp(filetype, php_sig_jp2, 12)) {
  60.       return IMAGE_FILETYPE_JP2;
  61.    }
  62.  
  63. /* AFTER ALL ABOVE FAILED */
  64.    if (php_get_wbmp(stream, NULL, 1 TSRMLS_CC)) {
  65.       return IMAGE_FILETYPE_WBMP;
  66.    }
  67.    if (php_get_xbm(stream, NULL TSRMLS_CC)) {
  68.       return IMAGE_FILETYPE_XBM;
  69.    }
  70.    return IMAGE_FILETYPE_UNKNOWN;
  71. }


This looks promising. I see bytes from the files contents being read and compared to known image type signatures.

It still doesn't validate the entire file contents, meaning someone crafty enough may be able to slip something nasty past, but it is better than relying on an easily alterable file name though.

<Edit> While the individual image handler functions such as "php_handle_png" do read further into the files, they still do not validate further than the file header. This just means rather than prepending a few bits for an image signature, an entire file header has to be prepended instead</Edit>


I don't see any other methods designed specifically for determining a file extension that can be investigated. So I have to figure that $ext is either being determined by looking at the last few characters of a file name, or by looking at the first few bytes of the file.


Now I'm left wondering, how is $_FILES['id']['type'] determined ?
I'm not sure where to begin looking for that piece of information though, so I'll start with the PHP manual page for file uploads which gives me this little piece of information.

Quote:
$_FILES['userfile']['type']

The mime type of the file, if the browser provided this information. An example would be "image/gif". This mime type is however not checked on the PHP side and therefore don't take its value for granted.


That's a big red flag right there. "if the browser provided this information" means PHP assumes the entity uploading the file is telling the truth about the file. It can be spoofed.


So at this point, the ['size'] index is pretty much irrelevant. Both of the other elements can be spoofed.


Suppose you're allowing image uploads, and someone finds out where those uploads are stored and that they're directly accessible from a browser.

Judging by those function declarations, and assuming both pathinfo and getimagesize are being used to check the extension, someone could prepend the binary signature of a JPG/GIF/PNG to a PHP script, name it using a jpg/gif/png extension, and upload a PHP script of their own design to the image uploads folder.

This alone isn't too bad. A servers default settings usually aren't going to be configured to allow files with image extensions to be processed as PHP scripts, as far as I know.

However, if there's something, say a random image generator, in the directory and the server is configured to process image extensions as PHP files, an attacker could, knowing the directory and therefore the path to the image file, execute that file.


In any event, to be safe, it would be better to determine the file type using getimagesize, then using the return value from that to decide which image function to attempt to create an image resource from, for instance imagecreatefrompng and assuming a valid image resource is returned from that imagecreate* function, then trust it as the image function has to read and parse the entire file contents in order to return a valid image resource.

It will take a lot more memory per image upload, but it will be safer.

This, is of course assuming there are no flaws in any of the image file formats or the libraries the server is using to read them. But that's a whole different topic altogether.
  • seularts
  • Graduate
  • Graduate
  • User avatar
  • Posts: 153
  • Loc: Romania

Post 3+ Months Ago

Sorry I forgot to say that it just jumped the if statement. $exe just read backwards the file name extracting only the extension and than comparing it with what is in the if statement. I figured it out in the end, but..

Code: [ Select ]
if (($ext == "jpg" || "gif" || "png") && ($_FILES["uploaded_file"]["type"] == "image/jpeg" || "image/gif" || "image/png") && ($_FILES["uploaded_file"]["size"] < 1000000))

had to be changed into

if (($ext == "jpg" || $ext == "gif" || $ext == "png") && ($_FILES["uploaded_file"]["type"] == "image/jpeg" || $_FILES["uploaded_file"]["type"] == "image/gif" || $_FILES["uploaded_file"]["type"] == "image/png") && ($_FILES["uploaded_file"]["size"] < 1000000))
  1. if (($ext == "jpg" || "gif" || "png") && ($_FILES["uploaded_file"]["type"] == "image/jpeg" || "image/gif" || "image/png") && ($_FILES["uploaded_file"]["size"] < 1000000))
  2. had to be changed into
  3. if (($ext == "jpg" || $ext == "gif" || $ext == "png") && ($_FILES["uploaded_file"]["type"] == "image/jpeg" || $_FILES["uploaded_file"]["type"] == "image/gif" || $_FILES["uploaded_file"]["type"] == "image/png") && ($_FILES["uploaded_file"]["size"] < 1000000))


This was the main problem. I still have no idea why it worked before in the first form and now I had to appeal to the second one to make it usable!?
  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13503
  • Loc: Florida

Post 3+ Months Ago

Maybe the first version wasn't tested thoroughly enough and it just seemed like it worked ?

I suppose there could have been two PHP versions used between then and now, and that there was a change in operator precedence between those two versions which altered the behavior of those "A == B || C" bits you have there. I don't remember hearing of any such change, you'd have to look into that in the PHP changelogs on your own.

I have a hunch that it's the not being tested thoroughly enough thing though. :)

Post Information

  • Total Posts in this topic: 4 posts
  • Users browsing this forum: No registered users and 98 guests
  • You cannot post new topics in this forum
  • You cannot reply to topics in this forum
  • You cannot edit your posts in this forum
  • You cannot delete your posts in this forum
  • You cannot post attachments in this forum
 
 

© 1998-2014. Ozzu® is a registered trademark of Unmelted, LLC.