prepare classifiers implemented, now for actual classification...

This commit is contained in:
robert-todora
2023-07-19 16:52:54 -04:00
parent f4c069755a
commit 9bb6cbef18
4 changed files with 82 additions and 46 deletions
+19 -11
View File
@@ -13,16 +13,24 @@ Tested with Python 3.10.6
## Usage
`usage: snaffler.py [-h] [-u username] [-p password] [-d domain] [-v] [-i] [-n] targets [targets ...] `
`usage: snaffler.py [-h] [-u USERNAME] [-p PASSWORD] [-d DOMAIN] [-H HASH] [-v] [--go-loud] [-i] [-n] targets [targets ...]`
## Options
1. targets IPs, hostnames, CIDR ranges, or files contains targets to snaffle
2. -h, --help show help message and exit
3. -u username, --username username username for LDAP login and SMB
4. -p password, --password password password for LDAP login and SMB
5. -d domain, --domain domain Domain to authenticate to
6. -H hash, --hash hash NT hash for authentication
7. -v, --verbose Show debugging information
8. -i, --no-discovery Disables computer and share discovery (more stealthy, maybe)
9. -n, --disable-computer-discovery Disable computer discovery, requires a single host or list of hosts to do discovery on
~~~
options:
-h, --help show this help message and exit
-u USERNAME, --username USERNAME
domain username
-p PASSWORD, --password PASSWORD
password for domain user
-d DOMAIN, --domain DOMAIN
FQDN domain to authenticate to, if this option is not provided, SnafflePy will attempt to automatically discover the domain for you
-H HASH, --hash HASH NT hash for authentication
-v, --verbose Show more info
--go-loud Don't try to find anything interesting, literally just go through every computer and every share and print out as many files as possible. Use at your own
risk
-i, --no-share-discovery
Disables share discovery (more stealthy)
-n, --disable-computer-discovery
Disable computer discovery, requires a list of hosts to do discovery on
~~~
+32 -6
View File
@@ -1,9 +1,17 @@
import re
import toml
from impacket.smbconnection import SessionError, SMBConnection
import os
import logging
import pprint
from impacket.smbconnection import SessionError, SMBConnection
log = logging.getLogger('snafflepy.classifier')
# TODO
# TODO
class Rules:
def __init__(self) -> None:
self.classifier_rules = []
@@ -13,7 +21,6 @@ class Rules:
self.contents_classifiers = []
self.postmatch_classifiers = []
def prepare_classifiers(self):
share_path = "./snaffcore/DefaultRules/"
@@ -21,11 +28,31 @@ class Rules:
for name in files:
# print(os.path.join(root,name))
with open(os.path.join(root, name), 'r') as tfile:
yield toml.load(tfile)
toml_loaded = toml.load(tfile)
for dict_rule in toml_loaded['ClassifierRules']:
if dict_rule['EnumerationScope'] == "ShareEnumeration":
self.share_classifiers.append(dict_rule)
elif dict_rule['EnumerationScope'] == "FileEnumeration":
self.file_classifiers.append(dict_rule)
elif dict_rule['EnumerationScope'] == "DirectoryEnumeration":
self.directory_classifiers.append(dict_rule)
elif dict_rule['EnumerationScope'] == "PostMatch":
self.postmatch_classifiers.append(dict_rule)
elif dict_rule['EnumerationScope'] == "ContentsEnumeration":
self.contents_classifiers.append(dict_rule)
else:
log.warning(
f"{dict_rule['RuleName']} is invalid, please check your syntax!")
# pprint.pprint(self.share_classifiers)
# pprint.pprint(self.directory_classifiers)
# pprint.pprint(self.file_classifiers)
# pprint.pprint(self.contents_classifiers)
# pprint.pprint(self.postmatch_classifiers)
# TODO
def is_interest(file):
# massive_wordlist = prepare_classifiers()
# print(massive_wordlist)
@@ -33,10 +60,9 @@ def is_interest(file):
# for name in files:
# with open(os.path.join(root, name), 'rb') as tfile:
# print(toml.loads(tfile))
interest_names = ["Creds.txt"]
if file.get_shortname() in interest_names:
return True
else:
return False
return False
+24 -24
View File
@@ -18,28 +18,28 @@ def begin_snaffle(options):
# Prepare classifiers for use in naive_classify()
snaff_rules = Rules()
# prepped_rules = snaff_rules.prepare_classifiers()
prepped_rules = snaff_rules.prepare_classifiers()
# for dict_rules in prepped_rules:
# for actual_rule in dict_rules['ClassifierRules']:
# pprint.pprint(actual_rule['Triage'])
print("Beginning the snaffle...")
sleep(0.2)
if(not options.domain):
if not options.domain:
log.info("Domain not provided, retrieving automatically.")
s = Server(options.targets[0], get_info = ALL)
s = Server(options.targets[0], get_info=ALL)
c = Connection(s)
if(not c.bind()):
log.error("Could not get domain automatically")
sys.exit(1)
else:
try:
options.domain = str(s.info.other["ldapServiceName"][0].split("@")[1]).lower()
except Exception as e:
log.error("Could not get domain automatically")
sys.exit(1)
if not c.bind():
log.error("Could not get domain automatically")
sys.exit(1)
else:
try:
options.domain = str(
s.info.other["ldapServiceName"][0].split("@")[1]).lower()
except Exception as e:
log.error("Could not get domain automatically")
sys.exit(1)
c.unbind()
domain_names = []
@@ -58,7 +58,7 @@ def begin_snaffle(options):
f"Found{target}, adding to targets to snaffle...")
sleep(0.5)
try:
# TODO: Try to fix this? - How to resolve local IP address from Hostname
# TODO: Try to fix this? - How to resolve internal IP address from Hostname
# Supposedly SMBConnection should be able to take a hostname but not working as intended on the HTB enviroment I am using for testing
# ip = resolve(options.domain, target)
options.targets.append(target)
@@ -79,8 +79,8 @@ def begin_snaffle(options):
except:
log.error(f"Error logging in to SMB on {options.targets[0]}")
else:
log.info("Enumerating shares for files...")
if options.go_loud:
log.warning("[GO LOUD ACTIVATED] Enumerating all shares for all files...")
for target in options.targets:
try:
smb_client = SMBClient(
@@ -89,12 +89,12 @@ def begin_snaffle(options):
for share in smb_client.shares:
try:
files = smb_client.ls(share, "")
for file in files:
# filelist.append(file)
# Ask do they want file sizes?
# log.info(f"{target} Found file in {share}: {file.get_longname()}")
naive_classify(share, file, prepped_rules)
log.info(f"{target} Found file in {share}: {file.get_longname()}")
# naive_classify(share, file, prepped_rules)
# log.info(f"{target} Found file in {share}: {file}")
except FileListError:
log.error(
@@ -103,9 +103,8 @@ def begin_snaffle(options):
except Exception as e:
log.error(f"Error creating SMBClient object, {e}")
else:
pass
def access_ldap_server(ip, username, password):
log.info("Accessing LDAP Server")
@@ -166,9 +165,10 @@ def list_computers(connection: Connection, domain):
return None
# TODO
def naive_classify(share, file, rules:Rules):
def naive_classify(share, file, rules: Rules):
log.info(f"{share}: {file.get_longname()}")
if is_interest(file, rules):
log.info(f"Found interesting file: {share}/{file}")
+7 -5
View File
@@ -19,16 +19,18 @@ def parse_arguments():
add_help=True, prog='snaffler.py', description='A "port" of Snaffler in python')
parser.add_argument("targets", nargs='+', type=make_targets,
help="IPs, hostnames, CIDR ranges, or files contains targets to snaffle. If you are providing more than one target, the -n option must be used.")
parser.add_argument("-u", "--username", metavar='username',
parser.add_argument("-u", "--username",
type=str, help="domain username")
parser.add_argument("-p", "--password", metavar='password',
parser.add_argument("-p", "--password",
type=str, help="password for domain user")
parser.add_argument("-d", "--domain", metavar='domain',
default="", help="FQDN domain to authenticate to")
parser.add_argument("-H", "--hash", metavar='hash',
parser.add_argument("-d", "--domain",
default="", help="FQDN domain to authenticate to, if this option is not provided, SnafflePy will attempt to automatically discover the domain for you")
parser.add_argument("-H", "--hash",
default="", help="NT hash for authentication")
parser.add_argument("-v", "--verbose",
action='store_true', help="Show more info")
parser.add_argument("--go-loud", action='store_true',
help="Don't try to find anything interesting, literally just go through every computer and every share and print out as many files as possible. Use at your own risk")
# parser.add_argument("-e", "--exclude", )
# TODO