Vulnerability in the Automatic Image Upload with Thumbnails v. 1.3.4

Description:
Peter Österberg has discovered a vulnerability in the Automatic Image Upload with Thumbnails module for PunBB, which can be exploited by malicious users to conduct cross-site scripting attacks and to compromise a vulnerable system.

The uploadimg.php script fails to validate the extension of an uploaded file. This can be exploited to upload files with ".html" or ".php" extensions by passing an allowed MIME media type in the HTTP headers.

Successful exploitation allows to conduct cross-site scripting attacks or to execute arbitrary PHP code on the server, but requires valid user credentials in a group that is allowed to upload files.

http://secunia.com/advisories/28138

solution:
open uploadimg.php and find line (~193):

// Determine whether file is correct filetype-
if (!((($_FILES['imagefile']['type'] == "image/jpg" || $_FILES['imagefile']['type'] == "image/jpeg" || $_FILES['imagefile']['type'] == "image/pjpeg") && ($allow_jpg_uploads == "1")) || (($_FILES['imagefile']['type'] == "image/png" || $_FILES['imagefile']['type'] == "image/x-png") && ($allow_png_uploads == "1")) || (($_FILES['imagefile']['type'] == "image/gif") && ($allow_gif_uploads == "1"))))

replace with (added extension checking):

if (!((($_FILES['imagefile']['type'] == "image/jpg" || $_FILES['imagefile']['type'] == "image/jpeg" || $_FILES['imagefile']['type'] == "image/pjpeg") && ($imagefilename_ext == 'jpg' || $imagefilename_ext == 'jpeg') && ($allow_jpg_uploads == "1")) || (($_FILES['imagefile']['type'] == "image/png" || $_FILES['imagefile']['type'] == "image/x-png") && ($imagefilename_ext == 'png') && ($allow_png_uploads == "1")) || (($_FILES['imagefile']['type'] == "image/gif") && ($imagefilename_ext == 'gif') && ($allow_gif_uploads == "1"))))

be careful! wink

subj.
it may be useful for people with slow inet connection.

file: /attachment.php

... skipped ...

else {
    // put the file out for download

    // open a pointer to the file
    $attach_full_path = $pun_config['attach_basefolder'].$attach_location;
    $fp = @fopen( $attach_full_path, "rb" );
    if ( !$fp )
        message($lang_common['Bad request']);
    else {

        // get some file info
        $attach_stat = fstat($fp);

        if ( isset($_SERVER['HTTP_RANGE']) ) {
            /* somebody resuming download */
            
            // used information from:
            // [*] sources of PHCDownload (The best File Management CMS) - http://www.phpcredo.com
            // [*] RFC 2616 "Hypertext Transfer Protocol -- HTTP/1.1" - http://www.faqs.org/rfcs/rfc2616
            // [*] Google - http://google.com.ua
            // [*] "??????? PHP-?????? - ???????? ????? ?? HTTP" - http://scorpion.amateria.ru/2007/10/02/zagruzka-fajla-po-http.html

            // check ranges
            list( , $server_range ) = explode( "=", $_SERVER['HTTP_RANGE'] );
            list( $server_range ) = explode( "-", $server_range );

            @fseek( $fp, $server_range );
            
            // send headers
            header( $_SERVER['SERVER_PROTOCOL'] . " 206 Partial Content" );
            header( "Accept-Ranges: bytes" );
            header( "Content-Range: bytes " . $server_range . "-" . ( $attach_size - 1 ) . "/" . $attach_size . "" );
            header( "Content-Length: " . ($attach_size - $server_range) . "" );
        }

        else {
            /* new download */
            
            // update number of downloads
            $result = $db->query('UPDATE '.$db->prefix.'attach_2_files SET downloads=downloads+1 WHERE id=\''.$attach_item.'\'') or error();

            // send headers
            header( $_SERVER['SERVER_PROTOCOL'] . " 200 OK" );
            header( "Content-Length: " . $attach_size . "" );
        }

        header( "Last-Modified: " . date( "D, d M Y H:i:s \G\M\T" , $attach_stat['mtime'] ) );
        header( "Cache-control: public" );
        header( "Pragma: public" );
        header( "Expires: 0" );
        if ( strlen( $attach_mime ) != 0 )
            header( "Content-Type: " . $attach_mime . "" );
        else
            header( "Content-Type: application/octet-stream" );
        header( "Content-Disposition: attachment; filename=\"" . $attach_filename . "\"" );

        // chunk size
        $chunk_size = 1024*10;
        
        // and finally send the file
        while ( !feof( $fp ) ) {
            echo fread( $fp, $chunk_size );
            @flush();
            @ob_flush();
        }

        fclose($fp);
    
    }
}

p.s. please, if you found some errors/bugs -- let me know wink
p.p.s. sorry for my english neutral