def testSystemAccountAnomaly(self): passwd = [ "root:x:0:0::/root:/bin/sash", "miss:x:1000:100:Missing:/home/miss:/bin/bash", "bad1:x:0:1001:Bad 1:/home/bad1:/bin/bash", "bad2:x:1002:0:Bad 2:/home/bad2:/bin/bash" ] shadow = [ "root:{UNSET}:16000:0:99999:7:::", "ok:{SHA512}:16000:0:99999:7:::", "bad1::16333:0:99999:7:::", "bad2:{DES}:16333:0:99999:7:::" ] group = [ "root:x:0:root", "miss:x:1000:miss", "bad1:x:1001:bad1", "bad2:x:1002:bad2" ] gshadow = ["root:::root", "miss:::miss", "bad1:::bad1", "bad2:::bad2"] stats, files = self._GenFiles(passwd, shadow, group, gshadow) no_grp = { "symptom": "Accounts with invalid gid.", "finding": ["gid 100 assigned without /etc/groups entry: miss"], "type": "PARSER_ANOMALY" } uid = { "symptom": "Accounts with shared uid.", "finding": ["uid 0 assigned to multiple accounts: bad1,root"], "type": "PARSER_ANOMALY" } gid = { "symptom": "Privileged group with unusual members.", "finding": ["Accounts in 'root' group: bad2"], "type": "PARSER_ANOMALY" } no_match = { "symptom": "Mismatched passwd and shadow files.", "finding": [ "Present in passwd, missing in shadow: miss", "Present in shadow, missing in passwd: ok" ], "type": "PARSER_ANOMALY" } expected = [ rdf_anomaly.Anomaly(**no_grp), rdf_anomaly.Anomaly(**uid), rdf_anomaly.Anomaly(**gid), rdf_anomaly.Anomaly(**no_match) ] parser = linux_file_parser.LinuxSystemPasswdParser() rdfs = parser.ParseMultiple(stats, files, None) results = [r for r in rdfs if isinstance(r, rdf_anomaly.Anomaly)] self.assertEqual(len(expected), len(results)) for expect, result in zip(expected, results): self.assertEqual(expect.symptom, result.symptom) # Expand out repeated field helper. self.assertItemsEqual(list(expect.finding), list(result.finding)) self.assertEqual(expect.type, result.type)
def CheckCryptResults(self, passwd, shadow, group, gshadow, algo, usr, grp): stats, files = self._GenFiles(passwd, shadow, group, gshadow) parser = linux_file_parser.LinuxSystemPasswdParser() results = list(parser.ParseMultiple(stats, files, None)) usrs = [r for r in results if isinstance(r, rdf_client.User)] grps = [r for r in results if isinstance(r, rdf_client.Group)] self.assertEqual(1, len(usrs), "Different number of usr %s results" % algo) self.assertEqual(1, len(grps), "Different number of grp %s results" % algo) self.CheckExpectedUser(algo, usr, usrs[0]) self.CheckExpectedGroup(algo, grp, grps[0])
def _GenResults(self): parser = linux_file_parser.LinuxSystemPasswdParser() if self.results is None: host_data = self.SetKnowledgeBase() login = { "/etc/passwd": """ nopasswd:x:1000:1000::/home/nopasswd:/bin/bash md5:x:1001:1001::/home/md5:/bin/bash undying:x:1002:1002::/home/undying:/bin/bash disabled:x:1003:1003::/home/disabled:/bin/bash +nisuser:acr.7pt3dpA5s::::::/bin/zsh""", "/etc/shadow": """ nopasswd::16000:0:365:7::: md5:$1$rootrootrootrootrootro:16000:0:365:7::: undying:$6$saltsalt${0}:16000:0:99999:7::: disabled:!:16000:0:99999:7:::""".format("r" * 86), "/etc/group": """ nopasswd:x:1000:nopasswd +::: md5:x:1001:md5 undying:x:1002:undying disabled:x:1003:disabled""", "/etc/gshadow": """ nopasswd:::nopasswd md5:::md5 undying:::undying disabled:::disabled""" } modes = { "/etc/passwd": { "st_mode": 0o100666 }, # Bad write perm. "/etc/group": { "st_uid": 1 }, # Bad owner. "/etc/shadow": { "st_mode": 0o100444 }, # Bad read perm. "/etc/gshadow": { "st_gid": 1, "st_mode": 0o100400 } } # Bad group. host_data = self.GenFileData("LoginPolicyConfiguration", login, parser, modes) return self.RunChecks(host_data)
def testNoAnomaliesWhenEverythingIsFine(self): passwd = [ "ok_1:x:1000:1000::/home/ok_1:/bin/bash", "ok_2:x:1001:1001::/home/ok_2:/bin/bash" ] shadow = [ "ok_1:{SHA256}:16000:0:99999:7:::", "ok_2:{SHA512}:16000:0:99999:7:::" ] group = ["ok_1:x:1000:ok_1", "ok_2:x:1001:ok_2"] gshadow = ["ok_1:::ok_1", "ok_2:::ok_2"] stats, files = self._GenFiles(passwd, shadow, group, gshadow) parser = linux_file_parser.LinuxSystemPasswdParser() rdfs = parser.ParseMultiple(stats, files, None) results = [r for r in rdfs if isinstance(r, rdf_anomaly.Anomaly)] self.assertFalse(results)