mirror of
https://github.com/Pennyw0rth/NetExec
synced 2026-06-06 16:34:30 +00:00
fix: catch BrokenPipeErrors when connecting via SMB
This commit is contained in:
@@ -259,7 +259,9 @@ class ldap(connection):
|
||||
self.local_ip = self.conn.getSMBServer().get_socket().getsockname()[0]
|
||||
|
||||
try:
|
||||
self.conn.login('' , '')
|
||||
self.conn.login('', '')
|
||||
except BrokenPipeError as e:
|
||||
self.logger.error(f"Broken Pipe Error while attempting to login")
|
||||
except Exception as e:
|
||||
if "STATUS_NOT_SUPPORTED" in str(e):
|
||||
self.no_ntlm = True
|
||||
|
||||
@@ -251,6 +251,8 @@ class mssql(connection):
|
||||
add_user_bh(self.username, self.domain, self.logger, self.config)
|
||||
if not self.args.continue_on_success:
|
||||
return True
|
||||
except BrokenPipeError as e:
|
||||
self.logger.error(f"Broken Pipe Error while attempting to login")
|
||||
except Exception as e:
|
||||
self.logger.error(u'{}\\{}:{} {}'.format(domain,
|
||||
username,
|
||||
@@ -298,6 +300,8 @@ class mssql(connection):
|
||||
add_user_bh(self.username, self.domain, self.logger, self.config)
|
||||
if not self.args.continue_on_success:
|
||||
return True
|
||||
except BrokenPipeError as e:
|
||||
self.logger.error(f"Broken Pipe Error while attempting to login")
|
||||
except Exception as e:
|
||||
self.logger.error(u'{}\\{}:{} {}'.format(domain,
|
||||
username,
|
||||
|
||||
@@ -362,7 +362,7 @@ class database:
|
||||
# if we're filtering by domain controllers
|
||||
elif filter_term == 'dc':
|
||||
q = q.filter(
|
||||
self.ComputersTable.c.dc == 1
|
||||
self.ComputersTable.c.dc == True
|
||||
)
|
||||
if domain:
|
||||
q = q.filter(
|
||||
|
||||
+10
-2
@@ -264,6 +264,8 @@ class smb(connection):
|
||||
no_ntlm = False
|
||||
try:
|
||||
self.conn.login('', '')
|
||||
except BrokenPipeError as e:
|
||||
self.logger.error(f"Broken Pipe Error while attempting to login")
|
||||
except Exception as e:
|
||||
if "STATUS_NOT_SUPPORTED" in str(e):
|
||||
# no ntlm supported
|
||||
@@ -481,7 +483,10 @@ class smb(connection):
|
||||
self.password = password
|
||||
self.username = username
|
||||
self.domain = domain
|
||||
self.conn.login(self.username, self.password, domain)
|
||||
try:
|
||||
self.conn.login(self.username, self.password, domain)
|
||||
except BrokenPipeError as e:
|
||||
self.logger.error(f"Broken Pipe Error while attempting to login")
|
||||
|
||||
self.check_if_admin()
|
||||
self.db.add_credential('plaintext', domain, self.username, self.password)
|
||||
@@ -548,7 +553,10 @@ class smb(connection):
|
||||
nthash = self.hash
|
||||
|
||||
self.domain = domain
|
||||
self.conn.login(self.username, '', domain, lmhash, nthash)
|
||||
try:
|
||||
self.conn.login(self.username, '', domain, lmhash, nthash)
|
||||
except BrokenPipeError as e:
|
||||
self.logger.error(f"Broken Pipe Error while attempting to login")
|
||||
|
||||
self.check_if_admin()
|
||||
self.db.add_credential('hash', domain, self.username, nthash)
|
||||
|
||||
@@ -17,11 +17,6 @@ from sqlalchemy.ext.compiler import compiles
|
||||
warnings.filterwarnings("ignore", category=SAWarning)
|
||||
|
||||
|
||||
@compiles(insert)
|
||||
def _prefix_insert_with_ignore(ins, compiler, **kw):
|
||||
return compiler.visit_insert(ins.prefix_with('OR IGNORE'), **kw)
|
||||
|
||||
|
||||
class database:
|
||||
def __init__(self, db_engine):
|
||||
self.ComputersTable = None
|
||||
@@ -35,8 +30,14 @@ class database:
|
||||
self.db_engine = db_engine
|
||||
self.metadata = MetaData()
|
||||
asyncio.run(self.reflect_tables())
|
||||
session_factory = sessionmaker(bind=self.db_engine, expire_on_commit=True, class_=AsyncSession)
|
||||
|
||||
# we don't use async_sessionmaker or async_scoped_session because when `database` is initialized,
|
||||
# there is no running async loop
|
||||
session_factory = sessionmaker(
|
||||
bind=self.db_engine,
|
||||
expire_on_commit=True,
|
||||
class_=AsyncSession
|
||||
)
|
||||
|
||||
Session = scoped_session(session_factory)
|
||||
# this is still named "conn" when it is the session object; TODO: rename
|
||||
self.conn = Session()
|
||||
@@ -77,7 +78,6 @@ class database:
|
||||
"zerologon" boolean,
|
||||
"petitpotam" boolean
|
||||
)''')
|
||||
|
||||
# type = hash, plaintext
|
||||
db_conn.execute('''CREATE TABLE "users" (
|
||||
"id" integer PRIMARY KEY,
|
||||
@@ -88,7 +88,6 @@ class database:
|
||||
"pillaged_from_computerid" integer,
|
||||
FOREIGN KEY(pillaged_from_computerid) REFERENCES computers(id)
|
||||
)''')
|
||||
|
||||
db_conn.execute('''CREATE TABLE "groups" (
|
||||
"id" integer PRIMARY KEY,
|
||||
"domain" text,
|
||||
@@ -96,7 +95,6 @@ class database:
|
||||
"member_count_ad" integer,
|
||||
"last_query_time" text
|
||||
)''')
|
||||
|
||||
# This table keeps track of which credential has admin access over which machine and vice-versa
|
||||
db_conn.execute('''CREATE TABLE "admin_relations" (
|
||||
"id" integer PRIMARY KEY,
|
||||
@@ -105,7 +103,6 @@ class database:
|
||||
FOREIGN KEY(userid) REFERENCES users(id),
|
||||
FOREIGN KEY(computerid) REFERENCES computers(id)
|
||||
)''')
|
||||
|
||||
db_conn.execute('''CREATE TABLE "loggedin_relations" (
|
||||
"id" integer PRIMARY KEY,
|
||||
"userid" integer,
|
||||
@@ -113,7 +110,6 @@ class database:
|
||||
FOREIGN KEY(userid) REFERENCES users(id),
|
||||
FOREIGN KEY(computerid) REFERENCES computers(id)
|
||||
)''')
|
||||
|
||||
db_conn.execute('''CREATE TABLE "group_relations" (
|
||||
"id" integer PRIMARY KEY,
|
||||
"userid" integer,
|
||||
@@ -121,7 +117,6 @@ class database:
|
||||
FOREIGN KEY(userid) REFERENCES users(id),
|
||||
FOREIGN KEY(groupid) REFERENCES groups(id)
|
||||
)''')
|
||||
|
||||
db_conn.execute('''CREATE TABLE "shares" (
|
||||
"id" integer PRIMARY KEY,
|
||||
"computerid" text,
|
||||
@@ -133,7 +128,6 @@ class database:
|
||||
FOREIGN KEY(userid) REFERENCES users(id)
|
||||
UNIQUE(computerid, userid, name)
|
||||
)''')
|
||||
|
||||
db_conn.execute('''CREATE TABLE "dpapi_secrets" (
|
||||
"id" integer PRIMARY KEY,
|
||||
"computer" text,
|
||||
@@ -144,15 +138,13 @@ class database:
|
||||
"url" text,
|
||||
UNIQUE(computer, dpapi_type, windows_user, username, password, url)
|
||||
)''')
|
||||
|
||||
db_conn.execute('''CREATE TABLE "dpapi_backupkey" (
|
||||
"id" integer PRIMARY KEY,
|
||||
"domain" text,
|
||||
"pvk" text,
|
||||
UNIQUE(domain)
|
||||
)''')
|
||||
|
||||
#db_conn.execute('''CREATE TABLE "ntds_dumps" (
|
||||
# db_conn.execute('''CREATE TABLE "ntds_dumps" (
|
||||
# "id" integer PRIMARY KEY,
|
||||
# "computerid", integer,
|
||||
# "domain" text,
|
||||
@@ -162,7 +154,8 @@ class database:
|
||||
# )''')
|
||||
|
||||
# pull/545
|
||||
def add_computer(self, ip, hostname, domain, os, smbv1, signing, spooler=None, zerologon=None, petitpotam=None, dc=None):
|
||||
def add_computer(self, ip, hostname, domain, os, smbv1, signing, spooler=None, zerologon=None, petitpotam=None,
|
||||
dc=None):
|
||||
"""
|
||||
Check if this host has already been added to the database, if not, add it in.
|
||||
TODO: return inserted or updated row ids as a list
|
||||
@@ -308,15 +301,16 @@ class database:
|
||||
q = update(self.GroupRelationsTable).values(gr_data)
|
||||
asyncio.run(self.conn.execute(q))
|
||||
|
||||
logging.debug('add_credential(credtype={}, domain={}, username={}, password={}, groupid={}, pillaged_from={}) => {}'.format(
|
||||
credtype,
|
||||
domain,
|
||||
username,
|
||||
password,
|
||||
group_id,
|
||||
pillaged_from,
|
||||
user_rowid
|
||||
))
|
||||
logging.debug(
|
||||
'add_credential(credtype={}, domain={}, username={}, password={}, groupid={}, pillaged_from={}) => {}'.format(
|
||||
credtype,
|
||||
domain,
|
||||
username,
|
||||
password,
|
||||
group_id,
|
||||
pillaged_from,
|
||||
user_rowid
|
||||
))
|
||||
return user_rowid
|
||||
|
||||
def remove_credentials(self, creds_id):
|
||||
@@ -397,7 +391,7 @@ class database:
|
||||
elif host_ids:
|
||||
for host_id in host_ids:
|
||||
q = q.filter(
|
||||
self.AdminRelationsTable.c.hostid == host_id
|
||||
self.AdminRelationsTable.c.hostid == host_id
|
||||
)
|
||||
asyncio.run(self.conn.execute(q))
|
||||
|
||||
@@ -465,12 +459,24 @@ class database:
|
||||
# if we're filtering by domain controllers
|
||||
elif filter_term == 'dc':
|
||||
q = q.filter(
|
||||
self.ComputersTable.c.dc == 1
|
||||
self.ComputersTable.c.dc == True
|
||||
)
|
||||
if domain:
|
||||
q = q.filter(
|
||||
func.lower(self.ComputersTable.c.domain) == func.lower(domain)
|
||||
)
|
||||
elif filter_term == 'spooler':
|
||||
q = q.filter(
|
||||
self.ComputersTable.c.spooler == True
|
||||
)
|
||||
elif filter_term == 'zerologon':
|
||||
q = q.filter(
|
||||
self.ComputersTable.c.zerologon == True
|
||||
)
|
||||
elif filter_term == 'petitpotam':
|
||||
q = q.filter(
|
||||
self.ComputersTable.c.petitpotam == True
|
||||
)
|
||||
# if we're filtering by ip/hostname
|
||||
elif filter_term and filter_term != "":
|
||||
like_term = func.lower(f"%{filter_term}%")
|
||||
@@ -589,7 +595,8 @@ class database:
|
||||
|
||||
results = asyncio.run(self.conn.execute(q)).all()
|
||||
|
||||
logging.debug(f"get_groups(filterTerm={filter_term}, groupName={group_name}, groupDomain={group_domain}) => {results}")
|
||||
logging.debug(
|
||||
f"get_groups(filterTerm={filter_term}, groupName={group_name}, groupDomain={group_domain}) => {results}")
|
||||
return results
|
||||
|
||||
def get_group_relations(self, user_id=None, group_id=None):
|
||||
|
||||
Reference in New Issue
Block a user