diff --git a/docker/worker/Dockerfile b/docker/worker/Dockerfile index b21440e87..d4ae66af4 100644 --- a/docker/worker/Dockerfile +++ b/docker/worker/Dockerfile @@ -158,6 +158,7 @@ RUN cd /home/turbinia && echo "" > password.lst RUN cd /home/turbinia && curl -s https://raw.githubusercontent.com/danielmiessler/SecLists/285474cf9bff85f3323c5a1ae436f78acd1cb62c/Passwords/UserPassCombo-Jay.txt >> password.lst RUN cd /home/turbinia && curl -s https://raw.githubusercontent.com/danielmiessler/SecLists/master/Passwords/Common-Credentials/10-million-password-list-top-1000000.txt >> password.lst RUN cp /home/turbinia/password.lst /root/ +RUN echo ':\nd' > /home/turbinia/turbinia-password-cracking.rules # Copy Kubernetes support tool to home folder COPY --chown=turbinia:turbinia k8s/tools/check-lockfile.py /home/turbinia/check-lockfile.py diff --git a/turbinia/lib/utils.py b/turbinia/lib/utils.py index b00993c73..d48357014 100644 --- a/turbinia/lib/utils.py +++ b/turbinia/lib/utils.py @@ -171,6 +171,8 @@ def bruteforce_password_hashes( pot_file = os.path.join((tmp_dir or tempfile.gettempdir()), 'hashcat.pot') password_list_file_path = os.path.expanduser('~/password.lst') + password_rules_file_path = os.path.expanduser( + '~/turbinia-password-cracking.rules') # Fallback if not os.path.isfile(password_list_file_path): @@ -180,6 +182,12 @@ def bruteforce_password_hashes( if not os.path.isfile(password_list_file_path): raise TurbiniaException('No password list available') + # Does rules file exist? If not make a temp one + if not os.path.isfile(password_rules_file_path): + with tempfile.NamedTemporaryFile(delete=False, mode='w+') as rf: + password_rules_file_path = rf.name + rf.write('\n'.join([':', 'd'])) + if '$y$' in ''.join(password_hashes): cmd = [ 'john', '--format=crypt', f'--wordlist={password_list_file_path}', @@ -187,14 +195,13 @@ def bruteforce_password_hashes( ] pot_file = os.path.expanduser('~/.john/john.pot') else: - cmd = ['hashcat', '--force', '-a', '1'] + # Ignore warnings & plain word list attack (with rules) + cmd = ['hashcat', '--force', '-a', '0'] if extra_args: cmd = cmd + extra_args.split(' ') cmd = cmd + [f'--potfile-path={pot_file}'] - cmd = cmd + [ - password_hashes_file_path, password_list_file_path, - password_list_file_path - ] + cmd = cmd + [password_hashes_file_path, password_list_file_path] + cmd = cmd + ['-r', password_rules_file_path] with open(os.devnull, 'w') as devnull: try: diff --git a/turbinia/workers/analysis/jenkins.py b/turbinia/workers/analysis/jenkins.py index b236ea00a..d6d14594b 100644 --- a/turbinia/workers/analysis/jenkins.py +++ b/turbinia/workers/analysis/jenkins.py @@ -37,7 +37,7 @@ class JenkinsAnalysisTask(TurbiniaTask): TASK_CONFIG = { # This is the length of time in seconds that the collected passwords will # be bruteforced. - 'bruteforce_timeout': 300 + 'bruteforce_timeout': 600 } def run(self, evidence, result): @@ -72,7 +72,7 @@ def run(self, evidence, result): jenkins_artifacts = [] jenkins_re = re.compile( - r'^.*jenkins[^\/]*(\/home)?(\/users\/[^\/]+)*\/config\.xml$') + r'^.*?jenkins[^\/]*(\/home)?(\/users)?(\/.*?)\/config\.xml$') for collected_artifact in collected_artifacts: if re.match(jenkins_re, collected_artifact): jenkins_artifacts.append(collected_artifact) diff --git a/turbinia/workers/analysis/postgresql_acct_test.py b/turbinia/workers/analysis/postgresql_acct_test.py index 6372eb58b..7dbbc1a22 100644 --- a/turbinia/workers/analysis/postgresql_acct_test.py +++ b/turbinia/workers/analysis/postgresql_acct_test.py @@ -15,6 +15,7 @@ """Tests for the PostgreSQL account analysis task.""" import os +import mock import unittest from turbinia import config @@ -35,7 +36,7 @@ class PostgresAcctAnalysisTaskTest(TestTurbiniaTaskBase): POSTGRES_REPORT = """#### **PostgreSQL analysis found 1 weak password(s)** * **1 weak password(s) found:** - * User 'postgres' with password 'password'""" + * User 'postgres' with password 'postgres'""" def setUp(self): super(PostgresAcctAnalysisTaskTest, self).setUp() @@ -72,22 +73,34 @@ def test_extract_scram_creds(self): _, hashes = task._extract_creds(['/scram_database'], self.evidence) self.assertDictEqual(hashes, self.EXPECTED_SCRAM_CREDENTIALS) - def test_analyse_md5_postgres_creds(self): + @mock.patch( + 'turbinia.workers.analysis.postgresql_acct.bruteforce_password_hashes') + def test_analyse_md5_postgres_creds(self, bruteforce_mock): """Tests the _analyse_postgres_creds method.""" config.LoadConfig() task = postgresql_acct.PostgresAccountAnalysisTask() + bruteforce_mock.side_effect = [ + [(list(self.EXPECTED_MD5_CREDENTIALS.keys())[0], 'postgres')], [] + ] + (report, priority, summary) = task._analyse_postgres_creds( self.EXPECTED_MD5_CREDENTIALS, {}) self.assertEqual(report, self.POSTGRES_REPORT) self.assertEqual(priority, 10) self.assertEqual(summary, 'PostgreSQL analysis found 1 weak password(s)') - def test_analyse_scram_postgres_creds(self): + @mock.patch( + 'turbinia.workers.analysis.postgresql_acct.bruteforce_password_hashes') + def test_analyse_scram_postgres_creds(self, bruteforce_mock): """Tests the _analyse_postgres_creds method.""" config.LoadConfig() task = postgresql_acct.PostgresAccountAnalysisTask() + bruteforce_mock.side_effect = [ + [], [(list(self.EXPECTED_SCRAM_CREDENTIALS.keys())[0], 'postgres')] + ] + (report, priority, summary) = task._analyse_postgres_creds( {}, self.EXPECTED_SCRAM_CREDENTIALS) self.assertEqual(report, self.POSTGRES_REPORT)