private static FirewallResponse OnFirewallCheck(FirewallRequest request) { // Only filter chrome. var filtering = request.BinaryAbsolutePath.IndexOf("chrome", StringComparison.OrdinalIgnoreCase) != -1; if (filtering) { switch (request.RemotePort) { case 80: case 443: { // Let's allow chrome to access TCP 80 and 443, but block all other ports. Console.WriteLine("Filtering application {0} destined for {1}", request.BinaryAbsolutePath, request.RemotePort); return(new FirewallResponse(FirewallAction.FilterApplication)); } default: { // Let's allow chrome to access TCP 80 and 443, but block all other ports. This is where we're // blocking any non-80/443 bound transmission. Console.WriteLine("Blocking internet for application {0} destined for {1}", request.BinaryAbsolutePath, request.RemotePort); return(new FirewallResponse(FirewallAction.BlockInternetForApplication)); } } } // For all other applications, just let them access the internet without filtering. Console.WriteLine("Not filtering application {0} destined for {1}", request.BinaryAbsolutePath, request.RemotePort); return(new FirewallResponse(FirewallAction.DontFilterApplication)); }
private static FirewallResponse OnFirewallCheck(FirewallRequest request) { // Only filter chrome. var filtering = request.BinaryAbsolutePath.IndexOf("chrome", StringComparison.OrdinalIgnoreCase) != -1; if (filtering) { if (request.RemotePort == s_standardHttpPortNetworkOrder || request.RemotePort == s_standardHttpsPortNetworkOrder) { // Let's allow chrome to access TCP 80 and 443, but block all other ports. Console.WriteLine("Filtering application {0} destined for {1}", request.BinaryAbsolutePath, (ushort)IPAddress.HostToNetworkOrder((short)request.RemotePort)); return(new FirewallResponse(CitadelCore.Net.Proxy.FirewallAction.FilterApplication)); } else { // Let's allow chrome to access TCP 80 and 443, but block all other // ports. This is where we're blocking any non-80/443 bound transmission. Console.WriteLine("Blocking internet for application {0} destined for {1}", request.BinaryAbsolutePath, (ushort)IPAddress.HostToNetworkOrder((short)request.RemotePort)); return(new FirewallResponse(CitadelCore.Net.Proxy.FirewallAction.BlockInternetForApplication)); } } // For all other applications, just let them access the internet without filtering. Console.WriteLine("Not filtering application {0} destined for {1}", request.BinaryAbsolutePath, (ushort)IPAddress.HostToNetworkOrder((short)request.RemotePort)); return(new FirewallResponse(CitadelCore.Net.Proxy.FirewallAction.DontFilterApplication)); }
private static FirewallResponse OnFirewallCheck(FirewallRequest request) { // Only filter chrome. //var filtering = request.BinaryAbsolutePath.IndexOf("chrome", StringComparison.OrdinalIgnoreCase) != -1; var filtering = true; if (filtering) { if ( request.RemotePort == s_standardHttpPortNetworkOrder || request.RemotePort == s_standardHttpsPortNetworkOrder || request.RemotePort == s_altHttpPortNetworkOrder || request.RemotePort == s_altHttpsPortNetworkOrder ) { // Let's allow chrome to access TCP 80 and 443, but block all other ports. //Console.WriteLine("Filtering application {0} destined for {1}", request.BinaryAbsolutePath, (ushort)IPAddress.HostToNetworkOrder((short)request.RemotePort)); return(new FirewallResponse(CitadelCore.Net.Proxy.FirewallAction.FilterApplication)); } else { // Let's allow chrome to access TCP 80 and 443, but ignore all other // ports. We want to allow non 80/443 requests to go through because // this example now demonstrates the replay API, which will cause // a bunch of browser tabs to open whenever you visit my website. // // If we filtered the replays back through the proxy, who knows // what would happen! Actually that's not true, you'd invoke an infinite // loopback, spawn a ton of browser tabs and then call me a bad programmer. //Console.WriteLine("Ignoring internet for application {0} destined for {1}", request.BinaryAbsolutePath, (ushort)IPAddress.HostToNetworkOrder((short)request.RemotePort)); return(new FirewallResponse(CitadelCore.Net.Proxy.FirewallAction.DontFilterApplication)); } } // For all other applications, just let them access the internet without filtering. //Console.WriteLine("Not filtering application {0} destined for {1}", request.BinaryAbsolutePath, (ushort)IPAddress.HostToNetworkOrder((short)request.RemotePort)); return(new FirewallResponse(CitadelCore.Net.Proxy.FirewallAction.DontFilterApplication)); }
/// <summary> /// Handles the process of inspecting a new TCP connection, seeking the user's decision on /// what to do with the connection, and then applying that decision in code in such a way as /// to cause the packet filtering loop to apply the user's decision. /// </summary> /// <param name="connInfo"> /// The state of the appropriate TCP table at the time of the new connectio. /// </param> /// <param name="tcpHeader"> /// The TCP header from the first packet in the new connection/flow. /// </param> /// <param name="isIpv6"> /// Whether or not this is from an IPV6 connection. /// </param> private unsafe void HandleNewTcpConnection(ITcpConnectionInfo connInfo, TcpHeader *tcpHeader, bool isIpv6) { if (tcpHeader == null) { } if (connInfo != null && connInfo.OwnerPid == m_thisPid) { // This is our process. switch (isIpv6) { case true: { Volatile.Write(ref m_v6ShouldFilter[tcpHeader->SrcPort], (int)FirewallAction.DontFilterApplication); } break; case false: { Volatile.Write(ref m_v4ShouldFilter[tcpHeader->SrcPort], (int)FirewallAction.DontFilterApplication); } break; } } else { FirewallResponse response = null; if (connInfo == null || connInfo.OwnerPid == 4 || connInfo.OwnerPid == 0) { var firewallRequest = new FirewallRequest("SYSTEM", tcpHeader->SrcPort, tcpHeader->DstPort, connInfo == null ? 0L : connInfo.OwnerPid); response = ConfirmDenyFirewallAccess?.Invoke(firewallRequest); } else { if (IsInternalIp(connInfo.RemoteAddress)) { response = new FirewallResponse(FirewallAction.DontFilterApplication); m_logger.Info("Don't filter internal IPs."); } else { // No need to null check here, because the above IF catches whenever connInfo // is null. var procPath = connInfo.OwnerProcessPath.Length > 0 ? connInfo.OwnerProcessPath : "SYSTEM"; var firewallRequest = new FirewallRequest(procPath, tcpHeader->SrcPort, tcpHeader->DstPort, connInfo.OwnerPid); response = ConfirmDenyFirewallAccess?.Invoke(firewallRequest); } } if (response == null) { // The user couldn't be bothered to give us an answer, so just go ahead and // let the packet through. switch (isIpv6) { case true: { Volatile.Write(ref m_v6ShouldFilter[tcpHeader->SrcPort], (byte)FirewallAction.DontFilterApplication); Volatile.Write(ref m_v6EncryptionHints[tcpHeader->SrcPort], (tcpHeader->DstPort == m_httpsStandardPort || tcpHeader->DstPort == m_httpsAltPort)); } break; case false: { Volatile.Write(ref m_v4ShouldFilter[tcpHeader->SrcPort], (byte)FirewallAction.DontFilterApplication); Volatile.Write(ref m_v4EncryptionHints[tcpHeader->SrcPort], (tcpHeader->DstPort == m_httpsStandardPort || tcpHeader->DstPort == m_httpsAltPort)); } break; } } else { switch (isIpv6) { case true: { Volatile.Write(ref m_v6ShouldFilter[tcpHeader->SrcPort], (byte)response.Action); Volatile.Write(ref m_v6EncryptionHints[tcpHeader->SrcPort], response.EncryptedHint ?? (tcpHeader->DstPort == m_httpsStandardPort || tcpHeader->DstPort == m_httpsAltPort)); } break; case false: { Volatile.Write(ref m_v4ShouldFilter[tcpHeader->SrcPort], (byte)response.Action); Volatile.Write(ref m_v4EncryptionHints[tcpHeader->SrcPort], response.EncryptedHint ?? (tcpHeader->DstPort == m_httpsStandardPort || tcpHeader->DstPort == m_httpsAltPort)); } break; } } } }
/// <summary> /// Called whenever the Engine want's to check if the application at the supplied absolute /// path should have its traffic forced through itself or not. /// </summary> /// <param name="appAbsolutePath"> /// The absolute path to an application that the filter is inquiring about. /// </param> /// <returns> /// True if the application at the specified absolute path should have its traffic forced /// through the filtering engine, false otherwise. /// </returns> public FirewallResponse OnAppFirewallCheck(FirewallRequest request) { if (!IsStandardHttpPort(request.RemotePort)) { return(new FirewallResponse(FirewallAction.DontFilterApplication, null)); } if (appListCheck == null && m_provider.PolicyConfiguration != null) { appListCheck = new AppListCheck(m_provider.PolicyConfiguration); } // XXX TODO - The engine shouldn't even tell us about SYSTEM processes and just silently // let them through. if (request.BinaryAbsolutePath.OIEquals("SYSTEM")) { return(new FirewallResponse(FirewallAction.DontFilterApplication)); } // Lets completely avoid piping anything from the operating system in the filter, with // the sole exception of Microsoft edge. if ((request.BinaryAbsolutePath.IndexOf("MicrosoftEdge", StringComparison.OrdinalIgnoreCase) == -1) && request.BinaryAbsolutePath.IndexOf(@"\Windows\", StringComparison.OrdinalIgnoreCase) != -1) { lock (s_foreverWhitelistedApplications) { if (s_foreverWhitelistedApplications.Contains(request.BinaryAbsolutePath)) { return(new FirewallResponse(FirewallAction.DontFilterApplication)); } } // Here we'll simply check if the binary is signed. If so, we'll validate the // certificate. If the cert is good, let's just go and bypass this binary altogether. // However, note that this does not verify that the signed binary is actually valid // for the certificate. That is, it doesn't ensure file integrity. Also, note that // even if we went all the way as to use WinVerifyTrust() from wintrust.dll to // completely verify integrity etc, this can still be bypassed by adding a self // signed signing authority to the windows trusted certs. // // So, all we can do is kick the can further down the road. This should be sufficient // to prevent the lay person from dropping a browser into the Windows folder. // // Leaving above notes just for the sake of knowledge. We can kick the can pretty // darn far down the road by asking Windows Resource Protection if the file really // belongs to the OS. Viruses are known to call SfcIsFileProtected in order to avoid // getting caught messing with these files so if viruses avoid them, I think we've // booted the can so far down the road that we need not worry about being exploited // here. The OS would need to be funamentally compromised and that wouldn't be our fault. // // The only other way we could get exploited here by getting our hook to sfc.dll // hijacked. There are countermeasures of course but not right now. // If the result is greater than zero, then this is a protected operating system file // according to the operating system. if (SFC.SfcIsFileProtected(IntPtr.Zero, request.BinaryAbsolutePath) > 0) { lock (s_foreverWhitelistedApplications) { s_foreverWhitelistedApplications.Add(request.BinaryAbsolutePath); } return(new FirewallResponse(FirewallAction.DontFilterApplication)); } } try { m_provider.PolicyConfiguration.PolicyLock.EnterReadLock(); if (m_provider.PolicyConfiguration.BlacklistedApplications.Count == 0 && m_provider.PolicyConfiguration.WhitelistedApplications.Count == 0) { // Just filter anything accessing port 80 and 443. m_logger.Debug("1Filtering application: {0}", request.BinaryAbsolutePath); return(new FirewallResponse(FirewallAction.FilterApplication)); } var appName = Path.GetFileName(request.BinaryAbsolutePath); if (m_provider.PolicyConfiguration.WhitelistedApplications.Count > 0) { bool inList = appListCheck.IsAppInWhitelist(request.BinaryAbsolutePath, appName); if (inList) { return(new FirewallResponse(FirewallAction.DontFilterApplication)); } else { // Whitelist is in effect, and this app is not whitelisted, so force it through. m_logger.Debug("2Filtering application: {0}", request.BinaryAbsolutePath); return(new FirewallResponse(FirewallAction.FilterApplication)); } } if (m_provider.PolicyConfiguration.BlacklistedApplications.Count > 0) { bool inList = appListCheck.IsAppInBlacklist(request.BinaryAbsolutePath, appName); if (inList) { m_logger.Debug("3Filtering application: {0}", request.BinaryAbsolutePath); return(new FirewallResponse(FirewallAction.FilterApplication)); } return(new FirewallResponse(FirewallAction.DontFilterApplication)); } // This app was not hit by either an enforced whitelist or blacklist. So, by default // we will filter everything. We should never get here, but just in case. m_logger.Debug("4Filtering application: {0}", request.BinaryAbsolutePath); return(new FirewallResponse(FirewallAction.FilterApplication)); } catch (Exception e) { m_logger.Error("Error in {0}", nameof(OnAppFirewallCheck)); LoggerUtil.RecursivelyLogException(m_logger, e); return(new FirewallResponse(FirewallAction.DontFilterApplication)); } finally { m_provider?.PolicyConfiguration?.PolicyLock?.ExitReadLock(); } }
/// <summary> /// Handles the process of inspecting a new TCP connection, seeking the user's decision on /// what to do with the connection, and then applying that decision in code in such a way as /// to cause the packet filtering loop to apply the user's decision. /// </summary> /// <param name="connInfo"> /// The state of the appropriate TCP table at the time of the new connectio. /// </param> /// <param name="tcpHeader"> /// The TCP header from the first packet in the new connection/flow. /// </param> /// <param name="isIpv6"> /// Whether or not this is from an IPV6 connection. /// </param> private void HandleNewTcpConnection(ITcpConnectionInfo connInfo, WINDIVERT_TCPHDR *tcpHeader, bool isIpv6) { if (tcpHeader != null) { Console.WriteLine(nameof(HandleNewTcpConnection)); if (connInfo != null && connInfo.OwnerPid == m_thisPid) { LoggerProxy.Default.Info(string.Format("Connection from local:{0} -> remote:{1} outbound is our process.", tcpHeader->SrcPort, tcpHeader->DstPort)); // This is our process. switch (isIpv6) { case true: { Volatile.Write(ref m_v6ShouldFilter[tcpHeader->SrcPort], (int)FirewallAction.DontFilterApplication); } break; case false: { Volatile.Write(ref m_v4ShouldFilter[tcpHeader->SrcPort], (int)FirewallAction.DontFilterApplication); } break; } } else { FirewallResponse response = null; if (connInfo == null || connInfo.OwnerPid == 4 || connInfo.OwnerPid == 0) { var firewallRequest = new FirewallRequest("SYSTEM", tcpHeader->SrcPort, tcpHeader->DstPort); response = ConfirmDenyFirewallAccess?.Invoke(firewallRequest); } else { // No need to null check here, because the above IF catches whenever connInfo // is null. var procPath = connInfo.OwnerProcessPath.Length > 0 ? connInfo.OwnerProcessPath : "SYSTEM"; var firewallRequest = new FirewallRequest(procPath, tcpHeader->SrcPort, tcpHeader->DstPort); response = ConfirmDenyFirewallAccess?.Invoke(firewallRequest); } if (response == null) { LoggerProxy.Default.Info("NO RESPONSE"); // The user couldn't be bothered to give us an answer, so just go ahead and // let the packet through. switch (isIpv6) { case true: { Volatile.Write(ref m_v6ShouldFilter[tcpHeader->SrcPort], (int)FirewallAction.DontFilterApplication); Volatile.Write(ref m_v6EncryptionHints[tcpHeader->SrcPort], (tcpHeader->DstPort == s_httpsStandardPort || tcpHeader->DstPort == s_httpsAltPort)); } break; case false: { Volatile.Write(ref m_v4ShouldFilter[tcpHeader->SrcPort], (int)FirewallAction.DontFilterApplication); Volatile.Write(ref m_v4EncryptionHints[tcpHeader->SrcPort], (tcpHeader->DstPort == s_httpsStandardPort || tcpHeader->DstPort == s_httpsAltPort)); } break; } } else { LoggerProxy.Default.Info("RESPONSE"); switch (isIpv6) { case true: { Volatile.Write(ref m_v6ShouldFilter[tcpHeader->SrcPort], (int)response.Action); Volatile.Write(ref m_v6EncryptionHints[tcpHeader->SrcPort], response.EncryptedHint ?? (tcpHeader->DstPort == s_httpsStandardPort || tcpHeader->DstPort == s_httpsAltPort)); } break; case false: { Volatile.Write(ref m_v4ShouldFilter[tcpHeader->SrcPort], (int)response.Action); Volatile.Write(ref m_v4EncryptionHints[tcpHeader->SrcPort], response.EncryptedHint ?? (tcpHeader->DstPort == s_httpsStandardPort || tcpHeader->DstPort == s_httpsAltPort)); } break; } } } } else { LoggerProxy.Default.Info("How on earth do we not have a valid TCP header."); // Somehow we fail to have even a valid TCP header here. Let the connection go // through, but warn. LoggerProxy.Default.Warn("TCP header was a null pointer. Allowing packet."); Volatile.Write(ref m_v4ShouldFilter[tcpHeader->SrcPort], (int)FirewallAction.DontFilterApplication); } }