mirror of https://github.com/n1nj4sec/pupy.git
Add isearch module
This commit is contained in:
parent
8de4ff940a
commit
9593b71df0
|
@ -0,0 +1,103 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
|
||||
from pupylib.PupyModule import config, PupyModule, PupyArgumentParser
|
||||
from pupylib.PupyOutput import Table
|
||||
from argparse import REMAINDER
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
__class_name__='IndexSearchModule'
|
||||
|
||||
# ZOMG Kill me please
|
||||
def escape(x):
|
||||
if "'" in x:
|
||||
x = x.replace("'", "")
|
||||
|
||||
return "'" + x + "'"
|
||||
|
||||
@config(cat='gather', compat='windows')
|
||||
class IndexSearchModule(PupyModule):
|
||||
''' Use Windows Search Index to search for data '''
|
||||
|
||||
dependencies = [
|
||||
'win32com', 'win32api', 'winerror',
|
||||
'numbers', 'decimal', 'adodbapi', 'isearch'
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def init_argparse(cls):
|
||||
cls.arg_parser = PupyArgumentParser(prog='isearch', description=cls.__doc__)
|
||||
cls.arg_parser.add_argument(
|
||||
'-L', '--limit', type=int, help='Limit records (default 50)',
|
||||
default=50)
|
||||
cls.arg_parser.add_argument('-v', '--verbose', action='store_true',
|
||||
default=False, help='Show SQL query')
|
||||
cls.arg_parser.add_argument('-t', '--text', help='Text to search')
|
||||
cls.arg_parser.add_argument('-p', '--path', help='Path to search')
|
||||
cls.arg_parser.add_argument('-d', '--directory', help='Directory to limit output')
|
||||
cls.arg_parser.add_argument(
|
||||
'-R', '--raw', metavar='SELECT ... FROM SYSTEMINDEX ...',
|
||||
nargs=REMAINDER, help='RAW SQL Query to search '\
|
||||
'(https://docs.microsoft.com/en-us/windows/'\
|
||||
'desktop/search/-search-3x-advancedquerysyntax)')
|
||||
|
||||
def run(self, args):
|
||||
query = self.client.remote('isearch', 'query')
|
||||
|
||||
request = []
|
||||
if args.raw:
|
||||
request = args.raw
|
||||
else:
|
||||
request.append('SELECT TOP {} System.ItemUrl, System.Size, System.DateModified FROM SYSTEMINDEX'.format(args.limit))
|
||||
where = []
|
||||
if args.text:
|
||||
where.append('FREETEXT({})'.format(escape(args.text)))
|
||||
if args.directory:
|
||||
where.append('SCOPE={}'.format(escape('file:'+args.directory)))
|
||||
if args.path:
|
||||
where.append('CONTAINS(System.FileName, {})'.format(escape(args.path)))
|
||||
|
||||
if where:
|
||||
request.append('WHERE')
|
||||
request.append('AND'.join(where))
|
||||
|
||||
request.append('ORDER BY System.DateModified DESC')
|
||||
|
||||
if not request:
|
||||
self.error('You should specify request')
|
||||
return
|
||||
|
||||
text = ' '.join(request)
|
||||
|
||||
if args.verbose:
|
||||
self.info('QUERY: {}'.format(text))
|
||||
|
||||
idx, cidx, data, error = query(text, args.limit)
|
||||
if error:
|
||||
self.error(error)
|
||||
elif not data:
|
||||
self.warning('No data found')
|
||||
else:
|
||||
objects = []
|
||||
header = []
|
||||
legend = True
|
||||
|
||||
if args.raw:
|
||||
legend = False
|
||||
for record in data:
|
||||
objects.append({
|
||||
str(idx):v for idx,v in enumerate(record)
|
||||
})
|
||||
header = [
|
||||
str(x) for x in xrange(cidx+1)
|
||||
]
|
||||
else:
|
||||
header = ['File', 'Size', 'Modified']
|
||||
for record in data:
|
||||
objects.append({
|
||||
'File': record[0][5:] if record[0].startswith('file:') else record[0],
|
||||
'Size': record[1],
|
||||
'Modified': datetime.fromtimestamp(record[2])
|
||||
})
|
||||
|
||||
self.log(Table(objects, header, legend=legend))
|
|
@ -0,0 +1,47 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import adodbapi
|
||||
import sys
|
||||
import datetime
|
||||
|
||||
PROVIDER = 'provider=Search.CollatorDSO.1;EXTENDED?PROPERTIES="Application=Windows"'
|
||||
|
||||
def query(sql, limit):
|
||||
data = []
|
||||
error = None
|
||||
idx = 0
|
||||
cidx = 0
|
||||
|
||||
encoding = sys.getfilesystemencoding()
|
||||
|
||||
conn = adodbapi.connect(PROVIDER)
|
||||
|
||||
try:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(sql)
|
||||
for idx, record in enumerate(cursor):
|
||||
|
||||
if idx >= limit:
|
||||
break
|
||||
|
||||
line = []
|
||||
for cidx, column in enumerate(record):
|
||||
if type(column) == str:
|
||||
column = column.decode(encoding)
|
||||
elif type(column) == datetime.datetime:
|
||||
column = int((
|
||||
column - datetime.datetime.fromtimestamp(0)
|
||||
).total_seconds())
|
||||
line.append(column)
|
||||
data.append(tuple(line))
|
||||
|
||||
except adodbapi.apibase.DatabaseError, e:
|
||||
# ZOMG
|
||||
parts = e.message.split('\n')
|
||||
code = eval(parts[0])[1].decode(encoding)
|
||||
error = '\n'.join(parts[1:]) + '\n' + code
|
||||
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
return idx, cidx, data, error
|
Loading…
Reference in New Issue