mirror of
https://github.com/Pennyw0rth/NetExec
synced 2026-06-06 16:34:30 +00:00
Added db_navigator stuff
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
import sys
|
||||
|
||||
from sqlalchemy import func, Table, select
|
||||
from sqlalchemy import func, Table, select, delete
|
||||
from sqlalchemy.dialects.sqlite import Insert # used for upsert
|
||||
from sqlalchemy.exc import (
|
||||
NoInspectionAvailable,
|
||||
NoSuchTableError,
|
||||
)
|
||||
|
||||
from nxc.database import BaseDB
|
||||
from nxc.database import BaseDB, format_host_query
|
||||
from nxc.logger import nxc_logger
|
||||
|
||||
class database(BaseDB):
|
||||
@@ -166,6 +166,14 @@ class database(BaseDB):
|
||||
|
||||
self.db_execute(q_groups, groups)
|
||||
|
||||
def remove_credentials(self, creds_id):
|
||||
"""Removes a credential ID from the database"""
|
||||
del_hosts = []
|
||||
for cred_id in creds_id:
|
||||
q = delete(self.UsersTable).filter(self.UsersTable.c.id == cred_id)
|
||||
del_hosts.append(q)
|
||||
self.db_execute(q)
|
||||
|
||||
def is_credential_valid(self, credential_id):
|
||||
"""Check if this credential ID is valid."""
|
||||
q = select(self.UsersTable).filter(
|
||||
@@ -200,4 +208,32 @@ class database(BaseDB):
|
||||
self.UsersTable.c.credtype == cred_type,
|
||||
)
|
||||
results = self.db_execute(q).first()
|
||||
return results.id
|
||||
return results.id
|
||||
|
||||
def get_hosts(self, filter_term=None, domain=None):
|
||||
"""Return hosts from the database."""
|
||||
q = select(self.HostsTable)
|
||||
|
||||
# if we're returning a single host by ID
|
||||
if self.is_host_valid(filter_term):
|
||||
q = q.filter(self.HostsTable.c.id == filter_term)
|
||||
results = self.db_execute(q).first()
|
||||
# all() returns a list, so we keep the return format the same so consumers don't have to guess
|
||||
return [results]
|
||||
elif filter_term is not None and filter_term.startswith("domain"):
|
||||
domain = filter_term.split()[1]
|
||||
like_term = func.lower(f"%{domain}%")
|
||||
q = q.filter(self.HostsTable.c.domain.like(like_term))
|
||||
# if we're filtering by ip/hostname
|
||||
elif filter_term and filter_term != "":
|
||||
q = format_host_query(q, filter_term, self.HostsTable)
|
||||
|
||||
results = self.db_execute(q).all()
|
||||
nxc_logger.debug(f"ldap hosts() - results: {results}")
|
||||
return results
|
||||
|
||||
def is_host_valid(self, host_id):
|
||||
"""Check if this host ID is valid."""
|
||||
q = select(self.HostsTable).filter(self.HostsTable.c.id == host_id)
|
||||
results = self.db_execute(q).all()
|
||||
return len(results) > 0
|
||||
@@ -1,7 +1,183 @@
|
||||
from nxc.nxcdb import DatabaseNavigator, print_help
|
||||
from nxc.helpers.misc import validate_ntlm
|
||||
from nxc.nxcdb import DatabaseNavigator, print_table, print_help
|
||||
|
||||
|
||||
class navigator(DatabaseNavigator):
|
||||
def display_hosts(self, hosts):
|
||||
data = [
|
||||
[
|
||||
"HostID",
|
||||
"IP",
|
||||
"Hostname",
|
||||
"Domain",
|
||||
"OS"
|
||||
]
|
||||
]
|
||||
|
||||
for host in hosts:
|
||||
host_id = host[0]
|
||||
ip = host[1]
|
||||
hostname = host[2]
|
||||
domain = host[3]
|
||||
|
||||
try:
|
||||
os = host[4].decode()
|
||||
except Exception:
|
||||
os = host[4]
|
||||
|
||||
data.append(
|
||||
[
|
||||
host_id,
|
||||
ip,
|
||||
hostname,
|
||||
domain,
|
||||
os
|
||||
]
|
||||
)
|
||||
print_table(data, title="Hosts")
|
||||
|
||||
def do_hosts(self, line):
|
||||
filter_term = line.strip()
|
||||
|
||||
if filter_term == "":
|
||||
hosts = self.db.get_hosts()
|
||||
self.display_hosts(hosts)
|
||||
else:
|
||||
hosts = self.db.get_hosts(filter_term=filter_term)
|
||||
|
||||
if len(hosts) > 1:
|
||||
self.display_hosts(hosts)
|
||||
elif len(hosts) == 1:
|
||||
data = [
|
||||
[
|
||||
"HostID",
|
||||
"IP",
|
||||
"Hostname",
|
||||
"Domain",
|
||||
"OS"
|
||||
]
|
||||
]
|
||||
host_id_list = []
|
||||
|
||||
for host in hosts:
|
||||
host_id = host[0]
|
||||
host_id_list.append(host_id)
|
||||
ip = host[1]
|
||||
hostname = host[2]
|
||||
domain = host[3]
|
||||
|
||||
try:
|
||||
os = host[4].decode()
|
||||
except Exception:
|
||||
os = host[4]
|
||||
|
||||
data.append(
|
||||
[
|
||||
host_id,
|
||||
ip,
|
||||
hostname,
|
||||
domain,
|
||||
os
|
||||
]
|
||||
)
|
||||
print_table(data, title="Host")
|
||||
|
||||
def help_hosts(self):
|
||||
help_string = """
|
||||
hosts [filter_term]
|
||||
By default prints all hosts
|
||||
Table format:
|
||||
| 'HostID', 'IP', 'Hostname', 'Domain', 'OS' |
|
||||
Subcommands:
|
||||
filter_term - filters hosts with filter_term
|
||||
If a single host is returned (e.g. `hosts 15`, it prints the following tables:
|
||||
Host | 'HostID', 'IP', 'Hostname', 'Domain', 'OS' |
|
||||
Otherwise, it prints the default host table from a `like` query on the `ip` and `hostname` columns
|
||||
"""
|
||||
print_help(help_string)
|
||||
|
||||
def display_creds(self, creds):
|
||||
data = [["CredID", "CredType", "Domain", "UserName", "Password"]]
|
||||
|
||||
for cred in creds:
|
||||
cred_id = cred[0]
|
||||
domain = cred[1]
|
||||
username = cred[2]
|
||||
password = cred[3]
|
||||
credtype = cred[4]
|
||||
|
||||
data.append(
|
||||
[
|
||||
cred_id,
|
||||
credtype,
|
||||
domain,
|
||||
username,
|
||||
password
|
||||
]
|
||||
)
|
||||
print_table(data, title="Credentials")
|
||||
|
||||
def do_creds(self, line):
|
||||
filter_term = line.strip()
|
||||
|
||||
if filter_term == "":
|
||||
creds = self.db.get_credentials()
|
||||
self.display_creds(creds)
|
||||
elif filter_term.split()[0].lower() == "add":
|
||||
args = filter_term.split()[1:]
|
||||
|
||||
if len(args) == 3:
|
||||
domain, username, password = args
|
||||
if validate_ntlm(password):
|
||||
self.db.add_credential("hash", domain, username, password)
|
||||
else:
|
||||
self.db.add_credential("plaintext", domain, username, password)
|
||||
else:
|
||||
print("[!] Format is 'add domain username password")
|
||||
return
|
||||
elif filter_term.split()[0].lower() == "remove":
|
||||
args = filter_term.split()[1:]
|
||||
|
||||
if len(args) != 1:
|
||||
print("[!] Format is 'remove <credID>'")
|
||||
return
|
||||
else:
|
||||
self.db.remove_credentials(args)
|
||||
elif filter_term.split()[0].lower() == "plaintext":
|
||||
creds = self.db.get_credentials(cred_type="plaintext")
|
||||
self.display_creds(creds)
|
||||
elif filter_term.split()[0].lower() == "hash":
|
||||
creds = self.db.get_credentials(cred_type="hash")
|
||||
self.display_creds(creds)
|
||||
else:
|
||||
creds = self.db.get_credentials(filter_term=filter_term)
|
||||
data = [["CredID", "CredType", "Domain", "UserName", "Password"]]
|
||||
cred_id_list = []
|
||||
|
||||
for cred in creds:
|
||||
cred_id_list.append(cred[0])
|
||||
data.append([cred[0], cred[1], cred[2], cred[3], cred[4]])
|
||||
|
||||
print_table(data, title="Credential(s)")
|
||||
|
||||
def help_creds(self):
|
||||
help_string = """
|
||||
creds [add|remove|plaintext|hash|filter_term]
|
||||
By default prints all creds
|
||||
Table format:
|
||||
| 'CredID', 'CredType', 'Domain', 'UserName', 'Password' |
|
||||
Subcommands:
|
||||
add - format: "add domain username password <notes> <credType> <sid>"
|
||||
remove - format: "remove <credID>"
|
||||
plaintext - prints plaintext creds
|
||||
hash - prints hashed creds
|
||||
filter_term - filters creds with filter_term
|
||||
If a single credential is returned (e.g. `creds 15`, it prints the following tables:
|
||||
Credential(s) | 'CredID', 'CredType', 'Domain', 'UserName', 'Password'
|
||||
Otherwise, it prints the default credential table from a `like` query on the `username` column
|
||||
"""
|
||||
print_help(help_string)
|
||||
|
||||
def do_clear_database(self, line):
|
||||
if input("This will destroy all data in the current database, are you SURE you want to run this? (y/n): ") == "y":
|
||||
self.db.clear_database()
|
||||
|
||||
Reference in New Issue
Block a user