MD5sum differs between what I upload to my website and download

I check the MD5sum of an .iso file before uploading to my website using Filezilla in active mode. The MD5sum is calculated on the website and matches what was calculated before upload. If I download the same file from the website using the following code, the MD5sum is different.

<?php
$php_scripts = '../../php/';
require $php_scripts . 'PDO_Connection_Select.php';
require $php_scripts . 'GetUserIpAddr.php';
function mydloader($l_filename=NULL)
{
$ip = GetUserIpAddr();
if (!$pdo = PDOConnect("foxclone"))
{
	echo "Failed to connect to database" ;
    exit;
}
    if( isset( $l_filename ) ) {
 //       var_dump($ip,$l_filename);
        $stmt = $pdo->prepare("INSERT INTO download (IP_ADDRESS, FILENAME) VALUES (?, ?)");
        $stmt->execute([$ip, $l_filename]) ;

        header('Content-Type: octet-stream');
        header("Content-Disposition: attachment; filename={$l_filename}");
        header('Pragma: no-cache');
        header('Expires: 0');
        
        readfile($l_filename); 
        }
    else {
        echo "isset failed";
        }
}

mydloader($_GET["f"]);

Why is this happening?

Thanks in advance.

Where are the checksums coming from?

I calculated the MD5sum using MD5sum(filename) prior to upload. On the website, the MD5sum is calculated using md5_file(filename) and matches the MD5sum calculated prior to upload. . After downloading the same file, the MD5sum is different.

I found the difference by opening both the original iso and the downloaded iso in atom editor. The downloaded version has the following added to the start of the file:
herestring(14) “xx.xxx.xxx.xxx” <— my ip
string(17) “foxclone35-02.iso”
herestring(14) “xx.xxx.xxx.xxx”
string(17) “foxclone35-02.iso”

What could be causing this?

That’s the var_dump() output, which is apparently is not commented out in the actual code that’s running on the server, and php’s output buffering setting is turned on in the php.ini, which allows the header() statements to ‘work’ even though something has been output the browser prior to the header() statements.

You also wouldn’t tell an actual visitor to your site if a database error occurred. Also, since you are using the PDO extension, it an error occurred in the connection code, the connection error handling logic you have will never be executed and might as well not be present. Database errors are useless information for a visitor to your site and only helps a hacker who was intentionally trying to trigger errors. You should log all errors when on a live site. The simple way of displaying database errors when learning, developing, and debugging code/queries, and to log them when on a live server, is to use exceptions for database statement errors and just let php catch and handle the exception, where it will use its error related settings to control what happens with the actual error information (database statement errors will ‘automatically’ get displayed/logged the same as php errors, just by changing php’s error settings.)

This code has a serious security issue. By accepting the actual filename as an input, by specifying a path as part of that input (directory transversal), ANY file on your server can be downloaded, such as your database connection credentials. What you should do instead is have the file information stored in a database table. This will assign an id (auto-increment integer primary index) to each file. Any reference to the file would use the id. The download link would contain the id, not the filename. You would then query inside the posted code to get the actual filename. This will limit the downloaded file to those that have records in the database table, not to all the files that your web server’s user account has access to.

Thanks for your reply, that fixed the immediate problem. I’m working on making the changes you outlined to make the site more secure.

Sponsor our Newsletter | Privacy Policy | Terms of Service