373 lines
14 KiB
Python
373 lines
14 KiB
Python
import json
|
|
import time
|
|
|
|
import process
|
|
import rule
|
|
import sql
|
|
import global_vars
|
|
import config
|
|
import plugin
|
|
import hash_white_list
|
|
|
|
LOG_TYPE_PROCESS_CREATE = 1
|
|
LOG_TYPE_PROCESS_ACTION = 2
|
|
|
|
|
|
def update_att_ck(process: process.Process, score, hit_name, attck_t_list):
|
|
if hash_white_list.check_in_while_list(process):
|
|
score = 0
|
|
for t in attck_t_list:
|
|
process.set_attck(score, t, hit_name)
|
|
# 更新命中的规则
|
|
return global_vars.THREAT_TYPE_PROCESS
|
|
|
|
|
|
def update_threat(process: process.Process, score, rule_hit_name):
|
|
had_threat = global_vars.THREAT_TYPE_NONE
|
|
if hash_white_list.check_in_while_list(process):
|
|
score = 0
|
|
if score > 0:
|
|
# 更新命中的规则
|
|
process.set_score(score, rule_hit_name)
|
|
had_threat = global_vars.THREAT_TYPE_PROCESS
|
|
return had_threat
|
|
|
|
|
|
def match_threat(process: process.Process, log, log_type):
|
|
had_threat = global_vars.THREAT_TYPE_NONE
|
|
success_match = False
|
|
hit_name = ''
|
|
hit_score = 0
|
|
is_ioa = False
|
|
if log_type == LOG_TYPE_PROCESS_CREATE:
|
|
success_match, is_ioa, attck_t_list, hit_score, rule_hit_name = rule.calc_score_in_create_process(
|
|
log)
|
|
elif log_type == LOG_TYPE_PROCESS_ACTION:
|
|
success_match, is_ioa, attck_t_list, hit_score, rule_hit_name = rule.calc_score_in_action(
|
|
log)
|
|
if success_match == False:
|
|
return had_threat, is_ioa, hit_name, hit_score
|
|
# 匹配到了首先更新att&ck的t
|
|
had_threat = update_att_ck(
|
|
process, hit_score, rule_hit_name, attck_t_list)
|
|
hit_name = rule_hit_name
|
|
if is_ioa:
|
|
had_threat = update_threat(
|
|
process, hit_score, rule_hit_name)
|
|
else:
|
|
is_match_software, software_name, software_score = rule.match_att_ck_software(
|
|
process.chain.attck_hit_list)
|
|
if is_match_software:
|
|
# 匹配到software了,设置为ioa
|
|
had_threat = update_threat(
|
|
process, software_score, software_name)
|
|
hit_name = software_name
|
|
hit_score = software_score
|
|
#print('match_threat', process.path, is_ioa, hit_name, hit_score)
|
|
# if had_threat != global_vars.THREAT_TYPE_NONE:
|
|
# print('path: {} hit_name: {} socre: {}'.format(
|
|
# process.path, hit_name, hit_score))
|
|
return had_threat, is_ioa, hit_name, hit_score
|
|
|
|
|
|
def update_process_threat_status(current_process: process.Process, host, had_threat):
|
|
if current_process is not None:
|
|
# if current_process.path.find("f.exe") != -1:
|
|
# print(log)
|
|
if current_process.chain.risk_score >= config.MAX_THREAT_SCORE:
|
|
if had_threat == global_vars.THREAT_TYPE_PROCESS:
|
|
current_process.chain.update_process_tree()
|
|
threat = sql.select_threat_by_chain_id(
|
|
host, current_process.chain.hash, global_vars.THREAT_TYPE_PROCESS
|
|
)
|
|
if len(threat) == 0:
|
|
process_info: process.Process = None
|
|
|
|
if len(current_process.chain.process_list) > 1:
|
|
process_info = current_process.chain.process_list[1]
|
|
else:
|
|
process_info = current_process
|
|
info_save_data = {
|
|
"path": process_info.path,
|
|
"hash": process_info.md5,
|
|
"params": process_info.params,
|
|
"user": process_info.user,
|
|
"create_time": process_info.time,
|
|
}
|
|
sql.push_threat_log(
|
|
host,
|
|
current_process.chain.risk_score,
|
|
json.dumps(current_process.chain.operationlist),
|
|
json.dumps(current_process.chain.attck_hit_list),
|
|
current_process.chain.hash,
|
|
current_process.chain.get_json(),
|
|
global_vars.THREAT_TYPE_PROCESS,
|
|
json.dumps(info_save_data),
|
|
)
|
|
else:
|
|
sql.update_threat_log(
|
|
host,
|
|
current_process.chain.risk_score,
|
|
json.dumps(current_process.chain.operationlist),
|
|
json.dumps(current_process.chain.attck_hit_list),
|
|
current_process.chain.hash,
|
|
current_process.chain.get_json(),
|
|
global_vars.THREAT_TYPE_PROCESS,
|
|
current_process.chain.active == False,
|
|
)
|
|
|
|
|
|
def process_log(host, json_log, raw_log):
|
|
log = json_log["data"]
|
|
had_threat = global_vars.THREAT_TYPE_NONE
|
|
current_process: process.Process = None
|
|
rule_hit_name = ""
|
|
score = 0
|
|
chain_hash = ""
|
|
params = ""
|
|
user = ""
|
|
is_ioa = False
|
|
|
|
if json_log["action"] == "processcreate":
|
|
pid = log["processid"]
|
|
ppid = log["parentprocessid"]
|
|
path = log["image"]
|
|
params = log["commandline"]
|
|
user = log["user"]
|
|
hash = log["hashes"].split(",")[0].split("=")[1]
|
|
|
|
parent_pid = log["parentprocessid"]
|
|
parent_ppid = parent_pid
|
|
parent_path = log["parentimage"]
|
|
parent_params = log["parentcommandline"]
|
|
parent_user = log["parentuser"]
|
|
create_time = int(round(time.time() * 1000))
|
|
|
|
if path in process.skip_process_path or path in process.skip_process_path:
|
|
return
|
|
parent_process: process.Process = process.get_process_by_pid(ppid)
|
|
|
|
if hash in process.skip_md5:
|
|
return
|
|
if parent_process is None or parent_path in process.root_process_path:
|
|
# build a process
|
|
parent_process = process.Process(
|
|
parent_pid,
|
|
parent_ppid,
|
|
parent_path,
|
|
parent_params,
|
|
create_time - 1,
|
|
"None",
|
|
parent_user,
|
|
host,
|
|
)
|
|
is_white_list = hash in hash_white_list.g_white_list
|
|
child = process.Process(
|
|
pid, ppid, path, params, create_time, hash, parent_user, host, is_white_list
|
|
)
|
|
parent_process.parent_process = parent_process
|
|
child.parent_process = parent_process
|
|
chain = process.create_chain(parent_process)
|
|
chain.add_process(child, parent_pid)
|
|
current_process = child
|
|
|
|
had_threat, is_ioa, rule_hit_name, score = match_threat(
|
|
current_process, log, LOG_TYPE_PROCESS_CREATE)
|
|
else:
|
|
is_white_list = hash in hash_white_list.g_white_list
|
|
child = process.Process(
|
|
pid, ppid, path, params, create_time, hash, user, host, is_white_list
|
|
)
|
|
child.parent_process = parent_process
|
|
parent_process.chain.add_process(child, ppid)
|
|
current_process = child
|
|
|
|
had_threat, is_ioa, rule_hit_name, score = match_threat(
|
|
current_process, log, LOG_TYPE_PROCESS_CREATE)
|
|
|
|
had_threat_plugin = plugin.dispath_rule_new_process_create(
|
|
host, current_process, raw_log, json_log
|
|
)
|
|
if had_threat == global_vars.THREAT_TYPE_NONE:
|
|
had_threat = had_threat_plugin
|
|
elif json_log["action"] == "processterminal":
|
|
pid = log["processid"]
|
|
current_process = process.get_process_by_pid(pid)
|
|
if current_process is not None:
|
|
plugin.dispath_process_terminal(
|
|
host, current_process, raw_log, json_log)
|
|
current_process.active = False
|
|
current_process.chain.terminate_count += 1
|
|
if current_process.chain.terminate_count >= (
|
|
current_process.chain.active_count - 1
|
|
):
|
|
current_process.chain.active = False
|
|
if current_process.chain.risk_score >= config.MAX_THREAT_SCORE:
|
|
sql.update_threat_log(
|
|
host,
|
|
current_process.chain.risk_score,
|
|
json.dumps(current_process.chain.operationlist),
|
|
json.dumps(current_process.chain.attck_hit_list),
|
|
current_process.chain.hash,
|
|
current_process.chain.get_json(),
|
|
global_vars.THREAT_TYPE_PROCESS,
|
|
True,
|
|
)
|
|
process.g_ProcessChainList.remove(current_process.chain)
|
|
elif "processid" in log:
|
|
current_process = process.get_process_by_pid(log["processid"])
|
|
if current_process is not None:
|
|
log["action"] = json_log["action"]
|
|
had_threat, is_ioa, rule_hit_name, score = match_threat(
|
|
current_process, log, LOG_TYPE_PROCESS_ACTION)
|
|
had_threat_plugin = plugin.dispath_rule_new_process_action(
|
|
host, current_process, raw_log, json_log
|
|
)
|
|
if had_threat == global_vars.THREAT_TYPE_NONE:
|
|
had_threat = had_threat_plugin
|
|
update_process_threat_status(current_process, host, had_threat)
|
|
parent_pid = 0
|
|
target_pid = 0
|
|
self_hash = ""
|
|
target_image_path = ""
|
|
target_hash = ""
|
|
raw_json_log = json.loads(raw_log)
|
|
|
|
if current_process is not None:
|
|
chain_hash = current_process.chain.hash
|
|
parent_pid = current_process.ppid
|
|
if "TargetProcessId" in raw_json_log:
|
|
target_process: process.Process = current_process.chain.find_process_by_pid(
|
|
raw_json_log["TargetProcessId"]
|
|
)
|
|
target_pid = target_process.pid
|
|
target_image_path = target_process.path
|
|
target_hash = target_process.md5
|
|
self_hash = current_process.md5
|
|
# 以后有其他排除需求再优化
|
|
# if json_log['action'] == 'imageload' and (json_log['data']['imageloaded'][len(json_log['data']['imageloaded']) - 4:] == '.exe' or json_log['data']['imageloaded'] in hash_white_list.g_white_dll_load_list):
|
|
# return
|
|
|
|
if json_log['action'] == 'imageload':
|
|
return
|
|
|
|
sql.push_process_raw(
|
|
host,
|
|
raw_json_log,
|
|
rule_hit_name,
|
|
score,
|
|
chain_hash,
|
|
had_threat,
|
|
parent_pid,
|
|
target_pid,
|
|
self_hash,
|
|
target_image_path,
|
|
target_hash,
|
|
params,
|
|
user,
|
|
)
|
|
'''
|
|
for iter in process.g_ProcessChainList:
|
|
item: process.Process = iter
|
|
if item.risk_score >= config.MAX_THREAT_SCORE:
|
|
item.print_process()
|
|
'''
|
|
|
|
|
|
def process_raw_log(raw_logs: list) -> list:
|
|
return_data = []
|
|
process_chain_list = []
|
|
|
|
raw_logs.sort(key=operator.attrgetter("timestamp"))
|
|
|
|
def _get_process_chain(pid, host: str) -> process.ProcessChain:
|
|
for iter in process_chain_list:
|
|
chain_item: process.ProcessChain = iter
|
|
if chain_item.host != host:
|
|
continue
|
|
process_item = chain_item.find_process_by_pid(pid)
|
|
if process_item is not None:
|
|
return chain_item
|
|
return None
|
|
|
|
for log in raw_logs:
|
|
log: sql.raw_process_log = log
|
|
pid = log.pid
|
|
ppid = log.ppid
|
|
path = log.path
|
|
params = log.commandline
|
|
user = log.user
|
|
hash = log.hash
|
|
create_time = log.timestamp
|
|
host = log.host
|
|
current_process: process.Process = None
|
|
if path in process.skip_process_path:
|
|
continue
|
|
if log.action.lower() == "processcreate":
|
|
|
|
chain = _get_process_chain(pid, host)
|
|
if chain is not None:
|
|
parent_process = chain.find_process_by_pid(ppid)
|
|
else:
|
|
parent_process = None
|
|
|
|
if chain is None:
|
|
# build a process chain
|
|
current_process = process.Process(
|
|
pid, ppid, path, params, create_time, hash, user, host
|
|
)
|
|
chain = process.create_chain(current_process)
|
|
process_chain_list.append(chain)
|
|
else:
|
|
current_process = process.Process(
|
|
pid, ppid, path, params, create_time, hash, user, host
|
|
)
|
|
chain.add_process(current_process, ppid)
|
|
elif log.action.lower() == "processterminal":
|
|
chain = _get_process_chain(pid, host)
|
|
if chain is not None:
|
|
current_process = chain.find_process_by_pid(pid)
|
|
current_process.active = False
|
|
current_process.chain.terminate_count += 1
|
|
if (
|
|
current_process.chain.terminate_count
|
|
>= current_process.chain.active_count
|
|
):
|
|
current_process.chain.active = False
|
|
else:
|
|
# 不在指定时段内被创建的进程的结束事件
|
|
continue
|
|
else:
|
|
chain = _get_process_chain(pid, host)
|
|
if chain is None:
|
|
continue
|
|
current_process = chain.find_process_by_pid(pid)
|
|
if current_process is None:
|
|
continue
|
|
|
|
# if current_process is None :
|
|
# breakpoint()
|
|
start_process = current_process.chain.root_process
|
|
start_process_info = {
|
|
"path": start_process.path,
|
|
"hash": start_process.md5,
|
|
"params": start_process.params,
|
|
"user": start_process.user,
|
|
"create_time": start_process.time,
|
|
}
|
|
return_data.append(
|
|
{
|
|
"host": current_process.host,
|
|
"chain_hash": current_process.chain.hash,
|
|
"hit_rule": log.hit,
|
|
"time": log.timestamp,
|
|
"type": log.type,
|
|
"risk_score": log.score,
|
|
"id": log.id,
|
|
"is_end": current_process.chain.active == False,
|
|
"start_process": start_process_info,
|
|
}
|
|
)
|
|
|
|
return return_data
|