MSDN Blogs

Monday, January 28, 2019

Validate Malicious file upload through files MAGIC CHECK

      File upload in web application always open gates for malicious activity to perform on server if not validate properly. We are already allowed only to upload files with some predefined extensions like  PDF, DOC,.. etc. But this can not prevent some evil user to upload an executable file after renaming it to PDF or JPEG.
So first of all I will explain what are "magic numbers", and then I will show how we handle them in C#.


   You can think about magic number as a file id, they are strongly typed data used by application to identify data stored in the file. That is sequence of bytes on some special place in the file. Usually they are starting bytes of file but that is not case for every file type. Also it is possible that some application use more then one sequences of bytes to determinate file type.

Below is a sample code for validating file upload using magic check and simple file extension.

private Boolean   validateFileUpload()
    {
        /*
         pdf  25-50-44-46
         png  89-50-4E-47
         gif  47 49 46 38 
         jpg  FF-D8-FF-E1
         jpeg FF-D8-FF-E0*/
         
        string fileName = Path.GetFileName(FileUpload1.PostedFile.FileName);
        string[] path = { ".jpg", ".jpeg", ".gif", ".png", ".pdf" };
        string[] magicNumbers = {"25-50-44-46","89-50-4E-47","47 49 46 38","FF-D8-FF-E1","FF-D8-FF-E0"};
        string ext = Path.GetExtension(fileName).ToString().ToLower();
        string contenttype = FileUpload1.PostedFile.ContentType;
        string content = FileUpload1.PostedFile.ContentType.ToString().ToLower();
        string data_as_hex;
        string magicCheck=string.Empty;
        BinaryReader chkBinary;
        Byte[] chkbytes;
        bool extValidation = false;

        if (!string.IsNullOrWhiteSpace(fileName))
        {
            //check magic numbers
            Stream checkStream = FileUpload1.PostedFile.InputStream;
            if (checkStream.Length > 0)
            {
                chkBinary = new BinaryReader(checkStream);
                chkbytes = chkBinary.ReadBytes(0x10);
                data_as_hex = BitConverter.ToString(chkbytes);
                magicCheck = data_as_hex.Substring(0, 11);
            }
            for (int i = 0; i < magicNumbers.Length; i++)
            {
                if (magicCheck.Equals(magicNumbers[i]) )
                {
                    extValidation = true;
                    break;
                }
            }

            if (!extValidation)
            {
                //ltrDocError.Text = Convert.ToString(GetLocalResourceObject("Inavlidfileupload"));
                return false;
            }

            //check path
            for (int i = 0; i < path.Length; i++)
            {
                if (ext.Equals(path[i]))
                {
                    extValidation = true;
                    break;
                }
            }
            if (!extValidation)
            {
                //ltrDocError.Text = Convert.ToString(GetLocalResourceObject("Inavlidfileupload"));
                return false;
            }
            
            //else if (dtgDocUpload.Rows.Count >= 1)
            //{
            //    ltrDocError.Text = Convert.ToString(GetLocalResourceObject("errDocCount"));
            //    return false;
            //}
          
            else
            {
                return true;
            }
        }
        else {
            return false;
        }

    }



No comments:

Post a Comment