Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f11f6445ac | ||
|
|
ac1e01bfec | ||
|
|
dc60b03bcf | ||
|
|
0b85f35184 | ||
|
|
8e94c48e34 | ||
|
|
ff4f16e109 | ||
|
|
6b2eea6c18 | ||
|
|
1885161d67 | ||
|
|
7752d9465d | ||
|
|
f867ebfb33 | ||
|
|
a31398883e | ||
|
|
534443a475 | ||
|
|
c8292cf977 | ||
|
|
0447387079 | ||
|
|
27a22c2074 | ||
|
|
b3c6b5ae3a | ||
|
|
1aece69ad5 | ||
|
|
d6ca9d7273 | ||
|
|
abaaeff5d9 | ||
|
|
6c513aeb04 | ||
|
|
d5b88c7a01 | ||
|
|
011496349a | ||
|
|
e1fb23c112 | ||
|
|
3ddca10161 | ||
|
|
643bd9f103 | ||
|
|
9cda67c636 |
BIN
Image/16.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
Image/17.png
Normal file
|
After Width: | Height: | Size: 117 KiB |
BIN
Image/18.png
Normal file
|
After Width: | Height: | Size: 320 KiB |
BIN
Image/dashboard.png
Normal file
|
After Width: | Height: | Size: 154 KiB |
BIN
Image/dashboard_new.png
Normal file
|
After Width: | Height: | Size: 195 KiB |
BIN
Image/group.png
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 94 KiB |
BIN
Image/wx.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
@@ -1,3 +1,4 @@
|
|||||||
|
import process
|
||||||
import sql
|
import sql
|
||||||
g_white_list = []
|
g_white_list = []
|
||||||
g_white_dll_load_list = [
|
g_white_dll_load_list = [
|
||||||
@@ -24,6 +25,22 @@ g_white_dll_load_list = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def check_in_while_list(process: process.Process):
|
||||||
|
parent_process = process.parent_process
|
||||||
|
is_white = process.is_white or process.chain.root_process.is_white or process.parent_process.is_white
|
||||||
|
if is_white == False:
|
||||||
|
while parent_process:
|
||||||
|
if parent_process is None:
|
||||||
|
break
|
||||||
|
if parent_process.is_white:
|
||||||
|
is_white = True
|
||||||
|
break
|
||||||
|
if parent_process == process.chain.root_process:
|
||||||
|
break
|
||||||
|
parent_process = parent_process.parent_process
|
||||||
|
return is_white
|
||||||
|
|
||||||
|
|
||||||
def add_white_list(path, hash, reason):
|
def add_white_list(path, hash, reason):
|
||||||
global g_white_list
|
global g_white_list
|
||||||
if hash in g_white_list:
|
if hash in g_white_list:
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ LOG_TYPE_PROCESS_ACTION = 2
|
|||||||
|
|
||||||
|
|
||||||
def update_att_ck(process: process.Process, score, hit_name, attck_t_list):
|
def update_att_ck(process: process.Process, score, hit_name, attck_t_list):
|
||||||
if process.is_white or process.chain.root_process.is_white or process.parent_process.is_white:
|
if hash_white_list.check_in_while_list(process):
|
||||||
score = 0
|
score = 0
|
||||||
for t in attck_t_list:
|
for t in attck_t_list:
|
||||||
process.set_attck(score, t, hit_name)
|
process.set_attck(score, t, hit_name)
|
||||||
@@ -24,8 +24,8 @@ def update_att_ck(process: process.Process, score, hit_name, attck_t_list):
|
|||||||
|
|
||||||
def update_threat(process: process.Process, score, rule_hit_name):
|
def update_threat(process: process.Process, score, rule_hit_name):
|
||||||
had_threat = global_vars.THREAT_TYPE_NONE
|
had_threat = global_vars.THREAT_TYPE_NONE
|
||||||
if process.is_white or process.chain.root_process.is_white or process.parent_process.is_white:
|
if hash_white_list.check_in_while_list(process):
|
||||||
return had_threat
|
score = 0
|
||||||
if score > 0:
|
if score > 0:
|
||||||
# 更新命中的规则
|
# 更新命中的规则
|
||||||
process.set_score(score, rule_hit_name)
|
process.set_score(score, rule_hit_name)
|
||||||
@@ -70,6 +70,53 @@ def match_threat(process: process.Process, log, log_type):
|
|||||||
return had_threat, is_ioa, 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):
|
def process_log(host, json_log, raw_log):
|
||||||
log = json_log["data"]
|
log = json_log["data"]
|
||||||
had_threat = global_vars.THREAT_TYPE_NONE
|
had_threat = global_vars.THREAT_TYPE_NONE
|
||||||
@@ -178,51 +225,7 @@ def process_log(host, json_log, raw_log):
|
|||||||
)
|
)
|
||||||
if had_threat == global_vars.THREAT_TYPE_NONE:
|
if had_threat == global_vars.THREAT_TYPE_NONE:
|
||||||
had_threat = had_threat_plugin
|
had_threat = had_threat_plugin
|
||||||
|
update_process_threat_status(current_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,
|
|
||||||
)
|
|
||||||
parent_pid = 0
|
parent_pid = 0
|
||||||
target_pid = 0
|
target_pid = 0
|
||||||
self_hash = ""
|
self_hash = ""
|
||||||
|
|||||||
@@ -97,15 +97,15 @@ def dispath_html_menu():
|
|||||||
plugin_menu = []
|
plugin_menu = []
|
||||||
for index in range(len(global_vars.g_plugs)):
|
for index in range(len(global_vars.g_plugs)):
|
||||||
_, plug_obj = global_vars.g_plugs[index]
|
_, plug_obj = global_vars.g_plugs[index]
|
||||||
if hasattr(plug_obj, "html_menu"):
|
if hasattr(plug_obj, "html_menu"):
|
||||||
plugin_menu.append(plug_obj.html_menu())
|
plugin_menu.append(plug_obj.html_menu())
|
||||||
return plugin_menu
|
return plugin_menu
|
||||||
|
|
||||||
|
|
||||||
def dispath_html_draw(name):
|
def dispath_html_draw(name):
|
||||||
for index in range(len(global_vars.g_plugs)):
|
for index in range(len(global_vars.g_plugs)):
|
||||||
_, plug_obj = global_vars.g_plugs[index]
|
_, plug_obj = global_vars.g_plugs[index]
|
||||||
if hasattr(plug_obj, "html_draw"):
|
if hasattr(plug_obj, "html_draw"):
|
||||||
if plug_obj.rm_plugs_config['html'] == name:
|
if plug_obj.rm_plugs_config['html'] == name:
|
||||||
return plug_obj.html_draw()
|
return plug_obj.html_draw()
|
||||||
return 'Access Denied '
|
return 'Access Denied '
|
||||||
|
|||||||
342
Server/plugins/ioc_opswat/opswat.py
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
import requests
|
||||||
|
import global_vars
|
||||||
|
import process
|
||||||
|
import hash_white_list
|
||||||
|
from threading import Thread
|
||||||
|
# 引入sqlalchemy中相关模块
|
||||||
|
from sqlalchemy import Column, Integer, String
|
||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
import time
|
||||||
|
from sqlalchemy import create_engine, MetaData, Table
|
||||||
|
|
||||||
|
STATUS_CLEAN = -1
|
||||||
|
STATUS_UNK = 0
|
||||||
|
STATUS_VIRUS = 1
|
||||||
|
|
||||||
|
# 自己去https://metadefender.opswat.com/注册一个申请一个免费的api
|
||||||
|
# 我这边的api有每日最大使用限制!!!!!!用的人多了很有可能会被封掉
|
||||||
|
rm_plugs_config = {
|
||||||
|
"enable": True,
|
||||||
|
"author": "huoji",
|
||||||
|
"description": "opswat ioc检测扩展插件",
|
||||||
|
"version": "0.0.1",
|
||||||
|
# !自己去https://metadefender.opswat.com/注册一个申请一个免费的api!
|
||||||
|
# !自己去https://metadefender.opswat.com/注册一个申请一个免费的api!
|
||||||
|
# !自己去https://metadefender.opswat.com/注册一个申请一个免费的api!
|
||||||
|
"apikey": "010d4868aef799750e2828fdf17a4d98",
|
||||||
|
}
|
||||||
|
g_engine = None
|
||||||
|
g_opswat_cache_hashes_table = None
|
||||||
|
g_opswat_cache_hashes_ins = None
|
||||||
|
g_opswat_cache_ip_addr_table = None
|
||||||
|
g_opswat_cache_ip_addr_ins = None
|
||||||
|
g_sql_base = declarative_base()
|
||||||
|
g_check_hashes_list = {}
|
||||||
|
g_check_ip_list = {}
|
||||||
|
|
||||||
|
|
||||||
|
class opswat_cache_hashes(g_sql_base):
|
||||||
|
__tablename__ = "opswat_cache_hashs"
|
||||||
|
# 定义各字段
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
# 主机ip
|
||||||
|
host = Column(String)
|
||||||
|
# 进程路径
|
||||||
|
path = Column(String)
|
||||||
|
# hash
|
||||||
|
hash = Column(String)
|
||||||
|
# 时间戳
|
||||||
|
timestamp = Column(Integer)
|
||||||
|
# 信息 -1绿色 0 未知 1病毒
|
||||||
|
status = Column(Integer)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.id
|
||||||
|
|
||||||
|
|
||||||
|
class opswat_cache_ip_addr(g_sql_base):
|
||||||
|
__tablename__ = "opswat_cache_ip_addr"
|
||||||
|
# 定义各字段
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
# 主机ip
|
||||||
|
host = Column(String)
|
||||||
|
# 进程路径
|
||||||
|
path = Column(String)
|
||||||
|
# ip_addr
|
||||||
|
ip_addr = Column(String)
|
||||||
|
# 时间戳
|
||||||
|
timestamp = Column(Integer)
|
||||||
|
# 信息 -1绿色 0 未知 1病毒
|
||||||
|
status = Column(Integer)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.id
|
||||||
|
|
||||||
|
|
||||||
|
def search_ip_in_opswat(ip_addr):
|
||||||
|
request_obj = requests.Session()
|
||||||
|
request_obj.trust_env = False
|
||||||
|
url = "https://api.metadefender.com/v4/ip/" + ip_addr
|
||||||
|
headers = {
|
||||||
|
"apikey": rm_plugs_config['apikey'],
|
||||||
|
}
|
||||||
|
status = STATUS_UNK
|
||||||
|
try:
|
||||||
|
response = request_obj.get(
|
||||||
|
url, headers=headers, timeout=30, verify=True)
|
||||||
|
if response.status_code == 200:
|
||||||
|
json_data = response.json()
|
||||||
|
if 'lookup_results' in json_data:
|
||||||
|
if json_data['lookup_results']['detected_by'] >= 1:
|
||||||
|
status = STATUS_VIRUS
|
||||||
|
else:
|
||||||
|
status = STATUS_CLEAN
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return status
|
||||||
|
|
||||||
|
|
||||||
|
def search_hash_in_opswat(hash):
|
||||||
|
request_obj = requests.Session()
|
||||||
|
request_obj.trust_env = False
|
||||||
|
url = "https://api.metadefender.com/v4/hash/" + hash
|
||||||
|
headers = {
|
||||||
|
"apikey": rm_plugs_config['apikey'],
|
||||||
|
}
|
||||||
|
status = STATUS_UNK
|
||||||
|
try:
|
||||||
|
response = request_obj.get(
|
||||||
|
url, headers=headers, timeout=30, verify=True)
|
||||||
|
if response.status_code == 200:
|
||||||
|
json_data = response.json()
|
||||||
|
if 'scan_all_result_i' in json_data['scan_results']:
|
||||||
|
if json_data['scan_results']['total_detected_avs'] > 5:
|
||||||
|
status = STATUS_VIRUS
|
||||||
|
else:
|
||||||
|
status = STATUS_CLEAN
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return status
|
||||||
|
|
||||||
|
|
||||||
|
def async_call(fn):
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
Thread(target=fn, args=args, kwargs=kwargs).start()
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def query_hash(pHash):
|
||||||
|
global g_opswat_cache_hashes_table
|
||||||
|
sql_session = sessionmaker(bind=g_engine)
|
||||||
|
hash_info = sql_session().query(
|
||||||
|
g_opswat_cache_hashes_table).filter_by(hash=pHash).first()
|
||||||
|
sql_session().close()
|
||||||
|
if hash_info is None:
|
||||||
|
return False, None
|
||||||
|
last_time = hash_info[4]
|
||||||
|
status = hash_info[5]
|
||||||
|
is_need_update = False
|
||||||
|
# 10 day
|
||||||
|
if time.time() - last_time > 864000:
|
||||||
|
is_need_update = True
|
||||||
|
return is_need_update, status
|
||||||
|
|
||||||
|
|
||||||
|
def query_ipaddr(pIp):
|
||||||
|
global g_opswat_cache_ip_addr_table
|
||||||
|
sql_session = sessionmaker(bind=g_engine)
|
||||||
|
ip_info = sql_session().query(
|
||||||
|
g_opswat_cache_ip_addr_table).filter_by(ip_addr=pIp).first()
|
||||||
|
sql_session().close()
|
||||||
|
if ip_info is None:
|
||||||
|
return False, None
|
||||||
|
last_time = ip_info[4]
|
||||||
|
status = ip_info[5]
|
||||||
|
is_need_update = False
|
||||||
|
# 10 day
|
||||||
|
if time.time() - last_time > 864000:
|
||||||
|
is_need_update = True
|
||||||
|
return is_need_update, status
|
||||||
|
|
||||||
|
|
||||||
|
def update_ip_addr(ip_addr, net_status):
|
||||||
|
global g_opswat_cache_ip_addr_table
|
||||||
|
global g_engine
|
||||||
|
conn = g_engine.connect()
|
||||||
|
update = (
|
||||||
|
g_opswat_cache_ip_addr_table.update()
|
||||||
|
.values(status=net_status,
|
||||||
|
timestamp=int(round(time.time() * 1000)))
|
||||||
|
.where(g_opswat_cache_ip_addr_table.c.ip_addr == ip_addr)
|
||||||
|
)
|
||||||
|
result = conn.execute(update)
|
||||||
|
conn.close()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def update_hash(hash, new_status):
|
||||||
|
global g_opswat_cache_hashes_table
|
||||||
|
global g_engine
|
||||||
|
conn = g_engine.connect()
|
||||||
|
update = (
|
||||||
|
g_opswat_cache_hashes_table.update()
|
||||||
|
.values(
|
||||||
|
status=new_status,
|
||||||
|
timestamp=int(round(time.time() * 1000))
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
g_opswat_cache_hashes_table.columns.hash == hash
|
||||||
|
)
|
||||||
|
)
|
||||||
|
result = conn.execute(update)
|
||||||
|
conn.close()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def push_ip_addr(host, path, ip_addr, status):
|
||||||
|
global g_opswat_cache_ip_addr_table
|
||||||
|
global g_engine
|
||||||
|
conn = g_engine.connect()
|
||||||
|
insert = g_opswat_cache_ip_addr_table.insert().values(
|
||||||
|
host=host,
|
||||||
|
path=path,
|
||||||
|
ip_addr=ip_addr,
|
||||||
|
status=status,
|
||||||
|
timestamp=int(round(time.time() * 1000))
|
||||||
|
)
|
||||||
|
result = conn.execute(insert)
|
||||||
|
conn.close()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def push_hash(
|
||||||
|
host,
|
||||||
|
path,
|
||||||
|
hash,
|
||||||
|
status
|
||||||
|
):
|
||||||
|
global g_engine
|
||||||
|
global g_opswat_cache_hashes_table
|
||||||
|
global g_opswat_cache_hashes_ins
|
||||||
|
ins = g_opswat_cache_hashes_ins.values(
|
||||||
|
host=host,
|
||||||
|
path=path,
|
||||||
|
hash=hash,
|
||||||
|
status=status,
|
||||||
|
timestamp=int(round(time.time() * 1000))
|
||||||
|
)
|
||||||
|
# 连接引擎
|
||||||
|
conn = g_engine.connect()
|
||||||
|
# 执行语句
|
||||||
|
result = conn.execute(ins)
|
||||||
|
conn.close()
|
||||||
|
# print(raw_json)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@async_call
|
||||||
|
def asnyc_check_ip(current_process: process.Process, host, ip):
|
||||||
|
global g_check_ip_list
|
||||||
|
if ip in g_check_ip_list and g_check_ip_list[ip] != -2:
|
||||||
|
return g_check_ip_list[ip]
|
||||||
|
g_check_ip_list[ip] = STATUS_UNK
|
||||||
|
cache_need_update, cache_status = query_ipaddr(ip)
|
||||||
|
if cache_need_update or cache_status is None:
|
||||||
|
create_one = False
|
||||||
|
if cache_status is None:
|
||||||
|
create_one = True
|
||||||
|
cache_status = search_ip_in_opswat(ip)
|
||||||
|
if create_one:
|
||||||
|
push_ip_addr(host, current_process.path, ip, cache_status)
|
||||||
|
else:
|
||||||
|
push_ip_addr(ip, cache_status)
|
||||||
|
|
||||||
|
if cache_status == STATUS_VIRUS:
|
||||||
|
current_process.set_score(666, "恶意网络链接IP:{}".format(ip))
|
||||||
|
elif cache_status == STATUS_UNK:
|
||||||
|
# crowdstrike: 这个我熟
|
||||||
|
current_process.set_score(10, "低信誉ip链接:{}".format(ip))
|
||||||
|
g_check_ip_list[ip] = cache_status
|
||||||
|
|
||||||
|
|
||||||
|
@async_call
|
||||||
|
def asnyc_check_domian(current_process: process.Process, host, domain):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@async_call
|
||||||
|
def asnyc_check_hash(current_process: process.Process, host):
|
||||||
|
global g_check_hashes_list
|
||||||
|
hash = current_process.md5
|
||||||
|
if hash in g_check_hashes_list and g_check_hashes_list[hash] != -2:
|
||||||
|
return g_check_hashes_list[hash]
|
||||||
|
g_check_hashes_list[hash] = STATUS_UNK
|
||||||
|
cache_need_update, cache_status = query_hash(hash)
|
||||||
|
if cache_need_update or cache_status is None:
|
||||||
|
create_one = False
|
||||||
|
if cache_status is None:
|
||||||
|
create_one = True
|
||||||
|
cache_status = search_hash_in_opswat(hash)
|
||||||
|
if create_one:
|
||||||
|
push_hash(host, current_process.path, hash, cache_status)
|
||||||
|
else:
|
||||||
|
update_hash(hash, cache_status)
|
||||||
|
|
||||||
|
if cache_status == STATUS_VIRUS:
|
||||||
|
current_process.set_score(666, "恶意软件")
|
||||||
|
elif cache_status == STATUS_UNK:
|
||||||
|
# crowdstrike: 这个我熟
|
||||||
|
current_process.set_score(10, "低信誉文件")
|
||||||
|
g_check_hashes_list[hash] = cache_status
|
||||||
|
|
||||||
|
|
||||||
|
def rule_new_process_create(current_process: process.Process, host, raw_log_data, json_log_data):
|
||||||
|
global g_check_hashes_list
|
||||||
|
if rm_plugs_config['apikey'] != "" is not None and hash_white_list.check_in_while_list(current_process) == False:
|
||||||
|
g_check_hashes_list[current_process.md5] = -2
|
||||||
|
asnyc_check_hash(current_process, host)
|
||||||
|
return global_vars.THREAT_TYPE_NONE
|
||||||
|
|
||||||
|
|
||||||
|
def rule_new_process_action(current_process: process.Process, host, raw_log_data, json_log_data):
|
||||||
|
global g_check_ip_list
|
||||||
|
if rm_plugs_config['apikey'] != "" is not None and json_log_data['action'] == 'networkconnect' and hash_white_list.check_in_while_list(current_process) == False:
|
||||||
|
# print('network connect{}'.format(
|
||||||
|
# json_log_data['data']['destinationip']))
|
||||||
|
ip_addr = json_log_data['data']['destinationip']
|
||||||
|
if len(ip_addr) >= 5:
|
||||||
|
g_check_ip_list[json_log_data['data']['destinationip']] = -2
|
||||||
|
asnyc_check_ip(current_process, host,
|
||||||
|
json_log_data['data']['destinationip'])
|
||||||
|
return global_vars.THREAT_TYPE_NONE
|
||||||
|
|
||||||
|
|
||||||
|
def rule_init():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def plugin_init():
|
||||||
|
global g_engine
|
||||||
|
global g_metadata
|
||||||
|
global g_sql_base
|
||||||
|
global g_opswat_cache_hashes_table
|
||||||
|
global g_opswat_cache_hashes_ins
|
||||||
|
global g_opswat_cache_ip_addr_table
|
||||||
|
global g_opswat_cache_ip_addr_ins
|
||||||
|
print('opswat ioc检测扩展插件 2022/9/23 by huoji')
|
||||||
|
|
||||||
|
if rm_plugs_config['apikey'] != "":
|
||||||
|
g_engine = create_engine(
|
||||||
|
"sqlite:///plugin_opswat_cache.db?check_same_thread=False", echo=False)
|
||||||
|
g_sql_base.metadata.create_all(g_engine)
|
||||||
|
g_metadata = MetaData(g_engine)
|
||||||
|
g_opswat_cache_hashes_table = Table(
|
||||||
|
"opswat_cache_hashs", g_metadata, autoload=True)
|
||||||
|
g_opswat_cache_hashes_ins = g_opswat_cache_hashes_table.insert()
|
||||||
|
g_opswat_cache_ip_addr_table = Table(
|
||||||
|
"opswat_cache_ip_addr", g_metadata, autoload=True)
|
||||||
|
g_opswat_cache_ip_addr_ins = g_opswat_cache_ip_addr_table.insert()
|
||||||
|
else:
|
||||||
|
print('opswat ioc检测扩展插件未配置apikey,自己去metadefender.opswat.com申请一个!')
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import global_vars
|
import global_vars
|
||||||
import process
|
import process
|
||||||
|
import hash_white_list
|
||||||
rm_plugs_config = {
|
rm_plugs_config = {
|
||||||
"enable": True,
|
"enable": True,
|
||||||
"author": "huoji",
|
"author": "huoji",
|
||||||
@@ -31,7 +31,7 @@ mimikatz_dll_list = [
|
|||||||
|
|
||||||
def rule_new_process_create(current_process: process.Process, host, raw_log_data, json_log_data):
|
def rule_new_process_create(current_process: process.Process, host, raw_log_data, json_log_data):
|
||||||
# 服务端提供了一个 plugin_var 变量用于存放当前进程插件的上下文
|
# 服务端提供了一个 plugin_var 变量用于存放当前进程插件的上下文
|
||||||
if current_process.path != 'c:\\windows\\system32\\wbem\\wmic.exe' and current_process.parent_process.path != 'c:\\windows\\system32\\svchost.exe' and current_process.path != 'c:\\windows\\system32\\svchost.exe':
|
if current_process.path != 'c:\\windows\\system32\\wbem\\wmic.exe' and current_process.parent_process.path != 'c:\\windows\\system32\\svchost.exe' and current_process.path != 'c:\\windows\\system32\\svchost.exe' and hash_white_list.check_in_while_list(current_process) == False:
|
||||||
current_process.plugin_var['mimikatz_matched_num'] = 0
|
current_process.plugin_var['mimikatz_matched_num'] = 0
|
||||||
current_process.plugin_var['mimikatz_detected'] = False
|
current_process.plugin_var['mimikatz_detected'] = False
|
||||||
return global_vars.THREAT_TYPE_NONE
|
return global_vars.THREAT_TYPE_NONE
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import global_vars
|
import global_vars
|
||||||
import process
|
import process
|
||||||
#import yara
|
#import yara
|
||||||
|
import hash_white_list
|
||||||
rm_plugs_config = {
|
rm_plugs_config = {
|
||||||
"enable": True,
|
"enable": True,
|
||||||
"author": "huoji",
|
"author": "huoji",
|
||||||
@@ -26,7 +26,7 @@ def rule_new_process_create(current_process: process.Process, host, raw_log_data
|
|||||||
|
|
||||||
if 'uac_flag' not in current_process.chain.root_process.plugin_var:
|
if 'uac_flag' not in current_process.chain.root_process.plugin_var:
|
||||||
current_process.chain.root_process.plugin_var['uac_flag'] = integritylevel
|
current_process.chain.root_process.plugin_var['uac_flag'] = integritylevel
|
||||||
if integritylevel > current_process.chain.root_process.plugin_var['uac_flag']:
|
if integritylevel > current_process.chain.root_process.plugin_var['uac_flag'] and hash_white_list.check_in_while_list(current_process) == False:
|
||||||
print('[uac bypass detect] detect uac bypass in process chain {}'.format(
|
print('[uac bypass detect] detect uac bypass in process chain {}'.format(
|
||||||
current_process.path))
|
current_process.path))
|
||||||
current_process.chain.root_process.plugin_var['uac_flag'] = integritylevel
|
current_process.chain.root_process.plugin_var['uac_flag'] = integritylevel
|
||||||
|
|||||||
@@ -6,13 +6,6 @@ rule = [
|
|||||||
'attck_hit':['T1562.001'],
|
'attck_hit':['T1562.001'],
|
||||||
'name': 'Impair Defenses: Disable or Modify Tools'
|
'name': 'Impair Defenses: Disable or Modify Tools'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
'rules': [
|
|
||||||
'action == "processaccess" and targetimage =~ ".*lsass.exe"',
|
|
||||||
],
|
|
||||||
'attck_hit':['T1003'],
|
|
||||||
'name': 'OS Credential Dumping: LSASS Memory'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
'rules': [
|
'rules': [
|
||||||
'action == "processaccess" and calltrace =~ ".*unknown.*" and not calltrace =~ ".*conpty\.node.*" and not calltrace =~ ".*java\.dll.*" and not calltrace =~ ".*appvisvsubsystems64\.dll.*" and not calltrace =~ ".*twinui\.dll.*" and not calltrace =~ ".*nativeimages.*" and not targetimage == "c:\\windows\\system32\\cmd.exe"',
|
'action == "processaccess" and calltrace =~ ".*unknown.*" and not calltrace =~ ".*conpty\.node.*" and not calltrace =~ ".*java\.dll.*" and not calltrace =~ ".*appvisvsubsystems64\.dll.*" and not calltrace =~ ".*twinui\.dll.*" and not calltrace =~ ".*nativeimages.*" and not targetimage == "c:\\windows\\system32\\cmd.exe"',
|
||||||
@@ -37,6 +30,7 @@ rule = [
|
|||||||
'action == "createremotethread"',
|
'action == "createremotethread"',
|
||||||
],
|
],
|
||||||
'attck_hit':['T1055'],
|
'attck_hit':['T1055'],
|
||||||
|
'score': 30,
|
||||||
'name': 'Process Injection'
|
'name': 'Process Injection'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
rule = [
|
rule = [
|
||||||
{
|
{
|
||||||
'rules': [
|
'rules': [
|
||||||
'originalfilename =~ ".*taskill.exe.*"',
|
'originalfilename == "taskill.exe"',
|
||||||
'originalfilename =~ ".*net.exe.*" and commandline =~ ".*stop.*"',
|
'originalfilename == "net.exe" and commandline =~ ".*stop.*"',
|
||||||
'originalfilename =~ ".*sc.exe.*" and commandline =~ ".*config.*" and commandline =~ ".*disabled.*"',
|
'originalfilename == "sc.exe" and commandline =~ ".*config.*" and commandline =~ ".*disabled.*"',
|
||||||
],
|
],
|
||||||
'attck_hit':['T1489'],
|
'attck_hit':['T1489'],
|
||||||
'score': 30,
|
'score': 30,
|
||||||
@@ -44,7 +44,7 @@ rule = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'rules': [
|
'rules': [
|
||||||
'originalfilename =~ ".*vssadmin.exe.*" and commandline =~ ".*create.*"',
|
'originalfilename =~ ".*vssadmin.exe" and commandline =~ ".*create.*"',
|
||||||
],
|
],
|
||||||
'attck_hit':['T1003.003'],
|
'attck_hit':['T1003.003'],
|
||||||
'score': 30,
|
'score': 30,
|
||||||
@@ -52,7 +52,7 @@ rule = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'rules': [
|
'rules': [
|
||||||
'originalfilename =~ ".*wbadmin.exe.*" and commandline =~ ".*delete.*"',
|
'originalfilename =~ ".*wbadmin.exe" and commandline =~ ".*delete.*"',
|
||||||
'originalfilename =~ ".*bcdedit.exe" and commandline =~ ".*recoveryenabled.*no.*"',
|
'originalfilename =~ ".*bcdedit.exe" and commandline =~ ".*recoveryenabled.*no.*"',
|
||||||
'originalfilename =~ ".*bcdedit.exe" and commandline =~ ".*bootstatuspolicy.*ignoreallfailures.*"',
|
'originalfilename =~ ".*bcdedit.exe" and commandline =~ ".*bootstatuspolicy.*ignoreallfailures.*"',
|
||||||
'originalfilename =~ ".*wmic.exe" and commandline =~ ".*shadowcopy.*" and commandline =~ ".*delete.*"',
|
'originalfilename =~ ".*wmic.exe" and commandline =~ ".*shadowcopy.*" and commandline =~ ".*delete.*"',
|
||||||
@@ -64,9 +64,9 @@ rule = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'rules': [
|
'rules': [
|
||||||
'originalfilename =~ ".*net.exe.*" and commandline =~ ".*view.*"',
|
'originalfilename == "net.exe" and commandline =~ ".*view.*"',
|
||||||
'originalfilename =~ ".*net.exe.*" and commandline =~ ".*group.*"',
|
'originalfilename == "net.exe" and commandline =~ ".*group.*"',
|
||||||
'originalfilename =~ ".*ping.exe"',
|
'originalfilename == "ping.exe"',
|
||||||
|
|
||||||
],
|
],
|
||||||
'attck_hit':['T1018'],
|
'attck_hit':['T1018'],
|
||||||
@@ -75,7 +75,7 @@ rule = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'rules': [
|
'rules': [
|
||||||
'originalfilename =~ ".*fsutil.exe.*" and commandline =~ ".*deletejournal.*"',
|
'originalfilename =~ ".*fsutil.exe" and commandline =~ ".*deletejournal.*"',
|
||||||
],
|
],
|
||||||
'attck_hit':['T1070.004'],
|
'attck_hit':['T1070.004'],
|
||||||
'score': 10,
|
'score': 10,
|
||||||
@@ -83,11 +83,11 @@ rule = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'rules': [
|
'rules': [
|
||||||
'originalfilename =~ ".*net.exe.*" and commandline =~ ".*user.*"',
|
'originalfilename == ".*net.exe" and commandline =~ ".*user.*"',
|
||||||
'originalfilename =~ ".*whoami.*"',
|
'originalfilename =~ ".*whoami.exe"',
|
||||||
'originalfilename =~ ".*query.exe"',
|
'originalfilename =~ ".*query.exe"',
|
||||||
'originalfilename =~ ".*setspn.exe"',
|
'originalfilename =~ ".*setspn.exe"',
|
||||||
'originalfilename =~ ".*cmdkey.exe.*"'
|
'originalfilename =~ ".*cmdkey.exe"'
|
||||||
],
|
],
|
||||||
'attck_hit':['T1087.001'],
|
'attck_hit':['T1087.001'],
|
||||||
'score': 30,
|
'score': 30,
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
rule = [
|
rule = [
|
||||||
|
{
|
||||||
|
'rules': [
|
||||||
|
'action == "processaccess" and targetimage =~ ".*lsass.exe"',
|
||||||
|
],
|
||||||
|
'attck_hit':['T1003'],
|
||||||
|
'score': 100,
|
||||||
|
'name': 'OS Credential Dumping: LSASS Memory'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'rules': [
|
'rules': [
|
||||||
'action == "processaccess" and targetimage =~ ".*lsass.exe" and grantedaccess & 0x0010 and sourceimage =~ ".*rundll32.exe"',
|
'action == "processaccess" and targetimage =~ ".*lsass.exe" and grantedaccess & 0x0010 and sourceimage =~ ".*rundll32.exe"',
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ def delete_white_list(pHash):
|
|||||||
delete(g_hash_white_list_table).where(
|
delete(g_hash_white_list_table).where(
|
||||||
g_hash_white_list_table.columns.hash == pHash)
|
g_hash_white_list_table.columns.hash == pHash)
|
||||||
)
|
)
|
||||||
|
conn.close()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -159,6 +160,7 @@ def push_white_list(pPath, pHash, pReason):
|
|||||||
conn = g_engine.connect()
|
conn = g_engine.connect()
|
||||||
# 执行语句
|
# 执行语句
|
||||||
result = conn.execute(ins)
|
result = conn.execute(ins)
|
||||||
|
conn.close()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -228,9 +230,29 @@ def push_process_raw(
|
|||||||
conn = g_engine.connect()
|
conn = g_engine.connect()
|
||||||
# 执行语句
|
# 执行语句
|
||||||
result = conn.execute(ins)
|
result = conn.execute(ins)
|
||||||
|
conn.close()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def query_last_raw_process_log(num):
|
||||||
|
global g_rawdata_table
|
||||||
|
sql_session = sessionmaker(bind=g_engine)
|
||||||
|
# 用g_rawdata_table 不行, utf8编码问题?
|
||||||
|
start_time = int(round(time.time() * 1000))
|
||||||
|
end_time = start_time - 1000 * 60 * 60 * 24 * 7
|
||||||
|
raw_log = (
|
||||||
|
sql_session()
|
||||||
|
.query(raw_process_log)
|
||||||
|
# .filter(
|
||||||
|
# raw_process_log.timestamp >= end_time
|
||||||
|
# )
|
||||||
|
.limit(num)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
sql_session().close()
|
||||||
|
return raw_log
|
||||||
|
|
||||||
|
|
||||||
def select_process_raw_log_by_time(start: int, end: int):
|
def select_process_raw_log_by_time(start: int, end: int):
|
||||||
global g_rawdata_table
|
global g_rawdata_table
|
||||||
sql_session = sessionmaker(bind=g_engine)
|
sql_session = sessionmaker(bind=g_engine)
|
||||||
@@ -245,7 +267,6 @@ def select_process_raw_log_by_time(start: int, end: int):
|
|||||||
)
|
)
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
|
|
||||||
sql_session().close()
|
sql_session().close()
|
||||||
return raw_log
|
return raw_log
|
||||||
|
|
||||||
@@ -285,6 +306,7 @@ def update_threat_log(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
result = conn.execute(update)
|
result = conn.execute(update)
|
||||||
|
conn.close()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -298,6 +320,7 @@ def handle_threat_log(threat_id, handle_type):
|
|||||||
.where(g_threat_table.columns.id == int(threat_id))
|
.where(g_threat_table.columns.id == int(threat_id))
|
||||||
)
|
)
|
||||||
result = conn.execute(update)
|
result = conn.execute(update)
|
||||||
|
conn.close()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -309,6 +332,7 @@ def delete_threat(threat_id):
|
|||||||
delete(g_threat_table).where(
|
delete(g_threat_table).where(
|
||||||
g_threat_table.columns.id == int(threat_id))
|
g_threat_table.columns.id == int(threat_id))
|
||||||
)
|
)
|
||||||
|
conn.close()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -320,6 +344,22 @@ def query_one_threat(threat_id):
|
|||||||
return threat
|
return threat
|
||||||
|
|
||||||
|
|
||||||
|
def query_raw_host_log_num(host):
|
||||||
|
global g_rawdata_table
|
||||||
|
sql_session = sessionmaker(bind=g_engine)
|
||||||
|
num = sql_session().query(g_rawdata_table).filter_by(host=host).count()
|
||||||
|
sql_session().close()
|
||||||
|
return num
|
||||||
|
|
||||||
|
|
||||||
|
def query_threat_all_num():
|
||||||
|
global g_threat_table
|
||||||
|
sql_session = sessionmaker(bind=g_engine)
|
||||||
|
threat = sql_session().query(g_threat_table).count()
|
||||||
|
sql_session().close()
|
||||||
|
return threat
|
||||||
|
|
||||||
|
|
||||||
def query_all_threat_log(query_type):
|
def query_all_threat_log(query_type):
|
||||||
global g_threat_table
|
global g_threat_table
|
||||||
sql_session = sessionmaker(bind=g_engine)
|
sql_session = sessionmaker(bind=g_engine)
|
||||||
@@ -396,5 +436,6 @@ def push_threat_log(
|
|||||||
conn = g_engine.connect()
|
conn = g_engine.connect()
|
||||||
# 执行语句
|
# 执行语句
|
||||||
result = conn.execute(ins)
|
result = conn.execute(ins)
|
||||||
|
conn.close()
|
||||||
# print(raw_json)
|
# print(raw_json)
|
||||||
return result
|
return result
|
||||||
|
|||||||
66
Server/statistics.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import time
|
||||||
|
import sql
|
||||||
|
|
||||||
|
all_log_num = 0
|
||||||
|
host_list = {}
|
||||||
|
last_update_time = 0
|
||||||
|
|
||||||
|
|
||||||
|
def get_host_list():
|
||||||
|
global host_list
|
||||||
|
return host_list
|
||||||
|
|
||||||
|
|
||||||
|
def update_host_list(host):
|
||||||
|
global host_list
|
||||||
|
host_list[host] = 1
|
||||||
|
|
||||||
|
|
||||||
|
def update_loged_num(host):
|
||||||
|
global all_log_num
|
||||||
|
global host_list
|
||||||
|
global last_update_time
|
||||||
|
|
||||||
|
all_log_num += 1
|
||||||
|
if host not in host_list:
|
||||||
|
host_list[host] = {
|
||||||
|
'last_update_time': time.time(),
|
||||||
|
'log_num': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
'all_log_num': 0
|
||||||
|
}
|
||||||
|
host_list[host]['all_log_num'] += 1
|
||||||
|
if time.time() - host_list[host]['last_update_time'] > 60:
|
||||||
|
if host_list[host]['all_log_num'] == 0:
|
||||||
|
del host_list[host]
|
||||||
|
host_list[host]['last_update_time'] = time.time()
|
||||||
|
host_list[host]['log_num'].append(host_list[host]['all_log_num'])
|
||||||
|
host_list[host]['all_log_num'] = 0
|
||||||
|
if len(host_list[host]['log_num']) > 10:
|
||||||
|
del host_list[host]['log_num'][0]
|
||||||
|
|
||||||
|
|
||||||
|
def get_loged_num():
|
||||||
|
global all_log_num
|
||||||
|
if all_log_num > 30000000:
|
||||||
|
all_log_num = 0
|
||||||
|
return all_log_num
|
||||||
|
|
||||||
|
|
||||||
|
def get_threat_nums():
|
||||||
|
# sqlite的count啥的还不如自己查出来自己统计
|
||||||
|
host_list = get_host_list()
|
||||||
|
# 懒得做了...
|
||||||
|
# last_logs = sql.query_last_raw_process_log(10)
|
||||||
|
# for iter in last_logs:
|
||||||
|
# print(last_logs)
|
||||||
|
threat_datas = sql.query_all_threat_log(-1)
|
||||||
|
return_data = {"all": len(threat_datas), "confirm": 0,
|
||||||
|
"ingore": 0, "working": 0, "all_log_num": get_loged_num(), "host_list": host_list}
|
||||||
|
for iter in threat_datas:
|
||||||
|
if iter[9] == 1:
|
||||||
|
return_data["confirm"] += 1
|
||||||
|
elif iter[9] == 2:
|
||||||
|
return_data["ingore"] += 1
|
||||||
|
if iter[7] == 0:
|
||||||
|
return_data["working"] += 1
|
||||||
|
return return_data
|
||||||
@@ -1 +1 @@
|
|||||||
.menu-active{background:#f2c037;color:#fff}::-webkit-scrollbar{height:4px;width:5px}::-webkit-scrollbar-thumb{background:#027be3}::-webkit-scrollbar-thumb,::-webkit-scrollbar-track{border-radius:15px;-webkit-box-shadow:inset 0 0 5px #0003}::-webkit-scrollbar-track{background:#ededed}
|
.menu-active{background:#f2c037;color:#fff}::-webkit-scrollbar{height:4px;width:5px}::-webkit-scrollbar-thumb{background:#2f2b30}::-webkit-scrollbar-thumb,::-webkit-scrollbar-track{border-radius:15px;-webkit-box-shadow:inset 0 0 5px #0003}::-webkit-scrollbar-track{background:#ededed}
|
||||||
@@ -1 +1 @@
|
|||||||
<!DOCTYPE html><html><head><title>Duck Sys Eye</title><meta charset=utf-8><meta name=description content=syseye><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width"><link rel=icon type=image/png sizes=128x128 href=icons/favicon-128x128.png><link rel=icon type=image/png sizes=96x96 href=icons/favicon-96x96.png><link rel=icon type=image/png sizes=32x32 href=icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=icons/favicon-16x16.png><link rel=icon type=image/ico href=favicon.ico><script defer src=js/vendor.8b656787.js></script><script defer src=js/app.b7308b45.js></script><link href=css/vendor.5b8581f0.css rel=stylesheet><link href=css/app.31d6cfe0.css rel=stylesheet></head><body><div id=q-app></div></body></html>
|
<!DOCTYPE html><html><head><title>Duck Sys Eye</title><meta charset=utf-8><meta name=description content=syseye><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width"><link rel=icon type=image/png sizes=128x128 href=icons/favicon-128x128.png><link rel=icon type=image/png sizes=96x96 href=icons/favicon-96x96.png><link rel=icon type=image/png sizes=32x32 href=icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=icons/favicon-16x16.png><link rel=icon type=image/ico href=favicon.ico><script defer src=js/vendor.ee689f15.js></script><script defer src=js/app.563fee9e.js></script><link href=css/vendor.5b8581f0.css rel=stylesheet><link href=css/app.31d6cfe0.css rel=stylesheet></head><body><div id=q-app></div></body></html>
|
||||||
@@ -1 +1 @@
|
|||||||
"use strict";(globalThis["webpackChunksyseye"]=globalThis["webpackChunksyseye"]||[]).push([[219],{4219:(a,e,t)=>{t.r(e),t.d(e,{default:()=>_});var n=t(3673),s=t(2323);function o(a,e,t,o,i,l){const r=(0,n.up)("q-td"),p=(0,n.up)("q-btn"),d=(0,n.up)("q-tr"),h=(0,n.up)("q-table");return(0,n.wg)(),(0,n.j4)(h,{class:"q-pa-lg",dense:a.$q.screen.lt.md,title:"白名单列表",columns:a.data_columns,rows:a.data_columns_data,loading:a.loading,pagination:a.pagination,"onUpdate:pagination":e[0]||(e[0]=e=>a.pagination=e),onRequest:a.onRequest},{body:(0,n.w5)((e=>[(0,n.Wm)(d,{props:e},{default:(0,n.w5)((()=>[(0,n.Wm)(r,{key:"path",props:e},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(e.row.path),1)])),_:2},1032,["props"]),(0,n.Wm)(r,{key:"hash",props:e},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(e.row.hash),1)])),_:2},1032,["props"]),(0,n.Wm)(r,{key:"reason",props:e},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(e.row.reason),1)])),_:2},1032,["props"]),(0,n.Wm)(r,{key:"timestamp",props:e},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(a.time_parase(e.row.timestamp)),1)])),_:2},1032,["props"]),(0,n.Wm)(r,{key:"action",props:e},{default:(0,n.w5)((()=>[(0,n.Wm)(p,{color:"red",label:"移除白名单",onClick:t=>a.delete_white_hash(e.row.hash)},null,8,["onClick"])])),_:2},1032,["props"])])),_:2},1032,["props"])])),_:1},8,["dense","columns","rows","loading","pagination","onRequest"])}var i=t(52),l=t.n(i);const r=(0,n.aZ)({name:"WhiteList",data:function(){return{data_columns:[{name:"path",align:"center",label:"路径",field:"path"},{name:"hash",align:"center",label:"hash",field:"hash"},{name:"reason",align:"center",label:"原因",field:"reason"},{name:"timestamp",align:"center",label:"时间",field:"timestamp"},{name:"action",align:"center",label:"操作",field:"steamid"}],data_columns_data:[],loading:!1,pagination:{sortBy:"desc",descending:!1,page:1,rowsPerPage:10,rowsNumber:10}}},mounted(){this.onRequest({pagination:this.pagination,filter:void 0})},methods:{delete_white_hash(a){l().get("/api/v1/del/white_list?hash="+a).then((a=>{this.onRequest({pagination:this.pagination,filter:void 0})}))},time_parase(a){const e=a=>a<10?"0"+a:a,t=new Date(Number(a));console.log("time",a);const n=t.getFullYear(),s=t.getMonth()+1,o=t.getDate(),i=t.getHours(),l=t.getMinutes(),r=t.getSeconds();return n+"-"+e(s)+"-"+e(o)+" "+e(i)+":"+e(l)+":"+e(r)},onRequest(a){this.data_columns_data=[],this.loading=!0;const{page:e}=a.pagination;l().get("/api/v1/query/white_list_all").then((a=>{const t=a.data.result;console.log(t);for(let e=0;e<t.length;e++){const a=t[e];this.data_columns_data.push(a)}this.pagination.page=e,this.pagination.rowsNumber=this.data_columns_data.length,this.pagination.rowsPerPage=this.data_columns_data.length,this.loading=!1}))}}});var p=t(4260),d=t(1779),h=t(8186),g=t(3884),u=t(8240),m=t(7518),c=t.n(m);const w=(0,p.Z)(r,[["render",o]]),_=w;c()(r,"components",{QTable:d.Z,QTr:h.Z,QTd:g.Z,QBtn:u.Z})}}]);
|
"use strict";(globalThis["webpackChunksyseye"]=globalThis["webpackChunksyseye"]||[]).push([[219],{4219:(a,e,t)=>{t.r(e),t.d(e,{default:()=>_});var n=t(3673),s=t(2323);function o(a,e,t,o,i,l){const r=(0,n.up)("q-td"),p=(0,n.up)("q-btn"),d=(0,n.up)("q-tr"),h=(0,n.up)("q-table");return(0,n.wg)(),(0,n.j4)(h,{class:"q-pa-lg",dense:a.$q.screen.lt.md,title:"白名单列表",columns:a.data_columns,rows:a.data_columns_data,loading:a.loading,pagination:a.pagination,"onUpdate:pagination":e[0]||(e[0]=e=>a.pagination=e),onRequest:a.onRequest},{body:(0,n.w5)((e=>[(0,n.Wm)(d,{props:e},{default:(0,n.w5)((()=>[(0,n.Wm)(r,{key:"path",props:e},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(e.row.path),1)])),_:2},1032,["props"]),(0,n.Wm)(r,{key:"hash",props:e},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(e.row.hash),1)])),_:2},1032,["props"]),(0,n.Wm)(r,{key:"reason",props:e},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(e.row.reason),1)])),_:2},1032,["props"]),(0,n.Wm)(r,{key:"timestamp",props:e},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(a.time_parase(e.row.timestamp)),1)])),_:2},1032,["props"]),(0,n.Wm)(r,{key:"action",props:e},{default:(0,n.w5)((()=>[(0,n.Wm)(p,{color:"red",label:"移除白名单",onClick:t=>a.delete_white_hash(e.row.hash)},null,8,["onClick"])])),_:2},1032,["props"])])),_:2},1032,["props"])])),_:1},8,["dense","columns","rows","loading","pagination","onRequest"])}var i=t(52),l=t.n(i);const r=(0,n.aZ)({name:"WhiteList",data:function(){return{data_columns:[{name:"path",align:"center",label:"路径",field:"path"},{name:"hash",align:"center",label:"hash",field:"hash"},{name:"reason",align:"center",label:"原因",field:"reason"},{name:"timestamp",align:"center",label:"时间",field:"timestamp"},{name:"action",align:"center",label:"操作",field:"steamid"}],data_columns_data:[],loading:!1,pagination:{sortBy:"desc",descending:!1,page:1,rowsPerPage:10,rowsNumber:10}}},mounted(){this.onRequest({pagination:this.pagination,filter:void 0})},methods:{delete_white_hash(a){l().get("/api/v1/del/white_list?hash="+a).then((a=>{this.onRequest({pagination:this.pagination,filter:void 0})}))},time_parase(a){const e=a=>a<10?"0"+a:a,t=new Date(Number(a));console.log("time",a);const n=t.getFullYear(),s=t.getMonth()+1,o=t.getDate(),i=t.getHours(),l=t.getMinutes(),r=t.getSeconds();return n+"-"+e(s)+"-"+e(o)+" "+e(i)+":"+e(l)+":"+e(r)},onRequest(a){this.data_columns_data=[],this.loading=!0;const{page:e}=a.pagination;l().get("/api/v1/query/white_list_all").then((a=>{const t=a.data.result;console.log(t);for(let e=0;e<t.length;e++){const a=t[e];this.data_columns_data.push(a)}this.pagination.page=e,this.pagination.rowsNumber=this.data_columns_data.length,this.pagination.rowsPerPage=this.data_columns_data.length,this.loading=!1}))}}});var p=t(4260),d=t(7898),h=t(8186),g=t(3884),u=t(8240),m=t(7518),c=t.n(m);const w=(0,p.Z)(r,[["render",o]]),_=w;c()(r,"components",{QTable:d.Z,QTr:h.Z,QTd:g.Z,QBtn:u.Z})}}]);
|
||||||
1
Server/templates/js/550.c577ffe7.js
Normal file
BIN
Server/templates/js/550.c577ffe7.js.gz
Normal file
1
Server/templates/js/773.945120ec.js
Normal file
@@ -1 +0,0 @@
|
|||||||
"use strict";(globalThis["webpackChunksyseye"]=globalThis["webpackChunksyseye"]||[]).push([[904],{6904:(s,a,e)=>{e.r(a),e.d(a,{default:()=>h});var r=e(3673);const n={class:"row q-gutter-md q-mb-sm q-pa-lg"};function t(s,a,e,t,c,o){return(0,r.wg)(),(0,r.iD)("h4",n,"施工中....")}const c=(0,r.aZ)({name:"Dashboard"});var o=e(4260);const u=(0,o.Z)(c,[["render",t]]),h=u}}]);
|
|
||||||
1
Server/templates/js/95.8b297ab2.js
Normal file
1
Server/templates/js/app.563fee9e.js
Normal file
32
Server/templates/js/vendor.ee689f15.js
Normal file
BIN
Server/templates/js/vendor.ee689f15.js.gz
Normal file
@@ -1,16 +1,16 @@
|
|||||||
|
import logging
|
||||||
import hash_white_list
|
import hash_white_list
|
||||||
import json
|
import json
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask import request
|
from flask import request
|
||||||
import sql
|
import sql
|
||||||
import log
|
import log
|
||||||
import rule
|
|
||||||
import config
|
import config
|
||||||
from flask import Flask, render_template, request
|
from flask import Flask, render_template, request
|
||||||
import plugin
|
import plugin
|
||||||
import logging
|
|
||||||
import html
|
import html
|
||||||
|
import rule
|
||||||
|
import statistics
|
||||||
app = Flask(
|
app = Flask(
|
||||||
__name__,
|
__name__,
|
||||||
template_folder="./templates",
|
template_folder="./templates",
|
||||||
@@ -53,18 +53,7 @@ def plugin_menu():
|
|||||||
def threat_statistics():
|
def threat_statistics():
|
||||||
if request.remote_addr not in config.ALLOW_ACCESS_IP:
|
if request.remote_addr not in config.ALLOW_ACCESS_IP:
|
||||||
return "Access Denied"
|
return "Access Denied"
|
||||||
# sqlite的count啥的还不如自己查出来自己统计
|
return {"data": statistics.get_threat_nums()}
|
||||||
threat_datas = sql.query_all_threat_log(-1)
|
|
||||||
return_data = {"all": len(threat_datas), "confirm": 0,
|
|
||||||
"ingore": 0, "working": 0}
|
|
||||||
for iter in threat_datas:
|
|
||||||
if iter[9] == 1:
|
|
||||||
return_data["confirm"] += 1
|
|
||||||
elif iter[9] == 2:
|
|
||||||
return_data["ingore"] += 1
|
|
||||||
if iter[7] == 0:
|
|
||||||
return_data["working"] += 1
|
|
||||||
return {"data": return_data}
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/v1/query/white_list_all", methods=["GET"])
|
@app.route("/api/v1/query/white_list_all", methods=["GET"])
|
||||||
@@ -196,11 +185,12 @@ def process():
|
|||||||
# 转小写
|
# 转小写
|
||||||
host = request.remote_addr
|
host = request.remote_addr
|
||||||
log.process_log(host, json.loads(body_data.lower()), body_data)
|
log.process_log(host, json.loads(body_data.lower()), body_data)
|
||||||
|
statistics.update_loged_num(host)
|
||||||
|
|
||||||
return {"status": "success"}
|
return {"status": "success"}
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/v1/log_hunt", methods=["POST"])
|
@ app.route("/api/v1/log_hunt", methods=["POST"])
|
||||||
def log_rescan():
|
def log_rescan():
|
||||||
if request.remote_addr not in config.ALLOW_ACCESS_IP:
|
if request.remote_addr not in config.ALLOW_ACCESS_IP:
|
||||||
return "Access Denied"
|
return "Access Denied"
|
||||||
@@ -223,4 +213,5 @@ if __name__ == "__main__":
|
|||||||
flask_log.setLevel(logging.ERROR)
|
flask_log.setLevel(logging.ERROR)
|
||||||
print("注意,你正在使用测试版,请随时关注github以获取最新版本:")
|
print("注意,你正在使用测试版,请随时关注github以获取最新版本:")
|
||||||
print("https://github.com/RoomaSec/RmEye")
|
print("https://github.com/RoomaSec/RmEye")
|
||||||
|
# statistics.get_threat_nums()
|
||||||
app.run(debug=True, host="0.0.0.0")
|
app.run(debug=True, host="0.0.0.0")
|
||||||
|
|||||||
5
Web/syseye/package-lock.json
generated
@@ -5349,6 +5349,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"js-base64": {
|
||||||
|
"version": "3.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.2.tgz",
|
||||||
|
"integrity": "sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ=="
|
||||||
|
},
|
||||||
"js-tokens": {
|
"js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"echarts": "^5.3.3",
|
"echarts": "^5.3.3",
|
||||||
|
"js-base64": "^3.7.2",
|
||||||
"quasar": "^2.0.0",
|
"quasar": "^2.0.0",
|
||||||
"vue": "^3.0.0",
|
"vue": "^3.0.0",
|
||||||
"vue-router": "^4.0.0"
|
"vue-router": "^4.0.0"
|
||||||
|
|||||||
117
Web/syseye/src/assets/b64.js
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/* eslint-disable camelcase */
|
||||||
|
/* eslint-disable eqeqeq */
|
||||||
|
/* eslint-disable no-useless-escape */
|
||||||
|
// 1.加密解密方法使用:
|
||||||
|
|
||||||
|
// 1.加密
|
||||||
|
// var str = '124中文内容';
|
||||||
|
// var base = new Base64();
|
||||||
|
// var result = base.encode(str);
|
||||||
|
// //document.write(result);
|
||||||
|
|
||||||
|
// //2.解密
|
||||||
|
// var result2 = base.decode(result);
|
||||||
|
// document.write(result2);
|
||||||
|
// //2.加密、解密算法封装:
|
||||||
|
|
||||||
|
function Base64 () {
|
||||||
|
// private property
|
||||||
|
const _keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
|
||||||
|
|
||||||
|
// public method for encoding
|
||||||
|
this.encode = function (input) {
|
||||||
|
let output = ''
|
||||||
|
let chr1, chr2, chr3, enc1, enc2, enc3, enc4
|
||||||
|
let i = 0
|
||||||
|
input = _utf8_encode(input)
|
||||||
|
while (i < input.length) {
|
||||||
|
chr1 = input.charCodeAt(i++)
|
||||||
|
chr2 = input.charCodeAt(i++)
|
||||||
|
chr3 = input.charCodeAt(i++)
|
||||||
|
enc1 = chr1 >> 2
|
||||||
|
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4)
|
||||||
|
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6)
|
||||||
|
enc4 = chr3 & 63
|
||||||
|
if (isNaN(chr2)) {
|
||||||
|
enc3 = enc4 = 64
|
||||||
|
} else if (isNaN(chr3)) {
|
||||||
|
enc4 = 64
|
||||||
|
}
|
||||||
|
output = output +
|
||||||
|
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
|
||||||
|
_keyStr.charAt(enc3) + _keyStr.charAt(enc4)
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
// public method for decoding
|
||||||
|
this.decode = function (input) {
|
||||||
|
let output = ''
|
||||||
|
let chr1, chr2, chr3
|
||||||
|
let enc1, enc2, enc3, enc4
|
||||||
|
let i = 0
|
||||||
|
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '')
|
||||||
|
while (i < input.length) {
|
||||||
|
enc1 = _keyStr.indexOf(input.charAt(i++))
|
||||||
|
enc2 = _keyStr.indexOf(input.charAt(i++))
|
||||||
|
enc3 = _keyStr.indexOf(input.charAt(i++))
|
||||||
|
enc4 = _keyStr.indexOf(input.charAt(i++))
|
||||||
|
chr1 = (enc1 << 2) | (enc2 >> 4)
|
||||||
|
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2)
|
||||||
|
chr3 = ((enc3 & 3) << 6) | enc4
|
||||||
|
output = output + String.fromCharCode(chr1)
|
||||||
|
if (enc3 != 64) {
|
||||||
|
output = output + String.fromCharCode(chr2)
|
||||||
|
}
|
||||||
|
if (enc4 != 64) {
|
||||||
|
output = output + String.fromCharCode(chr3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output = _utf8_decode(output)
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
// private method for UTF-8 encoding
|
||||||
|
var _utf8_encode = function (string) {
|
||||||
|
string = string.replace(/\r\n/g, '\n')
|
||||||
|
let utftext = ''
|
||||||
|
for (let n = 0; n < string.length; n++) {
|
||||||
|
const c = string.charCodeAt(n)
|
||||||
|
if (c < 128) {
|
||||||
|
utftext += String.fromCharCode(c)
|
||||||
|
} else if ((c > 127) && (c < 2048)) {
|
||||||
|
utftext += String.fromCharCode((c >> 6) | 192)
|
||||||
|
utftext += String.fromCharCode((c & 63) | 128)
|
||||||
|
} else {
|
||||||
|
utftext += String.fromCharCode((c >> 12) | 224)
|
||||||
|
utftext += String.fromCharCode(((c >> 6) & 63) | 128)
|
||||||
|
utftext += String.fromCharCode((c & 63) | 128)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return utftext
|
||||||
|
}
|
||||||
|
// private method for UTF-8 decoding
|
||||||
|
var _utf8_decode = function (utftext) {
|
||||||
|
let string = ''
|
||||||
|
let i = 0
|
||||||
|
let c = 0, c1 = 0, c2 = 0
|
||||||
|
while (i < utftext.length) {
|
||||||
|
c = utftext.charCodeAt(i)
|
||||||
|
if (c < 128) {
|
||||||
|
string += String.fromCharCode(c)
|
||||||
|
i++
|
||||||
|
} else if ((c > 191) && (c < 224)) {
|
||||||
|
c2 = utftext.charCodeAt(i + 1)
|
||||||
|
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63))
|
||||||
|
i += 2
|
||||||
|
} else {
|
||||||
|
c2 = utftext.charCodeAt(i + 1)
|
||||||
|
c1 = utftext.charCodeAt(i + 2)
|
||||||
|
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c1 & 63))
|
||||||
|
i += 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default Base64
|
||||||
0
Web/syseye/src/css/light.css
Normal file
@@ -1,118 +1,56 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-layout view="lHh Lpr lFf" style="background-color: rgb(239, 243, 246)">
|
<q-layout view="lHh Lpr lFf" :style="`background-color: ${colors.background}`">
|
||||||
<q-header elevated height-hint="98">
|
<q-header elevated height-hint="98">
|
||||||
<q-toolbar class="text-primary bg-white">
|
<q-toolbar class="text-white" :style="`background-color: ${colors.toolbar}`">
|
||||||
<q-toolbar-title> RmEye内部测试版本v0.0.0.1 </q-toolbar-title>
|
<q-toolbar-title> RmEye测试版v1.0.1.3 </q-toolbar-title>
|
||||||
<q-btn flat round dense icon="more_vert"></q-btn>
|
<q-btn flat dense icon="restore" label="重置颜色" @click="cleanUpCookie">
|
||||||
</q-toolbar>
|
</q-btn>
|
||||||
|
<q-popup-proxy>
|
||||||
|
<q-banner>
|
||||||
|
<q-color v-model="colors.toolbar" @change="updateCookie(colors.toolbar)" class="my-picker" />
|
||||||
|
</q-banner>
|
||||||
|
</q-popup-proxy>
|
||||||
|
</q-toolbar>
|
||||||
|
<q-toolbar :style="`font-size: 16px;background-color: ${colors.layout}`">
|
||||||
|
<q-breadcrumbs active-color="white">
|
||||||
|
<q-breadcrumbs-el label="仪表盘" icon="dashboard" to="/page/dashboard" />
|
||||||
|
<q-breadcrumbs-el label="未处理威胁列表" icon="report" to="#" @click="routerToThreatList(0);" />
|
||||||
|
<q-breadcrumbs-el label="已处理威胁列表" icon="done" to="#" @click="routerToThreatList(1);" />
|
||||||
|
<q-breadcrumbs-el label="已忽略威胁列表" icon="texture" to="#" @click="routerToThreatList(2);" />
|
||||||
|
<q-breadcrumbs-el label="白名单列表" icon="list" to="#" @click="routerToWhiteList();" />
|
||||||
|
</q-breadcrumbs>
|
||||||
|
|
||||||
|
<q-popup-proxy>
|
||||||
|
<q-banner>
|
||||||
|
<q-color v-model="colors.layout" @change="updateCookie(colors.layout)" class="my-picker" />
|
||||||
|
</q-banner>
|
||||||
|
</q-popup-proxy>
|
||||||
|
</q-toolbar>
|
||||||
</q-header>
|
</q-header>
|
||||||
<q-drawer
|
|
||||||
show-if-above
|
|
||||||
:mini="miniState"
|
|
||||||
@mouseover="miniState = false"
|
|
||||||
@mouseout="miniState = true"
|
|
||||||
:width="200"
|
|
||||||
:breakpoint="500"
|
|
||||||
bordered
|
|
||||||
class="bg-white text-primary"
|
|
||||||
>
|
|
||||||
<q-scroll-area class="fit">
|
|
||||||
<q-list padding>
|
|
||||||
<q-item
|
|
||||||
:active="selectLabel == 'dashboard'"
|
|
||||||
clickable
|
|
||||||
v-ripple
|
|
||||||
active-class="menu-active"
|
|
||||||
@click="selectLabel = 'dashboard'"
|
|
||||||
to="/page/dashboard"
|
|
||||||
>
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="dashboard" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section> 仪表盘 </q-item-section>
|
|
||||||
</q-item>
|
|
||||||
|
|
||||||
<q-item
|
|
||||||
:active="selectLabel == 'non_hanlde_report'"
|
|
||||||
clickable
|
|
||||||
v-ripple
|
|
||||||
active-class="menu-active"
|
|
||||||
@click="
|
|
||||||
selectLabel = 'non_hanlde_report';
|
|
||||||
routerToThreatList(0);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="report" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section> 未处理威胁列表 </q-item-section>
|
|
||||||
</q-item>
|
|
||||||
<q-item
|
|
||||||
:active="selectLabel == 'handle_report'"
|
|
||||||
clickable
|
|
||||||
v-ripple
|
|
||||||
active-class="menu-active"
|
|
||||||
@click="
|
|
||||||
selectLabel = 'handle_report';
|
|
||||||
routerToThreatList(1);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="done" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section> 已处理威胁列表 </q-item-section>
|
|
||||||
</q-item>
|
|
||||||
<q-item
|
|
||||||
:active="selectLabel == 'ingore_report'"
|
|
||||||
clickable
|
|
||||||
v-ripple
|
|
||||||
active-class="menu-active"
|
|
||||||
@click="
|
|
||||||
selectLabel = 'ingore_report';
|
|
||||||
routerToThreatList(2);
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="texture" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section> 已忽略威胁列表 </q-item-section>
|
|
||||||
</q-item>
|
|
||||||
<q-item
|
|
||||||
:active="selectLabel == 'white_list'"
|
|
||||||
clickable
|
|
||||||
v-ripple
|
|
||||||
active-class="menu-active"
|
|
||||||
@click="
|
|
||||||
selectLabel = 'white_list';
|
|
||||||
routerToWhiteList();
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="list" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section> 白名单列表 </q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</q-scroll-area>
|
|
||||||
</q-drawer>
|
|
||||||
|
|
||||||
<template v-if="isInPlugin == false">
|
<template v-if="isInPlugin == false">
|
||||||
<q-page-container>
|
<q-page-container>
|
||||||
<router-view />
|
<router-view />
|
||||||
</q-page-container>
|
</q-page-container>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="isInPlugin">
|
<template v-if="isInPlugin">
|
||||||
<div class="q-gutter-md q-mb-sm q-pa-lg">
|
<div class="q-gutter-md q-mb-sm q-pa-lg">
|
||||||
<HtmlPanel v-model:url="PluginUrl" />
|
<HtmlPanel v-model:url="PluginUrl" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</q-layout>
|
</q-layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from 'vue'
|
import Base64 from '../assets/b64.js'
|
||||||
|
|
||||||
|
import {
|
||||||
|
defineComponent
|
||||||
|
} from 'vue'
|
||||||
import HtmlPanel from '../components/Html.vue' // 根据实际路径导入
|
import HtmlPanel from '../components/Html.vue' // 根据实际路径导入
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import {
|
||||||
|
Cookies
|
||||||
|
} from 'quasar'
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
HtmlPanel
|
HtmlPanel
|
||||||
@@ -123,15 +61,31 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
selectLabel: 'non_hanlde_report',
|
selectLabel: 'dashboard',
|
||||||
drawer: false,
|
drawer: false,
|
||||||
miniState: true,
|
miniState: true,
|
||||||
plugin: [],
|
plugin: [],
|
||||||
isInPlugin: false,
|
isInPlugin: false,
|
||||||
PluginUrl: ''
|
PluginUrl: '',
|
||||||
|
colors: {
|
||||||
|
layout: 'rgb(47,43,48)',
|
||||||
|
toolbar: 'rgb(210,61,42)',
|
||||||
|
background: 'rgb(239, 243, 246)'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
updateCookie (selectItem) {
|
||||||
|
const b64Obj = new Base64()
|
||||||
|
Cookies.set('custom_banner', b64Obj.encode(JSON.stringify(this.colors)))
|
||||||
|
},
|
||||||
|
cleanUpCookie () {
|
||||||
|
Cookies.remove('custom_threat_item')
|
||||||
|
Cookies.remove('custom_banner')
|
||||||
|
|
||||||
|
// refesh
|
||||||
|
window.location.reload()
|
||||||
|
},
|
||||||
routerToWhiteList () {
|
routerToWhiteList () {
|
||||||
this.isInPlugin = false
|
this.isInPlugin = false
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
@@ -164,6 +118,11 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.getPluginsMenu()
|
this.getPluginsMenu()
|
||||||
|
const coockieCustomBanner = Cookies.get('custom_banner')
|
||||||
|
if (coockieCustomBanner) {
|
||||||
|
const b64Obj = new Base64()
|
||||||
|
this.colors = JSON.parse(b64Obj.decode(coockieCustomBanner))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -185,7 +144,7 @@ export default defineComponent({
|
|||||||
/*滚动条里面小方块*/
|
/*滚动条里面小方块*/
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
|
-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
|
||||||
background: #027be3;
|
background: rgb(47,43,48);
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
::-webkit-scrollbar-track {
|
||||||
|
|||||||
@@ -1,10 +1,220 @@
|
|||||||
<template>
|
<template>
|
||||||
<h4 class="row q-gutter-md q-mb-sm q-pa-lg">施工中....</h4>
|
<div class="q-gutter-md q-mb-sm q-pa-lg">
|
||||||
</template>
|
<div>
|
||||||
<script>
|
<q-card class="bg-transparent no-shadow no-border">
|
||||||
import { defineComponent } from 'vue'
|
<q-card-section class="q-pa-none">
|
||||||
|
<div class="row q-col-gutter-sm">
|
||||||
|
<div v-for="(item, index) in Threatitems" :key="index" class="col-md-3 col-sm-12 col-xs-12">
|
||||||
|
<q-item :style="`background-color: ${item.color1}`" class="q-pa-none">
|
||||||
|
<q-item-section side :style="`background-color: ${item.color2}`" class="q-pa-lg q-mr-none text-white">
|
||||||
|
<q-icon :name="item.icon" color="white" size="24px"></q-icon>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section class="q-pa-md q-ml-none text-white">
|
||||||
|
<q-item-label class="text-white text-h6 text-weight-bolder">{{
|
||||||
|
item.value
|
||||||
|
}}</q-item-label>
|
||||||
|
<q-item-label>{{ item.title }}</q-item-label>
|
||||||
|
<q-popup-proxy>
|
||||||
|
<q-banner>
|
||||||
|
<q-color v-model="item.color1" @change="updateCookie(Threatitems[index].color1)" class="my-picker" />
|
||||||
|
</q-banner>
|
||||||
|
</q-popup-proxy>
|
||||||
|
</q-item-section>
|
||||||
|
<q-popup-proxy>
|
||||||
|
<q-banner>
|
||||||
|
<q-color v-model="item.color2" @change="updateCookie(Threatitems[index].color2)" class="my-picker" />
|
||||||
|
</q-banner>
|
||||||
|
</q-popup-proxy>
|
||||||
|
</q-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
<q-card class="no-shadow" style="background: rbg(255,255,255)">
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h6">
|
||||||
|
主机数量: {{threatStatistics.host_num}}/50 <q-icon name="info" class="text-brown cursor-pointer">
|
||||||
|
<q-popup-proxy transition-show="flip-up" transition-hide="flip-down">
|
||||||
|
<q-banner class="bg-brown text-white">
|
||||||
|
<template v-slot:avatar>
|
||||||
|
<q-icon name="lightbulb" />
|
||||||
|
</template>
|
||||||
|
由于python+sqlite数据库作为后端,理论上最高支持的主机数量为50.
|
||||||
|
</q-banner>
|
||||||
|
</q-popup-proxy>
|
||||||
|
</q-icon>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="text-subtitle2">最近日志数量: {{threatStatistics.all_log_num}}</div>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-section class="q-pt-none">
|
||||||
|
<div ref="main_draw" style="width: 100%; height: 600px; ">
|
||||||
|
1
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Base64 from '../assets/b64.js'
|
||||||
|
|
||||||
|
import {
|
||||||
|
defineComponent
|
||||||
|
} from 'vue'
|
||||||
|
import axios from 'axios'
|
||||||
|
import {
|
||||||
|
Cookies
|
||||||
|
} from 'quasar'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Dashboard'
|
name: 'Dashboard',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
Threatitems: [{
|
||||||
|
title: '发现的威胁',
|
||||||
|
icon: 'remove_red_eye',
|
||||||
|
value: '200',
|
||||||
|
color1: '#EE9B00',
|
||||||
|
color2: '#EE9B00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '确认的威胁',
|
||||||
|
icon: 'flash_on',
|
||||||
|
value: '500',
|
||||||
|
color1: '#CA6702',
|
||||||
|
color2: '#CA6702'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '忽略的威胁',
|
||||||
|
icon: 'add_moderator',
|
||||||
|
value: '50',
|
||||||
|
color1: '#BB3E03',
|
||||||
|
color2: '#BB3E03'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '进行中的威胁',
|
||||||
|
icon: 'stream',
|
||||||
|
value: '1020',
|
||||||
|
color1: '#AE2012',
|
||||||
|
color2: '#AE2012'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
threatStatistics: {
|
||||||
|
all: 1,
|
||||||
|
confirm: 0,
|
||||||
|
ingore: 1,
|
||||||
|
working: 0,
|
||||||
|
host_list: {},
|
||||||
|
host_num: 10,
|
||||||
|
all_log_num: 647
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateCookie (selectItem) {
|
||||||
|
const b64Obj = new Base64()
|
||||||
|
Cookies.set('custom_threat_item', b64Obj.encode(JSON.stringify(this.Threatitems)))
|
||||||
|
},
|
||||||
|
get_threatStatistics () {
|
||||||
|
axios
|
||||||
|
.get('/api/v1/get/threat_statistics', {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
const data = response.data
|
||||||
|
if (data.data) {
|
||||||
|
this.threatStatistics = data.data
|
||||||
|
this.threatStatistics.host_num = Object.keys(this.threatStatistics.host_list).length
|
||||||
|
// Threatitems
|
||||||
|
this.Threatitems[0].value = this.threatStatistics.all
|
||||||
|
this.Threatitems[1].value = this.threatStatistics.confirm
|
||||||
|
this.Threatitems[2].value = this.threatStatistics.ingore
|
||||||
|
this.Threatitems[3].value = this.threatStatistics.working
|
||||||
|
console.log(this.threatStatistics)
|
||||||
|
|
||||||
|
this.draw()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
draw () {
|
||||||
|
const hostList = []
|
||||||
|
const hostLoggedNumList = []
|
||||||
|
for (const key in this.threatStatistics.host_list) {
|
||||||
|
hostList.push(key)
|
||||||
|
hostLoggedNumList.push({
|
||||||
|
itemStyle: {
|
||||||
|
color: '#005F73'
|
||||||
|
},
|
||||||
|
name: key,
|
||||||
|
type: 'line',
|
||||||
|
stack: 'Total',
|
||||||
|
areaStyle: {},
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series'
|
||||||
|
},
|
||||||
|
data: this.threatStatistics.host_list[key].log_num
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const dom = this.$refs.main_draw
|
||||||
|
const myChart = echarts.init(dom)
|
||||||
|
const option = {
|
||||||
|
title: {
|
||||||
|
text: '最近十分钟日志量'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'cross',
|
||||||
|
label: {
|
||||||
|
backgroundColor: '#6a7985'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: hostList
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
feature: {
|
||||||
|
saveAsImage: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '3%',
|
||||||
|
right: '4%',
|
||||||
|
bottom: '3%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: [{
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: ['10min', '9min', '8min', '7min', '6min', '5min', '4min', '3min', '2min', '1min']
|
||||||
|
}],
|
||||||
|
yAxis: [{
|
||||||
|
type: 'value'
|
||||||
|
}],
|
||||||
|
series: hostLoggedNumList
|
||||||
|
}
|
||||||
|
myChart.setOption(option)
|
||||||
|
setTimeout(() => {
|
||||||
|
myChart.resize()
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.get_threatStatistics()
|
||||||
|
setInterval(() => {
|
||||||
|
this.get_threatStatistics()
|
||||||
|
}, 10000)
|
||||||
|
const cookieCustomThreatItem = Cookies.get('custom_threat_item')
|
||||||
|
if (cookieCustomThreatItem) {
|
||||||
|
const b64Obj = new Base64()
|
||||||
|
|
||||||
|
this.Threatitems = JSON.parse(b64Obj.decode(cookieCustomThreatItem))
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,26 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="q-gutter-md q-mb-sm q-pa-lg">
|
|
||||||
<q-card class="bg-transparent no-shadow no-border">
|
|
||||||
<q-card-section class="q-pa-none">
|
|
||||||
<div class="row q-col-gutter-sm">
|
|
||||||
<div v-for="(item, index) in Threatitems" :key="index" class="col-md-3 col-sm-12 col-xs-12">
|
|
||||||
<q-item :style="`background-color: ${item.color1}`" class="q-pa-none">
|
|
||||||
<q-item-section side :style="`background-color: ${item.color2}`" class="q-pa-lg q-mr-none text-white">
|
|
||||||
<q-icon :name="item.icon" color="white" size="24px"></q-icon>
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section class="q-pa-md q-ml-none text-white">
|
|
||||||
<q-item-label class="text-white text-h6 text-weight-bolder">{{
|
|
||||||
item.value
|
|
||||||
}}</q-item-label>
|
|
||||||
<q-item-label>{{ item.title }}</q-item-label>
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col"></div>
|
<div class="col"></div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@@ -133,7 +112,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<q-drawer show-if-above v-if="processChainShowDetails" v-model="processChainShowDetails" side="right" bordered width="350" class="text-dark">
|
<q-drawer show-if-above v-if="processChainShowDetails" v-model="processChainShowDetails" side="right" bordered width="350" class="text-dark">
|
||||||
<q-list style="width: 100%;word-break: break-all;">
|
<q-list style="width: 100%;word-break: break-all;">
|
||||||
<q-item>
|
<q-item>
|
||||||
<q-item-section>活跃状态: {{processChainDetails.active ? "运行中" : "已结束"}}</q-item-section>
|
<q-item-section>活跃状态: {{processChainDetails.active ? "运行中" : "已结束"}}</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-separator />
|
<q-separator />
|
||||||
@@ -161,13 +140,13 @@
|
|||||||
<q-item-section>进程hash: {{processChainDetails.md5}}</q-item-section>
|
<q-item-section>进程hash: {{processChainDetails.md5}}</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-separator />
|
<q-separator />
|
||||||
<q-item>
|
<q-item>
|
||||||
<q-item-section>是否在白名单中: {{processChainDetails.isWhite ? "是" : "否"}}</q-item-section>
|
<q-item-section>是否在白名单中: {{processChainDetails.isWhite ? "是" : "否"}}</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-separator />
|
<q-separator />
|
||||||
<q-item>
|
<q-item>
|
||||||
<q-item-section>进程命中的规则:
|
<q-item-section>进程命中的规则:
|
||||||
<template v-for="(index, operation) in processChainDetails.hitRules" :key="index">
|
<template v-for="(index, operation) in processChainDetails.hitRules" :key="index">
|
||||||
<q-chip square color="rgb(239,243,246)">
|
<q-chip square color="rgb(239,243,246)">
|
||||||
{{ operation }} ({{ index }})
|
{{ operation }} ({{ index }})
|
||||||
</q-chip>
|
</q-chip>
|
||||||
@@ -181,7 +160,7 @@
|
|||||||
</q-item>
|
</q-item>
|
||||||
<q-item>
|
<q-item>
|
||||||
<q-item-section>attck矩阵:
|
<q-item-section>attck矩阵:
|
||||||
<template v-for="(index, operation) in processChainDetails.hitAttck" :key="index">
|
<template v-for="(index, operation) in processChainDetails.hitAttck" :key="index">
|
||||||
<q-chip square color="rgb(239,243,246)">
|
<q-chip square color="rgb(239,243,246)">
|
||||||
{{ operation }} ({{ index }})
|
{{ operation }} ({{ index }})
|
||||||
</q-chip>
|
</q-chip>
|
||||||
@@ -251,41 +230,6 @@ export default defineComponent({
|
|||||||
width: '9px',
|
width: '9px',
|
||||||
opacity: 0.2
|
opacity: 0.2
|
||||||
},
|
},
|
||||||
threatStatistics: {
|
|
||||||
all: 1,
|
|
||||||
confirm: 0,
|
|
||||||
ingore: 1,
|
|
||||||
working: 0
|
|
||||||
},
|
|
||||||
Threatitems: [{
|
|
||||||
title: '发现的威胁',
|
|
||||||
icon: 'remove_red_eye',
|
|
||||||
value: '200',
|
|
||||||
color1: '#5064b5',
|
|
||||||
color2: '#3e51b5'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '确认的威胁',
|
|
||||||
icon: 'flash_on',
|
|
||||||
value: '500',
|
|
||||||
color1: '#f37169',
|
|
||||||
color2: '#f34636'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '忽略的威胁',
|
|
||||||
icon: 'texture',
|
|
||||||
value: '50',
|
|
||||||
color1: '#ea6a7f',
|
|
||||||
color2: '#ea4b64'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '进行中的威胁',
|
|
||||||
icon: 'bar_chart',
|
|
||||||
value: '1020',
|
|
||||||
color1: '#a270b1',
|
|
||||||
color2: '#9f52b1'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
dialog: false,
|
dialog: false,
|
||||||
maximizedToggle: true,
|
maximizedToggle: true,
|
||||||
server_threat: {},
|
server_threat: {},
|
||||||
@@ -453,23 +397,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
get_threatStatistics () {
|
|
||||||
axios
|
|
||||||
.get('/api/v1/get/threat_statistics', {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
const data = response.data
|
|
||||||
if (data.data) {
|
|
||||||
this.threatStatistics = data.data
|
|
||||||
// Threatitems
|
|
||||||
this.Threatitems[0].value = this.threatStatistics.all
|
|
||||||
this.Threatitems[1].value = this.threatStatistics.confirm
|
|
||||||
this.Threatitems[2].value = this.threatStatistics.ingore
|
|
||||||
this.Threatitems[3].value = this.threatStatistics.working
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
get_clientids () {
|
get_clientids () {
|
||||||
const queryType = this.$route.params.queryIndex
|
const queryType = this.$route.params.queryIndex
|
||||||
const queryIndex = (queryType === null || queryType === undefined) ? 0 : queryType
|
const queryIndex = (queryType === null || queryType === undefined) ? 0 : queryType
|
||||||
@@ -484,7 +412,6 @@ export default defineComponent({
|
|||||||
data: []
|
data: []
|
||||||
}
|
}
|
||||||
this.server_threat.data = data.data
|
this.server_threat.data = data.data
|
||||||
this.get_threatStatistics()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const routes = [
|
|||||||
path: '/',
|
path: '/',
|
||||||
component: () => import('layouts/MainLayout.vue'),
|
component: () => import('layouts/MainLayout.vue'),
|
||||||
children: [
|
children: [
|
||||||
{ path: '', component: () => import('pages/Index.vue') }
|
{ path: '', component: () => import('pages/Dashboard.vue') }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
33
readme.md
@@ -1,11 +1,9 @@
|
|||||||

|

|
||||||
|
|
||||||
# RmEye
|
# RmEye
|
||||||
RmEye是一个window上的基于att&ck现代EDR设计思想的威胁响应工具.
|
RmEye是一个window上的基于att&ck现代EDR设计思想的威胁响应工具.
|
||||||
不同于EDR,它轻量、高效.自身定位是轻量级威胁检出工具.
|
不同于EDR,它轻量、高效.自身定位是轻量级威胁检出工具.
|
||||||
而不是繁重的、需要付费的、效果不明的所谓的EDR
|
而不是繁重的、需要付费的、效果不明的所谓的EDR
|
||||||
RmEye基于att&ck模型,如果您对att&ck模型不熟悉,请先阅读相关文章后再使用:
|
|
||||||
https://key08.com/index.php/2022/08/09/1505.html
|
|
||||||
|
|
||||||
### 功能特点
|
### 功能特点
|
||||||
1. 基于att&ck设计.所有设计只是为了符合att&ck的攻击路径、攻击链(虽然规则里面没有标注T因为懒惰)
|
1. 基于att&ck设计.所有设计只是为了符合att&ck的攻击路径、攻击链(虽然规则里面没有标注T因为懒惰)
|
||||||
@@ -25,6 +23,15 @@ https://key08.com/index.php/2022/08/09/1505.html
|
|||||||
请牢记,RmEye自身定位是轻量级威胁检出工具
|
请牢记,RmEye自身定位是轻量级威胁检出工具
|
||||||
|
|
||||||
### 最新新闻
|
### 最新新闻
|
||||||
|
2022/10/11:
|
||||||
|
重新设计了一下界面...
|
||||||
|
|
||||||
|
2022/9/29:
|
||||||
|
国庆节更新,增加ip与hash的ioc插件,目前Rmeye有能力对ip和hash进行标注,使用时务必换成自己的apikey,其他请看下面的ioc部分
|
||||||
|
|
||||||
|
2022/9/22:
|
||||||
|
增加仪表盘,可视化展示检测结果
|
||||||
|
|
||||||
2022/9/21:
|
2022/9/21:
|
||||||
修复了秋季更新的几个bug,增加了`networkconnect`和`FileCreateTimeChange`的ds,增加了`brc4`的检测
|
修复了秋季更新的几个bug,增加了`networkconnect`和`FileCreateTimeChange`的ds,增加了`brc4`的检测
|
||||||
|
|
||||||
@@ -47,8 +54,19 @@ https://github.com/RoomaSec/RmEye/blob/main/doc_day0_rule.md
|
|||||||
增加uac提权检测插件`uac_bypass_detect`,但是受限于sysmon,没有办法获取RPC信息,因此只能检测一部分的UAC提权行为.并且有误报,请酌情考虑
|
增加uac提权检测插件`uac_bypass_detect`,但是受限于sysmon,没有办法获取RPC信息,因此只能检测一部分的UAC提权行为.并且有误报,请酌情考虑
|
||||||
|
|
||||||
### 检出截图
|
### 检出截图
|
||||||
|
|
||||||
|
新dashboard(2022/10/11更新):
|
||||||
|

|
||||||
|
新界面(2022/10/11更新):
|
||||||
|

|
||||||
|
|
||||||
|
IOC(2022/10/1更新):
|
||||||
|

|
||||||
|

|
||||||
威胁列表(2022/9/20更新):
|
威胁列表(2022/9/20更新):
|
||||||

|

|
||||||
|
仪表盘(2022/9/22更新):
|
||||||
|

|
||||||
进程链行为回溯
|
进程链行为回溯
|
||||||

|

|
||||||
powershell恶意执行:
|
powershell恶意执行:
|
||||||
@@ -135,6 +153,9 @@ sysmon /uninstall
|
|||||||
```
|
```
|
||||||
即可干净卫生的卸载掉RmEye
|
即可干净卫生的卸载掉RmEye
|
||||||
|
|
||||||
|
### IOC
|
||||||
|
目前RmEye使用的是`https://metadefender.opswat.com/`的免费IOC,目前的apikey仅用于测试,自己部署的时候请务必打开`plugins/ioc_opswat/opswat.py`把`"apikey": "010d4868aef799750e2828fdf17a4d98"`换成你自己的,否做会不安全(比如其他人能查得到你的请求记录)/有使用量限制(100次一天).所以务必换成你自己注册的账号.这个IOC源是免费的而且好用的,比OTX好用
|
||||||
|
|
||||||
### 规则相关的问题
|
### 规则相关的问题
|
||||||
1. 规则目前仅120条,很多攻击面没有覆盖,其他规则请访问《社区》
|
1. 规则目前仅120条,很多攻击面没有覆盖,其他规则请访问《社区》
|
||||||
2. 规则目前只支持rule_engine与yara的规则,其中yara的规则支持是以插件的形式支持
|
2. 规则目前只支持rule_engine与yara的规则,其中yara的规则支持是以插件的形式支持
|
||||||
@@ -173,12 +194,6 @@ https://github.com/VirusTotal/yara
|
|||||||
https://github.com/SwiftOnSecurity/sysmon-config
|
https://github.com/SwiftOnSecurity/sysmon-config
|
||||||
请遵守相关库的开源协议.相关法律风险本项目不负任何责任
|
请遵守相关库的开源协议.相关法律风险本项目不负任何责任
|
||||||
|
|
||||||
### 交流
|
|
||||||
开源的目的不是为了免费填鸭式教学,或者被免费拿去发公众号引流、去拿去集成产品方案去赚钱,而是要一起完善这个工具,从而实现共赢.
|
|
||||||
扫一扫加入这个工具的交流群,这样就能获取实时动态.参与开发、参与交流规则编写等等.欢迎加入
|
|
||||||
最近进群的人有点多,所以不活跃的哥们暂时清理掉,但是微信太不好使了.要是t错了或者还想在群待着不发言的重新加群吧
|
|
||||||

|
|
||||||
|
|
||||||
### 特别感谢
|
### 特别感谢
|
||||||
@Pwn0x01 yara插件
|
@Pwn0x01 yara插件
|
||||||
@zeroSteiner 规则引擎插件
|
@zeroSteiner 规则引擎插件
|
||||||
|
|||||||
4
requirements.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
Flask==2.2.2
|
||||||
|
requests==2.28.1
|
||||||
|
rule_engine==3.5.0
|
||||||
|
SQLAlchemy==1.4.42
|
||||||
39
sysmon.xml
@@ -282,7 +282,7 @@
|
|||||||
<Image name="Usermode" condition="begin with">C:\Users</Image> <!--Tools downloaded by users can use other processes for networking, but this is a very valuable indicator.-->
|
<Image name="Usermode" condition="begin with">C:\Users</Image> <!--Tools downloaded by users can use other processes for networking, but this is a very valuable indicator.-->
|
||||||
<Image name="Caution" condition="begin with">C:\Recycle</Image> <!--Nothing should operate from the RecycleBin locations.-->
|
<Image name="Caution" condition="begin with">C:\Recycle</Image> <!--Nothing should operate from the RecycleBin locations.-->
|
||||||
<Image condition="begin with">C:\ProgramData</Image> <!--Normally, network communications should be sourced from "Program Files" not from ProgramData, something to look at-->
|
<Image condition="begin with">C:\ProgramData</Image> <!--Normally, network communications should be sourced from "Program Files" not from ProgramData, something to look at-->
|
||||||
<Image condition="begin with">C:\Windows\Temp</Image> <!--Suspicious anything would communicate from the system-level temp directory-->
|
<Image condition="begin with">C:\Windows\</Image> <!--Suspicious anything would communicate from the system-level temp directory-->
|
||||||
<Image name="Caution" condition="begin with">\</Image> <!--Devices and VSC shouldn't be executing changes | Credit: @SBousseaden @ionstorm @neu5ron @PerchedSystems [ https://twitter.com/SwiftOnSecurity/status/1133167323991486464 ] -->
|
<Image name="Caution" condition="begin with">\</Image> <!--Devices and VSC shouldn't be executing changes | Credit: @SBousseaden @ionstorm @neu5ron @PerchedSystems [ https://twitter.com/SwiftOnSecurity/status/1133167323991486464 ] -->
|
||||||
<Image name="Caution" condition="begin with">C:\perflogs</Image> <!-- Credit @blu3_team [ https://blu3-team.blogspot.com/2019/05/netconn-from-suspicious-directories.html ] -->
|
<Image name="Caution" condition="begin with">C:\perflogs</Image> <!-- Credit @blu3_team [ https://blu3-team.blogspot.com/2019/05/netconn-from-suspicious-directories.html ] -->
|
||||||
<Image name="Caution" condition="begin with">C:\intel</Image> <!-- Credit @blu3_team [ https://blu3-team.blogspot.com/2019/05/netconn-from-suspicious-directories.html ] -->
|
<Image name="Caution" condition="begin with">C:\intel</Image> <!-- Credit @blu3_team [ https://blu3-team.blogspot.com/2019/05/netconn-from-suspicious-directories.html ] -->
|
||||||
@@ -376,8 +376,15 @@
|
|||||||
|
|
||||||
<RuleGroup name="" groupRelation="or">
|
<RuleGroup name="" groupRelation="or">
|
||||||
<NetworkConnect onmatch="exclude">
|
<NetworkConnect onmatch="exclude">
|
||||||
|
<Image condition="end with">clash-win64.exe</Image>
|
||||||
|
<Image condition="end with">dasHost.exe</Image>
|
||||||
|
<Image condition="end with">DingTalk.exe</Image>
|
||||||
|
<Image condition="end with">vmnat.exe</Image>
|
||||||
|
<Image condition="end with">SysEye.exe</Image>
|
||||||
|
|
||||||
<!--SECTION: Microsoft-->
|
<!--SECTION: Microsoft-->
|
||||||
<Image condition="begin with">C:\ProgramData\Microsoft\Windows Defender\Platform\</Image>
|
<Image condition="begin with">C:\ProgramData\Microsoft\Windows Defender\Platform\</Image>
|
||||||
|
<Image condition="is">C:\Windows\system32\svchost.exe</Image> <!--Microsoft: svchost-->
|
||||||
<Image condition="end with">AppData\Local\Microsoft\Teams\current\Teams.exe</Image> <!--Microsoft: Teams-->
|
<Image condition="end with">AppData\Local\Microsoft\Teams\current\Teams.exe</Image> <!--Microsoft: Teams-->
|
||||||
<DestinationHostname condition="end with">.microsoft.com</DestinationHostname> <!--Microsoft:Update delivery-->
|
<DestinationHostname condition="end with">.microsoft.com</DestinationHostname> <!--Microsoft:Update delivery-->
|
||||||
<DestinationHostname condition="end with">microsoft.com.akadns.net</DestinationHostname> <!--Microsoft:Update delivery-->
|
<DestinationHostname condition="end with">microsoft.com.akadns.net</DestinationHostname> <!--Microsoft:Update delivery-->
|
||||||
@@ -423,7 +430,34 @@
|
|||||||
<!--DATA: UtcTime, ProcessGuid, ProcessId, Image, ImageLoaded, Hashes, Signed, Signature, SignatureStatus-->
|
<!--DATA: UtcTime, ProcessGuid, ProcessId, Image, ImageLoaded, Hashes, Signed, Signature, SignatureStatus-->
|
||||||
<RuleGroup name="" groupRelation="or">
|
<RuleGroup name="" groupRelation="or">
|
||||||
<ImageLoad onmatch="include">
|
<ImageLoad onmatch="include">
|
||||||
<!--NOTE: Using "include" with no rules means nothing in this section will be logged-->
|
<ImageLoaded condition="contains">samlib.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">advapi32.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">crypt32.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">cryptdll.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">gdi32.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">imm32.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">msasn1.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">msvcrt.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">rpcrt4.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">rsaenh.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">samlib.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">sechost.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">secur32.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">shell32.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">shlwapi.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">sspicli.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">user32.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">vaultcli.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">dbghelp.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">winhttp.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">credui.dll</ImageLoaded>
|
||||||
|
|
||||||
|
<ImageLoaded condition="contains">dnsapi.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">rtutils.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">urlmon.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">sensapi.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">rasapi32.dll</ImageLoaded>
|
||||||
|
<ImageLoaded condition="contains">napinsp.dll</ImageLoaded>
|
||||||
</ImageLoad>
|
</ImageLoad>
|
||||||
</RuleGroup>
|
</RuleGroup>
|
||||||
|
|
||||||
@@ -585,7 +619,6 @@
|
|||||||
<TargetFilename name="T1176" condition="end with">.crx</TargetFilename> <!--Chrome extension-->
|
<TargetFilename name="T1176" condition="end with">.crx</TargetFilename> <!--Chrome extension-->
|
||||||
<TargetFilename condition="end with">.dmp</TargetFilename> <!--Process dumps [ (fr) http://blog.gentilkiwi.com/securite/mimikatz/minidump ] -->
|
<TargetFilename condition="end with">.dmp</TargetFilename> <!--Process dumps [ (fr) http://blog.gentilkiwi.com/securite/mimikatz/minidump ] -->
|
||||||
<TargetFilename condition="end with">.docm</TargetFilename> <!--Microsoft:Office:Word: Macro-->
|
<TargetFilename condition="end with">.docm</TargetFilename> <!--Microsoft:Office:Word: Macro-->
|
||||||
<TargetFilename condition="end with">.otm</TargetFilename> <!--Microsoft:Office:VBS: Macro-->
|
|
||||||
<TargetFilename name="DLL" condition="end with">.dll</TargetFilename> <!--Microsoft:Office:Word: Macro-->
|
<TargetFilename name="DLL" condition="end with">.dll</TargetFilename> <!--Microsoft:Office:Word: Macro-->
|
||||||
<TargetFilename name="EXE" condition="end with">.exe</TargetFilename> <!--Executable-->
|
<TargetFilename name="EXE" condition="end with">.exe</TargetFilename> <!--Executable-->
|
||||||
<TargetFilename name="ProcessHostingdotNETCode" condition="end with">.exe.log</TargetFilename> <!-- [ https://github.com/bitsadmin/nopowershell ] | Credit: @SBousseaden [ https://twitter.com/SBousseaden/status/1137493597769687040 ] -->
|
<TargetFilename name="ProcessHostingdotNETCode" condition="end with">.exe.log</TargetFilename> <!-- [ https://github.com/bitsadmin/nopowershell ] | Credit: @SBousseaden [ https://twitter.com/SBousseaden/status/1137493597769687040 ] -->
|
||||||
|
|||||||