Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for crossproc events to timeline.py #19

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
311 changes: 194 additions & 117 deletions timeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
_python3 = False


def process_search(cb_conn, query, query_base=None,
filemods=None, netconns=None,
processes=None, regmods=None):
def process_search(
cb_conn, query, query_base=None,
filemods=None, netconns=None,
processes=None, regmods=None,
crossprocs=None):

if query_base != None:
if query_base is not None:
query += query_base

log_info("QUERY: {0}".format(query))
Expand All @@ -41,7 +43,10 @@ def process_search(cb_conn, query, query_base=None,
for proc in query_result:
process_counter += 1
if process_counter % 10 == 0:
log_info('Processing {0} of {1}'.format(process_counter, query_result_len))
log_info('Processing {0} of {1}'.format(
process_counter,
query_result_len
))

hostname = proc.hostname.lower()
username = proc.username.lower()
Expand All @@ -50,81 +55,113 @@ def process_search(cb_conn, query, query_base=None,

try:
process_md5 = path.process_md5
except:
except Exception:
process_md5 = ''

parent_name = proc.parent_name

if processes == True:
results.append(('process',
convert_timestamp(proc.start),
hostname,
username,
path,
cmdline,
process_md5,
parent_name,
proc.childproc_count,
proc.webui_link
))

if netconns == True:
if processes is True:
results.append((
'process',
convert_timestamp(proc.start),
hostname,
username,
path,
cmdline,
process_md5,
parent_name,
proc.childproc_count,
proc.webui_link
))

if netconns is True:
for netconn in proc.all_netconns():
results.append(('netconn',
convert_timestamp(netconn.timestamp),
hostname,
username,
path,
cmdline,
process_md5,
parent_name,
proc.childproc_count,
proc.webui_link,
netconn.domain,
netconn.remote_ip,
netconn.remote_port,
netconn.local_ip,
netconn.local_port,
netconn.proto,
netconn.direction
))

if filemods == True:
results.append((
'netconn',
convert_timestamp(netconn.timestamp),
hostname,
username,
path,
cmdline,
process_md5,
parent_name,
proc.childproc_count,
proc.webui_link,
netconn.domain,
netconn.remote_ip,
netconn.remote_port,
netconn.local_ip,
netconn.local_port,
netconn.proto,
netconn.direction
))

if filemods is True:
for filemod in proc.all_filemods():
results.append(('filemod',
convert_timestamp(filemod.timestamp),
hostname,
username,
path,
cmdline,
process_md5,
parent_name,
proc.childproc_count,
proc.webui_link,
'','','','','','','', # netconn
filemod.path,
filemod.type,
filemod.md5
))

if regmods == True:
results.append((
'filemod',
convert_timestamp(filemod.timestamp),
hostname,
username,
path,
cmdline,
process_md5,
parent_name,
proc.childproc_count,
proc.webui_link,
'', '', '', '', '', '', '', # netconn
filemod.path,
filemod.type,
filemod.md5
))

if regmods is True:
for regmod in proc.all_regmods():
results.append(('regmod',
convert_timestamp(regmod.timestamp),
hostname,
username,
path,
cmdline,
process_md5,
parent_name,
proc.childproc_count,
proc.webui_link,
'','','','','','','', # netconn
'','','', # filemod
regmod.path,
regmod.type
))

results.append((
'regmod',
convert_timestamp(regmod.timestamp),
hostname,
username,
path,
cmdline,
process_md5,
parent_name,
proc.childproc_count,
proc.webui_link,
'', '', '', '', '', '', '', # netconn
'', '', '', # filemod
regmod.path,
regmod.type
))

if crossprocs is True:
for crossproc in proc.all_crossprocs():
results.append((
'crossproc',
convert_timestamp(crossproc.timestamp),
hostname,
username,
path,
cmdline,
process_md5,
parent_name,
proc.childproc_count,
proc.webui_link,
'', '', '', '', '', '', '', # netconn
'', '', '', # filemod
'', '', # regmod
crossproc.type,
crossproc.privileges,
crossproc.privilege_code,
crossproc.tamper_flag,
crossproc.is_target,
crossproc.target_procguid,
crossproc.target_md5,
crossproc.target_path,
crossproc.source_procguid,
crossproc.source_md5,
crossproc.source_path
))

except KeyboardInterrupt:
log_info("Caught CTRL-C. Returning what we have . . .")
Expand All @@ -136,16 +173,36 @@ def main():
parser = build_cli_parser("Timeline utility")

# Output options
output_events = parser.add_argument_group('output_events',
"If any output type is set, all other types will be suppressed unless they are explicitly set as well.")
output_events.add_argument("--filemods", action="store_true",
help="Output file modification records.")
output_events.add_argument("--netconns", action="store_true",
help="Output network connection records.")
output_events.add_argument("--processes", action="store_true",
help="Output process start records.")
output_events.add_argument("--regmods", action="store_true",
help="Output registry modification records.")
output_events = parser.add_argument_group(
'output_events',
"If any output type is set, all other types will be suppressed "
"unless they are explicitly set as well."
)
output_events.add_argument(
"--filemods",
action="store_true",
help="Output file modification records."
)
output_events.add_argument(
"--netconns",
action="store_true",
help="Output network connection records."
)
output_events.add_argument(
"--processes",
action="store_true",
help="Output process start records."
)
output_events.add_argument(
"--regmods",
action="store_true",
help="Output registry modification records."
)
output_events.add_argument(
"--crossprocs",
action="store_true",
help="Output cross-process activity records."
)

args = parser.parse_args()

Expand All @@ -154,13 +211,13 @@ def main():
else:
filename = 'timeline.csv'

if args.append == True or args.queryfile is not None:
if (args.append is True) or (args.queryfile is not None):
file_mode = 'a'
else:
file_mode = 'w'

if args.days:
query_base = ' start:-{0}m'.format(args.days*1440)
query_base = ' start:-{0}m'.format(args.days * 1440)
elif args.minutes:
query_base = ' start:-{0}m'.format(args.minutes)
else:
Expand All @@ -170,16 +227,20 @@ def main():
# all to True. If any are set to True, then evaluate each independently.
# If you're reading this and know of a cleaner way to do this, ideally via
# argparse foolery, by all means . . .
if args.filemods == False and \
args.netconns == False and \
args.processes == False and \
args.regmods == False:
(filemods, netconns, processes, regmods) = (True, True, True, True)
if (args.filemods is False and
args.netconns is False and
args.processes is False and
args.regmods is False and
args.crossprocs is False):
(filemods, netconns, processes, regmods, crossprocs) = (
True, True, True, True, True
)
else:
filemods = args.filemods
netconns = args.netconns
processes = args.processes
regmods = args.regmods
crossprocs = args.crossprocs

if args.profile:
cb = CbEnterpriseResponseAPI(profile=args.profile)
Expand All @@ -199,42 +260,58 @@ def main():

file = open(filename, file_mode)
writer = csv.writer(file)
writer.writerow(["event_type",
"timestamp",
"hostname",
"username",
"path",
"cmdline",
"process_md5",
"parent",
"childproc_count",
"url",
"netconn_domain",
"netconn_remote_ip",
"netconn_remote_port",
"netconn_local_ip",
"netconn_local_port",
"netconn_proto",
"netconn_direction",
"filemod_path",
"filemod_type",
"filemod_md5",
"regmod_path",
"regmod_type"
])
writer.writerow(
[
"event_type",
"timestamp",
"hostname",
"username",
"path",
"cmdline",
"process_md5",
"parent",
"childproc_count",
"url",
"netconn_domain",
"netconn_remote_ip",
"netconn_remote_port",
"netconn_local_ip",
"netconn_local_port",
"netconn_proto",
"netconn_direction",
"filemod_path",
"filemod_type",
"filemod_md5",
"regmod_path",
"regmod_type",
"crossproc_type",
"crossproc_privileges",
"crossproc_privilege_code",
"crossproc_tamper_flag",
"crossproc_is_target",
"crossproc_target_procguid",
"crossproc_target_md5",
"crossproc_target_path",
"crossproc_source_procguid",
"crossproc_source_md5",
"crossproc_source_path"
]
)

for query in queries:
result_set = process_search(cb, query, query_base, filemods, netconns,
processes, regmods)
result_set = process_search(
cb, query, query_base, filemods,
netconns, processes, regmods,
crossprocs
)

for row in result_set:
if _python3 == False:
if _python3 is False:
row = [col.encode('utf8') if isinstance(col, unicode) else col for col in row]
writer.writerow(row)

file.close()


if __name__ == '__main__':

sys.exit(main())