From 7568cebe8fa96f73e472685d6025c347124de85b Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Thu, 18 Jun 2026 23:24:58 +0200 Subject: [PATCH 1/3] reset command_timeout on interactive command when output is received also when prompt is set --- src/attackmate/executors/ssh/interactfeature.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/attackmate/executors/ssh/interactfeature.py b/src/attackmate/executors/ssh/interactfeature.py index b9dbf16d5..8449cedd3 100644 --- a/src/attackmate/executors/ssh/interactfeature.py +++ b/src/attackmate/executors/ssh/interactfeature.py @@ -19,8 +19,7 @@ def check_prompt(self, output: str, prompts: list[str]) -> bool: self.logger.debug('found prompt!') self.timer = None return True - else: - self.set_timer() + self.set_timer() return False def check_timer(self, seconds: int) -> bool: From dd099aec5dd5879d3961941fef16a9fbc4cf0739 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Thu, 18 Jun 2026 23:46:32 +0200 Subject: [PATCH 2/3] dont set timer on empty outout --- .../executors/ssh/interactfeature.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/attackmate/executors/ssh/interactfeature.py b/src/attackmate/executors/ssh/interactfeature.py index 8449cedd3..e4aec6820 100644 --- a/src/attackmate/executors/ssh/interactfeature.py +++ b/src/attackmate/executors/ssh/interactfeature.py @@ -13,12 +13,19 @@ def __init__(self): self.logger = logging.getLogger('playbook') def check_prompt(self, output: str, prompts: list[str]) -> bool: - if output and prompts: - for p in prompts: - if output.endswith(p): - self.logger.debug('found prompt!') - self.timer = None - return True + if not output: + return False + + if not prompts: + self.set_timer() + return False + + for p in prompts: + if output.endswith(p): + self.logger.debug('found prompt!') + self.timer = None + return True + self.set_timer() return False From 60a90918ef348a66545b7797982a19e8cfb71db0 Mon Sep 17 00:00:00 2001 From: thorinaboenke Date: Thu, 18 Jun 2026 23:48:01 +0200 Subject: [PATCH 3/3] add tests for interactive feature --- test/units/test_interactfeature.py | 33 ++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 test/units/test_interactfeature.py diff --git a/test/units/test_interactfeature.py b/test/units/test_interactfeature.py new file mode 100644 index 000000000..40b28dd65 --- /dev/null +++ b/test/units/test_interactfeature.py @@ -0,0 +1,33 @@ +import time +from attackmate.executors.ssh.interactfeature import Interactive + + +class TestCheckPrompt: + def setup_method(self): + self.interactive = Interactive() + self.interactive.set_timer() + + def test_no_prompts_configured_resets_timer(self): + before = self.interactive.timer + time.sleep(0.05) + self.interactive.check_prompt('some output', []) + assert self.interactive.timer > before + + def test_prompt_not_matched_resets_timer(self): + before = self.interactive.timer + time.sleep(0.05) + result = self.interactive.check_prompt('still running...', ['$ ']) + assert result is False + assert self.interactive.timer > before + + def test_prompt_matched_clears_timer_and_returns_true(self): + result = self.interactive.check_prompt('root@host:~$ ', ['$ ']) + assert result is True + assert self.interactive.timer is None + + def test_empty_output_on_channel_eof_does_not_reset_timer(self): + before = self.interactive.timer + time.sleep(0.05) + result = self.interactive.check_prompt('', ['$ ']) + assert result is False + assert self.interactive.timer == before