public static void ScanUploads(Config config, TeknikEntities db) { Output(string.Format("[{0}] Started Virus Scan.", DateTime.Now)); List<Upload> uploads = db.Uploads.ToList(); // Initialize ClamAV ClamClient clam = new ClamClient(config.UploadConfig.ClamServer, config.UploadConfig.ClamPort); clam.MaxStreamSize = config.UploadConfig.MaxUploadSize; int totalCount = uploads.Count(); int totalScans = 0; int totalClean = 0; int totalViruses = 0; foreach (Upload upload in uploads) { totalScans++; string subDir = upload.FileName[0].ToString(); string filePath = Path.Combine(config.UploadConfig.UploadDirectory, subDir, upload.FileName); if (File.Exists(filePath)) { // Read in the file byte[] data = File.ReadAllBytes(filePath); // If the IV is set, and Key is set, then decrypt it if (!string.IsNullOrEmpty(upload.Key) && !string.IsNullOrEmpty(upload.IV)) { // Decrypt the data data = AES.Decrypt(data, upload.Key, upload.IV); } // We have the data, let's scan it ClamScanResult scanResult = clam.SendAndScanFile(data); switch (scanResult.Result) { case ClamScanResults.Clean: totalClean++; string cleanMsg = string.Format("[{0}] Clean Scan: {1}/{2} Scanned | {3} - {4}", DateTime.Now, totalScans, totalCount, upload.Url, upload.FileName); Output(cleanMsg); break; case ClamScanResults.VirusDetected: totalViruses++; string msg = string.Format("[{0}] Virus Detected: {1} - {2} - {3}", DateTime.Now, upload.Url, upload.FileName, scanResult.InfectedFiles.First().VirusName); File.AppendAllLines(virusFile, new List<string> { msg }); Output(msg); // Delete from the DB db.Uploads.Remove(upload); db.SaveChanges(); // Delete the File if (File.Exists(filePath)) { File.Delete(filePath); } break; case ClamScanResults.Error: string errorMsg = string.Format("[{0}] Scan Error: {1}", DateTime.Now, scanResult.RawResult); File.AppendAllLines(errorFile, new List<string> { errorMsg }); Output(errorMsg); break; case ClamScanResults.Unknown: string unkMsg = string.Format("[{0}] Unknown Scan Result: {1}", DateTime.Now, scanResult.RawResult); File.AppendAllLines(errorFile, new List<string> { unkMsg }); Output(unkMsg); break; } } } if (totalViruses > 0) { // Add to transparency report if any were found Takedown report = db.Takedowns.Create(); report.Requester = TAKEDOWN_REPORTER; report.RequesterContact = config.SupportEmail; report.DateRequested = DateTime.Now; report.Reason = "Malware Found"; report.ActionTaken = string.Format("{0} Uploads removed", totalViruses); report.DateActionTaken = DateTime.Now; db.Takedowns.Add(report); db.SaveChanges(); } Output(string.Format("Scanning Complete. {0} Scanned | {1} Viruses Found | {2} Total Files", totalScans, totalViruses, totalCount)); }
/// <summary> /// Scans your data stream for virus /// </summary> /// <param name="stream">The stream you want to check</param> public ScanResult ScanStream(Stream stream) { var clam = new ClamClient("localhost", 3310); return MapScanResult(clam.SendAndScanFile(stream)); }
public ActionResult Upload(string fileType, string fileExt, string iv, int keySize, int blockSize, bool encrypt, bool saveKey, HttpPostedFileWrapper data, string key = null) { try { if (Config.UploadConfig.UploadEnabled) { if (data.ContentLength <= Config.UploadConfig.MaxUploadSize) { // convert file to bytes byte[] fileData = null; int contentLength = data.ContentLength; using (var binaryReader = new BinaryReader(data.InputStream)) { fileData = binaryReader.ReadBytes(data.ContentLength); } // Scan the file to detect a virus if (Config.UploadConfig.VirusScanEnable) { byte[] scanData = fileData; // If it was encrypted client side, decrypt it if (!encrypt && key != null) { // If the IV is set, and Key is set, then decrypt it if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(iv)) { // Decrypt the data scanData = AES.Decrypt(scanData, key, iv); } } ClamClient clam = new ClamClient(Config.UploadConfig.ClamServer, Config.UploadConfig.ClamPort); clam.MaxStreamSize = Config.UploadConfig.MaxUploadSize; ClamScanResult scanResult = clam.SendAndScanFile(scanData); switch (scanResult.Result) { case ClamScanResults.Clean: break; case ClamScanResults.VirusDetected: return Json(new { error = new { message = string.Format("Virus Detected: {0}. As per our <a href=\"{1}\">Terms of Service</a>, Viruses are not permited.", scanResult.InfectedFiles.First().VirusName, Url.SubRouteUrl("tos", "TOS.Index")) } }); case ClamScanResults.Error: return Json(new { error = new { message = string.Format("Error scanning the file upload for viruses. {0}", scanResult.RawResult) } }); case ClamScanResults.Unknown: return Json(new { error = new { message = string.Format("Unknown result while scanning the file upload for viruses. {0}", scanResult.RawResult) } }); } } // if they want us to encrypt it, we do so here if (encrypt) { // Generate key and iv if empty if (string.IsNullOrEmpty(key)) { key = Utility.RandomString(keySize / 8); } fileData = AES.Encrypt(fileData, key, iv); if (fileData == null || fileData.Length <= 0) { return Json(new { error = new { message = "Unable to encrypt file" } }); } } Models.Upload upload = Uploader.SaveFile(db, Config, fileData, fileType, contentLength, fileExt, iv, (saveKey) ? key : null, keySize, blockSize); if (upload != null) { if (User.Identity.IsAuthenticated) { Users.Models.User user = UserHelper.GetUser(db, User.Identity.Name); if (user != null) { upload.UserId = user.UserId; db.Entry(upload).State = EntityState.Modified; db.SaveChanges(); } } return Json(new { result = new { name = upload.Url, url = Url.SubRouteUrl("u", "Upload.Download", new { file = upload.Url }), key = key } }, "text/plain"); } return Json(new { error = new { message = "Unable to upload file" } }); } else { return Json(new { error = new { message = "File Too Large" } }); } } return Json(new { error = new { message = "Uploads are disabled" } }); } catch (Exception ex) { return Json(new { error = new { message = "Exception while uploading file: " + ex.GetFullMessage(true) } }); } }
/// <summary> /// Scans some bytes for virus /// </summary> /// <param name="data">byte data to scan</param> public ScanResult ScanBytes(byte[] data) { var clam = new ClamClient("localhost", 3310); return MapScanResult(clam.SendAndScanFile(data)); }
public ActionResult Upload(HttpPostedFileWrapper file, string contentType = null, bool encrypt = true, bool saveKey = true, string key = null, int keySize = 0, string iv = null, int blockSize = 0, bool genDeletionKey = false, bool doNotTrack = false) { try { ViewBag.Title = "Upload"; if (file != null) { if (file.ContentLength <= Config.UploadConfig.MaxUploadSize) { // convert file to bytes byte[] fileData = null; string fileExt = Path.GetExtension(file.FileName); int contentLength = file.ContentLength; using (var binaryReader = new BinaryReader(file.InputStream)) { fileData = binaryReader.ReadBytes(file.ContentLength); } // Scan the file to detect a virus if (Config.UploadConfig.VirusScanEnable) { byte[] scanData = fileData; // If it was encrypted client side, decrypt it if (!encrypt && key != null) { // If the IV is set, and Key is set, then decrypt it if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(iv)) { // Decrypt the data scanData = AES.Decrypt(scanData, key, iv); } } ClamClient clam = new ClamClient(Config.UploadConfig.ClamServer, Config.UploadConfig.ClamPort); clam.MaxStreamSize = Config.UploadConfig.MaxUploadSize; ClamScanResult scanResult = clam.SendAndScanFile(scanData); switch (scanResult.Result) { case ClamScanResults.Clean: break; case ClamScanResults.VirusDetected: return Json(new { error = new { message = string.Format("Virus Detected: {0}. As per our <a href=\"{1}\">Terms of Service</a>, Viruses are not permited.", scanResult.InfectedFiles.First().VirusName, Url.SubRouteUrl("tos", "TOS.Index")) } }); case ClamScanResults.Error: break; case ClamScanResults.Unknown: break; } } // Need to grab the contentType if it's empty if (string.IsNullOrEmpty(contentType)) { contentType = (string.IsNullOrEmpty(file.ContentType)) ? "application/octet-stream" : file.ContentType; } // Initialize the key size and block size if empty if (keySize <= 0) keySize = Config.UploadConfig.KeySize; if (blockSize <= 0) blockSize = Config.UploadConfig.BlockSize; byte[] data = null; // If they want us to encrypt the file first, do that here if (encrypt) { // Generate key and iv if empty if (string.IsNullOrEmpty(key)) { key = Utility.RandomString(keySize / 8); } if (string.IsNullOrEmpty(iv)) { iv = Utility.RandomString(blockSize / 8); } data = AES.Encrypt(fileData, key, iv); if (data == null || data.Length <= 0) { return Json(new { error = new { message = "Unable to encrypt file" } }); } } // Save the file data Upload.Models.Upload upload = Uploader.SaveFile(db, Config, (encrypt) ? data : fileData, contentType, contentLength, fileExt, iv, (saveKey) ? key : null, keySize, blockSize); if (upload != null) { // Generate delete key if asked to if (genDeletionKey) { string delKey = Utility.RandomString(Config.UploadConfig.DeleteKeyLength); upload.DeleteKey = delKey; db.Entry(upload).State = EntityState.Modified; db.SaveChanges(); } // Pull all the information together string fullUrl = Url.SubRouteUrl("upload", "Upload.Download", new { file = upload.Url }); var returnData = new { url = (saveKey || string.IsNullOrEmpty(key)) ? fullUrl : fullUrl + "#" + key, fileName = upload.Url, contentType = contentType, contentLength = contentLength, key = key, keySize = keySize, iv = iv, blockSize = blockSize, deletionKey = upload.DeleteKey }; return Json(new { result = returnData }); } return Json(new { error = new { message = "Unable to save file" } }); } else { return Json(new { error = new { message = "File Too Large" } }); } } return Json(new { error = new { message = "Invalid Upload Request" } }); } catch(Exception ex) { return Json(new { error = new { message = "Exception: " + ex.Message } }); } }