1

Seems the file keeps adding 0x0D to my saved binary files no matter what setting I put in the fopen mode flag.

It's not only affecting fopen/fwrite.. but also file_put_contents.

file_get_contents I thought was the problem to begin with.. but it turns out this one is actually working okay.. because when I dumped the file using bin2hex() it came out good.

I was blaming at first the std::string in C++ for this bug.. but it turns out it doesn't even have anything to do with C++ but it's in fact a bug with PHP or maybe with only CentOS linux and I have yet to find a solution to store my file in binary.. best I could do is hexstring dump file which works..

Look at my code and screenshots.

$target_file = "/privatefiles/" . basename($_FILES["a"]["name"]);
$fileTypeExtension = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));

//Check file extension.
if($fileTypeExtension != "dll" && $fileTypeExtension != "exe" ) die("ER");

// Check file size
if ($_FILES["a"]["size"] > 10*(1024*1024)) //10 MB cap
  die("ER");

//To decode a base64 encoded file (this was a quickfix to fix binary file encoding in C++ part).
$fileContent = file_get_contents($_FILES['a']['tmp_name']);
$fileContent = base64_decode($fileContent);

//fail
$fh = fopen("wtf1.bin", "wb");
fwrite($fh, $fileContent, strlen($fileContent));
fclose($fh);

//fail (exact result as top)
$fh = fopen("wtf2.bin", "wb");
$fileContent = bin2hex($fileContent);
for($i=0;$i<strlen($fileContent);$i+=2)
    fwrite($fh, chr(hexdec(substr($fileContent,$i,2))));
fclose($fh);

//good result.. but not binary
$fh = fopen("wtf3.bin", "w");
$fileContent = bin2hex(base64_decode(file_get_contents($_FILES['a']['tmp_name'])));
fwrite($fh, $fileContent);
fclose($fh);

//good result but not binary
file_put_contents($target_file, $fileContent); //good bin2hex.

//fail same as the top 2 fail's.
file_put_contents($target_file."_", file_get_contents($_FILES['a']['tmp_name'])); //bad same as wtf1.bin or wtf2.bin


Here are my screenshots (proof of what is happening from running the code above), and initiating a file upload using C++ application (which cannot be bugged because at first I sent using raw binary mode.. then after this 0x0D 0x0A bug I changed it to base64 encoding to fix the transfer problem.. and it turns out that wasn't even the problem, but in fact a PHP problem I believe..

Here is the original binary file (not altered) this is what I upload (as you can see I stop at 0x0A 0x40 to show you the bug). original

Here is wtf1.bin (Just a simple 1 liner of base64_decode to file) at same offset. wtf1

Here is wtf2.bin (Some hackery I tried to do to fix this problem using bin2hex which dumps it good) at same offset. wtf2

Here is wtf3.bin (bin2hex) which works good at same offset. (0x846 / 2 = 0x423) (same offset confirmed!) wtf3

phpversion

Even this simple upload script, uploads corrupted files with 0xA,0xD

<!DOCTYPE html>
<html>
<head>
  <title>Upload your files</title>
</head>
<body>
  <form enctype="multipart/form-data" action="test.php" method="POST">
    <p>Upload your file</p>
    <input type="file" name="uploaded_file"></input><br />
    <input type="submit" value="Upload"></input>
  </form>
</body>
</html>
<?php
  if(!empty($_FILES['uploaded_file']))
  {
    $path = basename( $_FILES['uploaded_file']['name']);
    print_r($_FILES);
    $size = filesize($_FILES['uploaded_file']['tmp_name']);
    echo "<br>size uploaded = " . $size . "<br>";
    if(move_uploaded_file($_FILES['uploaded_file']['tmp_name'], $path)) {
      echo "The file ".  basename( $_FILES['uploaded_file']['name']). 
      " has been uploaded<br>";
      echo "path = " . $path . "<br>";
      echo "size stored = " . filesize($path);
    } else{
        echo "There was an error uploading the file, please try again!";
    }
  }
?>

Bug happens when I just upload these bytes in binary format

BC 09 00 00 83 C4 04 BA E8 57 40 00 8D 64 24 00 8A 08 88 0A 40 42 84 C9

I get back on server

BC 09 00 00 83 C4 04 BA E8 57 40 00 8D 64 24 00 8A 08 88 0D 0A 40 42 84 C9

SSpoke
  • 5,656
  • 10
  • 72
  • 124
  • 1
    Before anything else in your PHP form - can you check the size of `$_FILES['uploaded_file']` ? Both from `filesize()` and the `size` property inside `$_FILES`. If the size is the same as your local file - then the problem is **not** the web server. – IVO GELOV Jun 02 '20 at 06:34
  • 1
    So where/how exactly are you looking at the file contents, and see those extra carriage returns? Are you checking them _on_ the server - or are you downloading them back to the client first? – CBroe Jun 02 '20 at 08:11
  • @CBroe I am downloading them using SSH FTP (SFTP) and viewing them in the same editor that shows me the original file in perfect hex pattern.., – SSpoke Jun 02 '20 at 10:12
  • @IVO GELOV https://i.imgur.com/ybqRtLb.png and https://i.imgur.com/5tXohiE.png you are right the filesize on drive seems good, but when I open in my editor it shows as 25 bytes instead of 24.. very strange... could it be my editor this whole time. original: https://i.imgur.com/n1vFmAm.png downloaded: https://i.imgur.com/5cmsz9R.png I think I figured my issue out it's not the editor but the SFTP Client (WinSCP) that has this problem. – SSpoke Jun 02 '20 at 10:13
  • 1
    Are you sure you did the re-download in FTP “binary” mode? (Many FTP clients have an “ASCII mode”, in which they will try to _translate_ line endings between different OS.) – CBroe Jun 02 '20 at 10:18
  • Thanks CBroe and IVO GELOV that was it, and to think I struggled so much with this thinking it was my uploader or my PHP server, I solved the problem, It was the force Text-Mode setting for all files it was turned on by default like you said. – SSpoke Jun 02 '20 at 10:21

1 Answers1

0

Thanks CBroe and IVO GELOV, The issue was in my FTP/SFTP Client WinSCP. I attached a screenshot which setting you need to turn off so this problem doesn't happen.

Solved

SSpoke
  • 5,656
  • 10
  • 72
  • 124