Last active
June 18, 2019 17:10
-
-
Save FrankSpierings/3eebfa89cce1ae0062ceb7bad1ab945f to your computer and use it in GitHub Desktop.
Playing with impacket smb and solr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import logging | |
import string | |
import os | |
import requests | |
import re | |
from impacket.smbconnection import * | |
log = logging.getLogger() | |
logging.basicConfig(format='%(levelname)s: %(asctime)s - %(name)s - %(process)s - %(message)s', | |
level=logging.INFO, datefmt='%I:%M:%S') | |
default_shares = [u'{0}$'.format(i) for i in string.ascii_uppercase] | |
default_shares.append('IPC$') | |
default_shares.append('ADMIN$') | |
extensions = ['ini', 'conf', 'config', 'xml', 'reg', 'vbs', 'ps1', 'txt', 'pdf', 'xlsx', 'xls', 'docx', 'doc'] | |
exclude_regexes = ['desktop.ini$', '/WinSxS$', '/system32$', '/SysWow64$', '/appcompat$', | |
'/diagnostics$', '/DriverStore$', '/INF$', '/Microsoft.NET$', '/WindowsPowerShell/Modules/Pester$', | |
'/AppData/Local/Packages$', '/SystemApps$'] | |
class SmbIndexer(): | |
def __init__(self, url, target, username, password, domain='', maxdepth=10, maxfilesize=(100*1024*1024)): | |
self.url = url | |
self.target = target | |
self.username = username | |
self.password = password | |
self.domain = domain | |
self.maxdepth = maxdepth | |
self.maxfilesize = maxfilesize | |
self.smb = SMBConnection(target, target) | |
self.smb.login(username, password, domain) | |
def index(self, spider_default_shares=False): | |
for share in self.smb.listShares(): | |
share_name = share['shi1_netname'][:-1] | |
share_remark = share['shi1_remark'][:-1] | |
if spider_default_shares or share_name not in default_shares: | |
log.info(u'{0}: {1}'.format(share_name, share_remark)) | |
self.__recur(share_name, u'', self.maxdepth) | |
def __getfullsharepath(self, share_name, path): | |
return u'//{0}/{1}{2}'.format(self.smb.getRemoteHost(), share_name, path) | |
def __recur(self, share_name, path, maxdepth): | |
excluded_dirs = ['..', '.'] | |
dirs = [] | |
entries = [] | |
if path == u'': | |
querypath = u'*' | |
else: | |
querypath = u'{0}/*'.format(path) | |
try: | |
entries = self.smb.listPath(share_name, querypath) | |
except (Exception) as e: | |
log.error('{0} - {1}'.format(self.__getfullsharepath(share_name, path), e)) | |
for entry in entries: | |
name = entry.get_longname() | |
newpath = u'{0}/{1}'.format(path, name) | |
if name not in excluded_dirs: | |
newfullpath = self.__getfullsharepath(share_name, newpath) | |
if self.__exclude_re_filter(newfullpath): | |
log.debug(u'{0}'.format(self.__getfullsharepath(share_name, newpath))) | |
if entry.is_directory(): | |
if path == '*': | |
dirs.append('{0}/*'.format(name)) | |
else: | |
dirs.append(newpath) | |
else: | |
# It is a file | |
self.__examinefile(share_name, newpath) | |
for directory in dirs: | |
if maxdepth-1 != 0: | |
self.__recur(share_name, directory, maxdepth-1) | |
else: | |
log.info(u'Maxdepth reached, will not examine: {0}'.format(self.__getfullsharepath(share_name, directory))) | |
def __examinefile(self, share_name, path): | |
ext = os.path.splitext(path)[1][1:] | |
ext = ext.lower() | |
filename = os.path.basename(path).lower() | |
if ext in extensions: | |
file = None | |
try: | |
file = self.smb.listPath(share_name, path)[0] | |
except (Exception) as e: | |
log.error(u'Examine; {0} - {1}'.format(self.__getfullsharepath(share_name, path), e)) | |
if file is not None: | |
if file.get_filesize() > self.maxfilesize: | |
log.info(u'Not indexing file since it is too large ({0} > {1}): {2}'.format(file.get_filesize(), self.maxfilesize, | |
self.__getfullsharepath(share_name, path))) | |
else: | |
self.__indexfile(share_name, path) | |
def __indexfile(self, share_name, path): | |
headers = {'Content-type': 'application/json'} | |
fullname = self.__getfullsharepath(share_name, path) | |
log.info('Indexing: {0}'.format(fullname)) | |
data = self.__readfile(share_name, path) | |
if data != None and data!= '': | |
url = '{0}/update/extract?commit=true&literal.id={1}'.format(self.url, fullname) | |
files = {'file': data} | |
requests.post(url, files=files, headers=headers) | |
data = None | |
def __readfile(self, share_name, path): | |
tid = None | |
fid = None | |
try: | |
tid = self.smb.connectTree(share_name) | |
except (Exception) as e: | |
log.error(u'Error while connecting tree: {0}'.format(e)) | |
try: | |
fid = self.smb.openFile(tid, path, desiredAccess=FILE_READ_DATA) | |
except (Exception) as e: | |
log.error(u'Error while opening file: {0}'.format(e)) | |
self.smb.disconnectTree(tid) | |
if tid is not None and fid is not None: | |
data = '' | |
tmpdata = '' | |
while True: | |
tmpdata = self.smb.readFile(tid, fid, offset=len(data)) | |
log.debug(u'Read {0} bytes'.format(len(tmpdata))) | |
if len(tmpdata) == 0: | |
break | |
else: | |
data += tmpdata | |
self.smb.closeFile(tid, fid) | |
self.smb.disconnectTree(tid) | |
return data | |
else: | |
return None | |
def __exclude_re_filter(self, fullpath): | |
for pattern in exclude_regexes: | |
if (re.search(pattern, fullpath, re.IGNORECASE)): | |
log.debug(u'Path excluded by pattern: "{0}" - "{1}"'.format(pattern, fullpath)) | |
matched = True | |
return False | |
return True | |
si = SmbIndexer('http://localhost:8983/solr/COLLECTOR1', '10.10.10.1', "administrator", "Password123!", maxdepth=-1) | |
si.index(spider_default_shares=True) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment