feat(smbtakeover): add smbtakeover.py module#1153
feat(smbtakeover): add smbtakeover.py module#1153sttlr wants to merge 6 commits intoPennyw0rth:mainfrom
Conversation
There was a problem hiding this comment.
Thanks for the PR.
This code looks much better than #1152, but there are still a few things to do.
| self.start_service(svc_obj, svc_name) if is_start else self.stop_service(svc_obj, svc_name) | ||
|
|
||
| failed = False | ||
| statuses = self.check() |
There was a problem hiding this comment.
process() already calls check_service() in the loop, then calls self.check() at the end which queries the same services again and prints highlights. It works, but it duplicates WMI calls and can be noisy. Consider reusing one pass of results for both the actions and the final check
There was a problem hiding this comment.
process() calls check_service() in the loop to only change services that don't have target state set.
if i remove check_service() check - it would try to change all the services.
self.check() is used to validate results after changing.
so a service needs to be checked at least 2 times: first to check if it needs changing, second time to check if it was changed successfully.
| self.logger.fail(f"SMB {msg} sequence failed.") | ||
| else: | ||
| status = "restored" if is_start else "free" | ||
| self.logger.success(f"SMB {msg} sequence completed. Port 445/tcp {status}.") |
There was a problem hiding this comment.
Are we only validating WMI service state here, and not that TCP 445 is actually closed or listening? If so, should the success line say that the services are in the expected state rather than that port 445/tcp is free/restored?
| return self._i_wbem_services | ||
|
|
||
| def get_service_or_driver(self, name): | ||
| svc_name_to_table = {"srv2": "Win32_SystemDriver", "srvnet": "Win32_SystemDriver", "LanmanServer": "Win32_Service"} |
There was a problem hiding this comment.
svc_name_to_table is built inside get_service_or_driver() on every call. Please move it to a class-level constant so the mapping isn’t recreated each time same behavior, slightly cleaner

Description
Added
smbtakeover.pymodule to unbind/rebind SMB port445/tcp. Useful when conducting NTLM relay attacks.Usually Windows hosts already use port
445/tcpfor SMB. And to conduct an NTLM relay attack you'd need port445to be available to bind to it. There are ways to do it via loading a driver, loading a module into LSASS, rebooting the target machine - which are all bad for OPSEC.This module solves this problem in an OPSEC safe way.
Original research - https://specterops.io/blog/2024/08/01/relay-your-heart-away-an-opsec-conscious-approach-to-445-takeover/
Original code - https://github.com/zyn3rgy/smbtakeover
Used Gemini Pro to generate the NXCModule class. Validated after it.
Type of change
Insert an "x" inside the brackets for relevant items (do not delete options)
Setup guide for the review
NOTE: User running the module has to have
Administratorlevel access on the machine (to start/stop the services).NOTE: WMI ports need to be accessible (check firewall).
I used
Kaijuchain from Vulnlab to validate the module.Screenshots (if appropriate):
Unbinding and then rebinding works ok.
Checklist:
Insert an "x" inside the brackets for completed and relevant items (do not delete options)
poetry run ruff check ., use--fixto automatically fix what it can)tests/e2e_commands.txtfile if necessary (new modules or features are required to be added to the e2e tests)