def testNtpDoesntAllowOpenQueries(self): """Test for checking we don't allow queries by default.""" parser = config_file.NtpdParser() check_id = "TIME-NTP-NO-OPEN-QUERIES" artifact_id = "NtpConfFile" good_config = {"/etc/ntp.conf": """ restrict default nomodify noquery nopeer """} bad_config = {"/etc/ntp.conf": """ restrict default nomodify nopeer """} bad_default_config = {"/etc/ntp.conf": """ """} # A good config should pass. results = self.RunChecks( self.GenFileData("NtpConfFile", good_config, parser)) self.assertCheckUndetected(check_id, results) found = ["Expected state was not found"] sym = ("Missing attribute: ntpd.conf is configured or defaults to open " "queries. Can allow DDoS. This configuration is an on-going " "recommendation following the Ntp December 2014 Vulnerability " "notice. (http://support.ntp.org/bin/view/Main/SecurityNotice)") # A bad one should detect a problem. results = self.RunChecks(self.GenFileData(artifact_id, bad_config, parser)) self.assertCheckDetectedAnom(check_id, results, sym, found) # And as the default is to be queryable, check we detect an empty config. results = self.RunChecks( self.GenFileData(artifact_id, bad_default_config, parser)) self.assertCheckDetectedAnom(check_id, results, sym, found)
def testNtpHasMonitorDisabled(self): """Test for checking that monitor is disabled.""" parser = config_file.NtpdParser() good_config = { "/etc/ntp.conf": """ disable monitor """ } good_tricky_config = { "/etc/ntp.conf": """ disable monitor auth enable kernel monitor auth disable kernel monitor """ } bad_config = {"/etc/ntp.conf": """ enable monitor """} bad_default_config = {"/etc/ntp.conf": """ """} bad_tricky_config = { "/etc/ntp.conf": """ enable kernel monitor auth disable monitor auth enable kernel monitor """ } found = ["ntpd.conf has monitor flag set to True."] sym = ( "Found: ntpd.conf is configured to allow monlist NTP reflection " "attacks.") results = self.RunChecks( self.GenFileData("NtpConfFile", good_config, parser)) self.assertCheckUndetected("TIME-NTP-REFLECTION", results) results = self.RunChecks( self.GenFileData("NtpConfFile", good_tricky_config, parser)) self.assertCheckUndetected("TIME-NTP-REFLECTION", results) results = self.RunChecks( self.GenFileData("NtpConfFile", bad_config, parser)) self.assertCheckDetectedAnom("TIME-NTP-REFLECTION", results, sym, found) results = self.RunChecks( self.GenFileData("NtpConfFile", bad_default_config, parser)) self.assertCheckDetectedAnom("TIME-NTP-REFLECTION", results, sym, found) results = self.RunChecks( self.GenFileData("NtpConfFile", bad_tricky_config, parser)) self.assertCheckDetectedAnom("TIME-NTP-REFLECTION", results, sym, found)
def testNtpDoesntAllowOpenQueries(self): """Test for checking we don't allow queries by default.""" parser = config_file.NtpdParser() good_config = { "/etc/ntp.conf": """ restrict default nomodify noquery nopeer """ } bad_config = { "/etc/ntp.conf": """ restrict default nomodify nopeer """ } bad_default_config = {"/etc/ntp.conf": """ """} # A good config should pass. results = self.RunChecks( self.GenFileData("NtpConfFile", good_config, parser)) self.assertCheckUndetected("TIME-NTP-VULN-2014-12", results) found = ["Expected state was not found"] sym = ( "Missing attribute: ntpd.conf is configured or defaults to open " "queries. Can allow DDoS.") # A bad one should detect a problem. results = self.RunChecks( self.GenFileData("NtpConfFile", bad_config, parser)) self.assertCheckDetectedAnom("TIME-NTP-VULN-2014-12", results, sym, found) # And as the default is to be queryable, check we detect an empty config. results = self.RunChecks( self.GenFileData("NtpConfFile", bad_default_config, parser)) self.assertCheckDetectedAnom("TIME-NTP-VULN-2014-12", results, sym, found)
def testParseNtpConfig(self): test_data = r""" # Time servers server 1.2.3.4 iburst server 4.5.6.7 iburst server 8.9.10.11 iburst server pool.ntp.org iburst server 2001:1234:1234:2::f iburst # Drift file driftfile /var/lib/ntp/ntp.drift restrict default nomodify noquery nopeer # Guard against monlist NTP reflection attacks. disable monitor # Enable the creation of a peerstats file enable stats statsdir /var/log/ntpstats filegen peerstats file peerstats type day link enable # Test only. ttl 127 88 broadcastdelay 0.01 """ conffile = StringIO.StringIO(test_data) parser = config_file.NtpdParser() results = list(parser.Parse(None, conffile, None)) # We expect some results. self.assertTrue(results) # There should be only one result. self.assertEqual(1, len(results)) # Now that we are sure, just use that single result for easy of reading. results = results[0] # Check all the expected "simple" config keywords are present. expected_config_keywords = set( ["driftfile", "statsdir", "filegen", "ttl", "broadcastdelay"]) | set(parser._defaults.keys()) self.assertEqual(expected_config_keywords, set(results.config.keys())) # Check all the expected "keyed" config keywords are present. self.assertTrue(results.server) self.assertTrue(results.restrict) # And check one that isn't in the config, isn't in out result. self.assertFalse(results.trap) # Check we got all the "servers". servers = ["1.2.3.4", "4.5.6.7", "8.9.10.11", "pool.ntp.org", "2001:1234:1234:2::f"] self.assertItemsEqual(servers, [r.address for r in results.server]) # In our test data, they all have "iburst" as an arg. Check that is found. for r in results.server: self.assertEqual("iburst", r.options) # Check a few values were parsed correctly. self.assertEqual("/var/lib/ntp/ntp.drift", results.config["driftfile"]) self.assertEqual("/var/log/ntpstats", results.config["statsdir"]) self.assertEqual("peerstats file peerstats type day link enable", results.config["filegen"]) self.assertEqual(1, len(results.restrict)) self.assertEqual("default", results.restrict[0].address) self.assertEqual("nomodify noquery nopeer", results.restrict[0].options) # A option that can have a list of integers. self.assertEqual([127, 88], results.config["ttl"]) # An option that should only have a single float. self.assertEqual([0.01], results.config["broadcastdelay"]) # Check the modified defaults. self.assertFalse(results.config["monitor"]) self.assertTrue(results.config["stats"]) # Check an unlisted defaults are unmodified. self.assertFalse(results.config["kernel"]) self.assertTrue(results.config["auth"])