/// <summary> /// Contacts the server from our beacon loop /// </summary> /// <param name="session"></param> /// <returns></returns> public bool ContactServer(NHibernate.ISession session) { bool ContactedServer = false; // Get info about all the new process events var processEvents = session.QueryOver <ProcessEvent>() .Where(e => e.HasInformedServer == false) .List <ProcessEvent>(); if (processEvents.Count() != 0) { foreach (var processEvent in processEvents) { // Get info about the exe associated ith this process Executable executable = null; try { executable = session.QueryOver <Executable>() .Where(e => e.Id == processEvent.ExecutableId) .List <Executable>().First(); } catch (Exception e) { // TODO Need to log this error Log.Exception(e, "Unable to find an executable for process event {0}", processEvent.Id); // I'll record in the DB that we already informed the server about this broken event } using (var transaction = session.BeginTransaction()) { if (executable == null) { // The executable for this process event was not found, so something broke, so just ignore it processEvent.HasInformedServer = true; session.Save(processEvent); transaction.Commit(); } else { if (Event.PostProcessEvent(processEvent, executable)) { // Record that we sent this data to the server so we don't try sending it again processEvent.HasInformedServer = true; session.Save(processEvent); transaction.Commit(); } ContactedServer = true; } } } } // Get info about all the new catalog files var catalogFiles = session.QueryOver <CatalogFile>() .Where(e => e.HasInformedServer == false) .List <CatalogFile>(); if (catalogFiles.Count() != 0) { foreach (var catalogFile in catalogFiles) { using (var transaction = session.BeginTransaction()) { if (Event.PostCatalogFile(catalogFile)) { // Record that we sent this data to the server so we don't try sending it again catalogFile.HasInformedServer = true; session.Save(catalogFile); transaction.Commit(); } } ContactedServer = true; } } if (!ContactedServer) { Log.Info("Posting heartbeat"); dynamic eventResponse = Event.PostHeartbeatEvent(); int avoidInfiniteLoop = 100; while (eventResponse != null) { // Sanity check, want to avoid infinite loop avoidInfiniteLoop--; if (avoidInfiniteLoop < 0) { break; } eventResponse = HandleServerResponse(eventResponse); } } return(ContactedServer); }
/// <summary> /// This function is called when a new process is being started. It return the decision if the process should be allowed to run. /// It stores some data in the DB about this executable (such as the computed hashes). /// </summary> /// <param name="filePath"></param> /// <param name="ExecutableId">Database ID for the executable</param> /// <returns>Decision on if the process should be allowed to run</returns> public static Decision DecideOnProcess(string filePath, out long ExecutableId) { Log.Info("Arbiter deciding on process"); Decision decision = Decision.ALLOW; List <Signer> signers = null; ExecutableId = 0; // TODO Must do something where there is an error in this function so we don't record that something with ExecutableID 0 happened try { filePath = CleanPath(filePath); Log.Info("Deciding on process: {0}", filePath); // // Check if we've seen this before // DateTime lastWriteTime = File.GetLastWriteTime(filePath); lastWriteTime = lastWriteTime.ToUniversalTime(); var sessionFactory = Database.getSessionFactory(); using (var session = sessionFactory.OpenSession()) { var exes = session.QueryOver <Executable>() .Where(e => e.Path == filePath) .And(e => e.LastWriteTime == lastWriteTime) .List <Executable>(); if (exes.Count() != 0) { Executable foundExe = exes[0]; Log.Debug("Exe has been seen before"); ExecutableId = foundExe.Id; // TODO need to use a rule engine if (!foundExe.Trusted) { Log.Info("Deny it"); decision = Decision.DENY; } else { Log.Info("Allow it"); } return(decision); } } // // If we're here then this is new, so verify it // bool isVerified = WinTrustVerify.WinTrust.Verify(filePath, out signers); string SignerName = ""; if (isVerified) { if (signers != null && signers.Count >= 1 && signers[0] != null) { SignerName = signers[0].Name; } Log.Info("File is signed by {0}", SignerName); } else { Log.Info("File is not signed (or not trusted)"); } // Compute hashes byte[] md5Hash, sha1Hash, sha256Hash; Helpers.ComputeHashes(filePath, out md5Hash, out sha1Hash, out sha256Hash); // Gather all this data var exe = new Executable { Path = filePath, LastWriteTime = lastWriteTime, LastSeen = DateTime.UtcNow, FirstSeen = DateTime.UtcNow, LastChecked = DateTime.UtcNow, Signed = (signers != null), Blocked = false, // TODO Change this based on if we are in audit mode Md5 = md5Hash, Sha1 = sha1Hash, Sha256 = sha256Hash, }; // // Record this info to the DB // using (var session = sessionFactory.OpenSession()) { using (var transaction = session.BeginTransaction()) { // I don't really need to check again, but I'm worried about a race var exes = session.QueryOver <Executable>() .Where(e => e.Path == filePath) .And(e => e.LastWriteTime == lastWriteTime) .List <Executable>(); if (exes.Count() == 0) { // Ensure we don't add certs to the DB if they already exist there if (signers != null) { foreach (var signer in signers) { var certs = session.QueryOver <Certificate>() .Where(e => e.SerialNumber == signer.SigningCert.SerialNumber) .And(e => e.Issuer == signer.SigningCert.Issuer) .List <Certificate>(); if (certs.Count() != 0) { signer.SigningCert = certs[0]; break; } } Database.AddSignersToExe(exe, signers); } // // Make a decision on it // decision = MakeDecisionFromRules(exe); exe.Trusted = (decision == Decision.ALLOW); session.Save(exe); transaction.Commit(); ExecutableId = exe.Id; } } } } catch (Exception e) { Log.Exception(e, "Exception in DecideOnProcess"); } return(FinalDecisionBasedOnMode(decision)); }