10 Commits

Author SHA1 Message Date
huoji
fe69282d89 白名单现在看父进程,如果父进程是白名单的子进程产生的行为都加白(不确定是否可靠,有待观察).
白名单现在看父进程,如果父进程是白名单的子进程产生的行为都加白(不确定是否可靠,有待观察).
2022-09-02 15:23:34 +08:00
huoji
e3ae734150 增加白名单、进程链增加详细信息
增加白名单、进程链增加详细信息
2022-08-31 17:52:26 +08:00
huoji
5c15aa975d Update .gitignore 2022-08-30 15:08:25 +08:00
huoji
628c87facc 1 2022-08-30 15:08:15 +08:00
huoji
816c32c899 Update group.png 2022-08-30 15:06:13 +08:00
huoji
fb1263043a Update webserver.py 2022-08-29 20:01:09 +08:00
huoji
fd44c23181 Update webserver.py 2022-08-29 20:00:30 +08:00
huoji
ae90a158bd Update prcoess_chain_detect.py 2022-08-29 20:00:02 +08:00
huoji
5b4f9c32c4 Merge branch 'main' of https://github.com/RoomaSec/RmEye 2022-08-29 18:46:59 +08:00
huoji
d3907bb427 增加uac提权检测 2022-08-29 18:46:56 +08:00
37 changed files with 754 additions and 345 deletions

1
.gitignore vendored
View File

@@ -153,3 +153,4 @@ cython_debug/
*.db
*.zip
*.db-journal

BIN
Image/7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
Image/8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 KiB

BIN
Image/group2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

View File

@@ -4,6 +4,8 @@
RmEye是一个window上的基于att&ck现代EDR设计思想的威胁响应工具.
不同于EDR,它轻量、高效.自身定位是轻量级威胁检出工具.
而不是繁重的、需要付费的、效果不明的所谓的EDR
RmEye基于att&ck模型,如果您对att&ck模型不熟悉,请先阅读相关文章后再使用:
https://key08.com/index.php/2022/08/09/1505.html
### 功能特点
1. 基于att&ck设计.所有设计只是为了符合att&ck的攻击路径、攻击链(虽然规则里面没有标注T因为懒惰)
@@ -19,12 +21,23 @@ RmEye是一个window上的基于att&ck现代EDR设计思想的威胁响应工具
5. 对RPC、COM、ALPC基本无能为力
6. 不支持更高级的扩展检测,如检测脚本、下发规则,主机链
7. 受限于Sysmon,很多att&ck的T没有覆盖,也无法覆盖.
8. 没有响应能力,只能被动记录.
请牢记,RmEye自身定位是轻量级威胁检出工具
### 最新新闻
2022/8/31:
增加进程白名单系统,现在能给进程加白名单了.在打开进程链后,点击某个进程加入白名单即可
2022/8/29:
增加uac提权检测插件`uac_bypass_detect`,但是受限于sysmon,没有办法获取RPC信息,因此只能检测一部分的UAC提权行为.并且有误报,请酌情考虑
### 检出截图
威胁列表:
![image](Image/1.png)
powershell:
进程链行为回溯
![image](Image/8.png)
powershell恶意执行:
![image](Image/2.png)
apt样本:
![image](Image/3.png)
@@ -34,6 +47,8 @@ apt样本:
![image](Image/5.png)
offic宏钓鱼:
![image](Image/6.png)
uac提权检测:
![image](Image/7.png)
### 待做列表
1. 更好的前端(目前是VUE-CDN模式,不太好,想换成VUE-CLI) 已经完成
@@ -47,7 +62,7 @@ offic宏钓鱼:
9. 完善目前的插件系统【目前重点】
10. 云日志检测能力【目前重点】
### 安装
下载release( https://github.com/RoomaSec/RmEye/releases/tag/pre-release ),里面有客户端,服务端自行clone本项目
下载release( https://github.com/RoomaSec/RmEye/releases ),里面有客户端,服务端自行clone本项目
服务端是python3编写,安装完依赖库后输入
```
python webserver.py
@@ -108,7 +123,7 @@ sysmon /uninstall
2. 规则目前只支持rule_engine与yara的规则,其中yara的规则支持是以插件的形式支持
3. 目前的规则字段完全依赖sysmon的字段,sysmon的字段请检查根目录下的provider.json(但是请记住纯小写,自行做大小写转换)
规则目前有两种规则:
规则目前在`Server/rules`目录规则目前有两种规则:
rule_engine:
如检测由CMD启动的ipconfig:
```
@@ -140,8 +155,8 @@ https://github.com/SwiftOnSecurity/sysmon-config
### 交流
开源的目的不是为了免费填鸭式教学,或者被免费拿去发公众号引流、去拿去集成产品方案去赚钱,而是要一起完善这个工具,从而实现共赢.
扫一扫加入这个工具内部测试群,这样就能获取实时动态
![image](Image/group.png)
扫一扫加入这个工具的交流群,这样就能获取实时动态.参与开发、参与交流规则编写等等.欢迎加入
![image](Image/group2.png)
### 特别感谢
@Pwn0x01 yara插件

View File

@@ -1,4 +1,4 @@
# 检出阈值,越高越难检出但是也会越准确
MAX_THREAT_SCORE = 170
# 授权访问主站的IP列表.如果不在后台里面则不能访问后台
ALLOW_ACCESS_IP = ['127.0.0.1']
ALLOW_ACCESS_IP = ['127.0.0.1', '192.168.111.189', '192.168.111.187']

17
Server/hash_white_list.py Normal file
View File

@@ -0,0 +1,17 @@
import sql
g_white_list = []
def add_white_list(path, hash, reason):
global g_white_list
if hash in g_white_list:
return False
g_white_list.append(hash)
sql.push_white_list(path, hash, reason)
def synchronization_white_list():
sql_data = sql.query_all_white_list()
for data in sql_data:
g_white_list.append(data[1])
print("sync white list success, size: {}".format(len(sql_data)))

View File

@@ -8,6 +8,7 @@ import sql
import global_vars
import config
import plugin
import hash_white_list
def process_log(host, json_log, raw_log):
@@ -53,9 +54,12 @@ def process_log(host, json_log, raw_log):
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
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
@@ -63,9 +67,11 @@ def process_log(host, json_log, raw_log):
child.set_score(score, rule_hit_name)
had_threat = global_vars.THREAT_TYPE_PROCESS
else:
is_white_list = hash in hash_white_list.g_white_list
child = process.Process(
pid, ppid, path, params, create_time, hash, user, host
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
if score > 0:
@@ -81,7 +87,8 @@ def process_log(host, json_log, raw_log):
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)
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 >= (
@@ -222,8 +229,8 @@ def process_raw_log(raw_logs: list) -> list:
hash = log.hash
create_time = log.timestamp
host = log.host
current_process:process.Process = None
if path in process.skip_process_path :
current_process: process.Process = None
if path in process.skip_process_path:
continue
if log.action.lower() == "processcreate":

View File

@@ -1,7 +1,5 @@
import global_vars
import yara
import glob
from pathlib import Path
#import yara
rm_plugs_config = {
"enable": False,

View File

@@ -0,0 +1,49 @@
import global_vars
import process
#import yara
rm_plugs_config = {
"enable": True,
"author": "huoji",
"description": "基于进程链的uac提权检测",
"version": "0.0.1"
}
def intergritylevel_to_int(str_name):
if str_name == 'high':
return 3
elif str_name == 'medium':
return 2
return 1
def rule_new_process_create(current_process: process.Process, host, raw_log_data, json_log_data):
if 'integritylevel' in json_log_data['data']:
integritylevel = intergritylevel_to_int(
json_log_data['data']['integritylevel'])
current_process.plugin_var['uac_flag'] = integritylevel
if 'uac_flag' not in current_process.chain.root_process.plugin_var:
current_process.chain.root_process.plugin_var['uac_flag'] = integritylevel
if integritylevel > current_process.chain.root_process.plugin_var['uac_flag']:
print('[uac bypass detect] detect uac bypass in process chain {}'.format(
current_process.path))
current_process.chain.root_process.plugin_var['uac_flag'] = integritylevel
current_process.set_score(30, "进程权限等级变动")
return global_vars.THREAT_TYPE_PROCESS
# print('process chain: {} path: {} level: {} log level: {}'.format(
# current_process.chain_hash, current_process.path, integritylevel, current_process.chain.root_process.plugin_var['uac_flag']))
return global_vars.THREAT_TYPE_NONE
def rule_new_process_action(current_process, host, raw_log_data, json_log_data):
return global_vars.THREAT_TYPE_NONE
def rule_init():
print('[helloworld plugin] rule init')
def plugin_init():
print('[helloworld plugin] plugin init')

View File

@@ -1,8 +1,6 @@
import json
from sqlalchemy import false
import tools
import time
skip_process_path = ['c:\\program files\\rivet networks\\smartbyte\\raps.exe',
'c:\\program files (x86)\\sogouinput\\11.5.0.5352\\pinyinup.exe',
@@ -87,8 +85,9 @@ g_ProcessChainList = []
class Process:
def __init__(self, pid, ppid, path, params, time, md5, user, host):
def __init__(self, pid, ppid, path, params, time, md5, user, host, is_white=False):
self.pid = pid
self.parent_process = None
self.ppid = ppid
self.path = path
self.params = params
@@ -102,10 +101,12 @@ class Process:
self.time = time
self.rmppid = ""
self.root_rmpid = ""
self.plugin_var = {}
self.md5 = md5
self.user = user
self.chain: ProcessChain = None
self.host = host
self.is_white = is_white
def set_chain_data(self, chain):
self.chain = chain
@@ -120,6 +121,8 @@ class Process:
self.rmppid = rmppid
def set_score(self, new_score, opertion):
if self.is_white or self.chain.root_process.is_white or self.parent_process.is_white:
return
if opertion not in self.operationlist:
self.risk_score += new_score
self.operationlist[opertion] = 1
@@ -150,6 +153,7 @@ class ProcessChain:
self.rpc_process_chain = ""
self.time = root_process.time
self.host = root_process.host
self.plugin_var = {}
self.add_root_process(root_process)
def get_operationlist(self):

View File

@@ -17,7 +17,7 @@ rule = [
'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"',
],
'score': 40,
'score': 20,
'name': '异常进程访问'
},
{

View File

@@ -306,6 +306,21 @@ rule = [
'score': 30,
'name': '从服务创建的进程'
},
{
'rules': [
'parentimage =~ ".*svchost.exe"',
'originalfilename =~ ".*werfault.exe"'
],
'score': 60,
'name': 'svchost.exe启动了werfault'
},
{
'rules': [
'parentimage =~ ".*werfault.exe"',
],
'score': 30,
'name': '从werfault创建的进程'
},
{
'rules': [
'originalfilename =~ ".*wscript.exe"',

View File

@@ -20,6 +20,8 @@ g_rawdata_table = None
g_rawdata_table_ins = None
g_threat_table = None
g_threat_table_ins = None
g_hash_white_list_table = None
g_hash_white_list_table_ins = None
class raw_process_log(g_base):
@@ -62,6 +64,15 @@ class raw_process_log(g_base):
return self.id
class hash_white_list(g_base):
__tablename__ = "hash_white_list"
id = Column(Integer, primary_key=True)
hash = Column(String)
path = Column(String)
timestamp = Column(Integer)
reason = Column(String)
class threat_log(g_base):
__tablename__ = "threat_log"
# 定义各字段
@@ -99,8 +110,11 @@ def init():
global g_rawdata_table_ins
global g_threat_table
global g_threat_table_ins
global g_hash_white_list_table
global g_hash_white_list_table_ins
g_engine = create_engine("sqlite:///syseye.db?check_same_thread=False", echo=False)
g_engine = create_engine(
"sqlite:///syseye.db?check_same_thread=False", echo=False)
g_base.metadata.create_all(g_engine)
g_metadata = MetaData(g_engine)
g_rawdata_table = Table("raw_process_log", g_metadata, autoload=True)
@@ -109,6 +123,54 @@ def init():
g_threat_table = Table("threat_log", g_metadata, autoload=True)
g_threat_table_ins = g_threat_table.insert()
g_hash_white_list_table = Table(
"hash_white_list", g_metadata, autoload=True)
g_hash_white_list_table_ins = g_hash_white_list_table.insert()
def query_white_list_by_hash(pHash):
global g_hash_white_list_table
sql_session = sessionmaker(bind=g_engine)
white_list = sql_session().query(
g_hash_white_list_table).filter_by(hash=pHash).first()
sql_session().close()
return white_list
def delete_white_list(pHash):
global g_hash_white_list_table
global g_engine
conn = g_engine.connect()
result = conn.execute(
delete(g_hash_white_list_table).where(
g_hash_white_list_table.columns.hash == pHash)
)
return result
def push_white_list(pPath, pHash, pReason):
global g_hash_white_list_table_ins
current_time = int(round(time.time() * 1000))
ins = g_hash_white_list_table_ins.values(
path=pPath, hash=pHash, reason=pReason, timestamp=current_time)
# 连接引擎
conn = g_engine.connect()
# 执行语句
result = conn.execute(ins)
return result
def query_all_white_list():
global g_hash_white_list_table
sql_session = sessionmaker(bind=g_engine)
white_list = (
sql_session()
.query(g_hash_white_list_table)
.all()
)
sql_session().close()
return white_list
def push_process_raw(
host,
@@ -241,7 +303,8 @@ def delete_threat(threat_id):
global g_engine
conn = g_engine.connect()
result = conn.execute(
delete(g_threat_table).where(g_threat_table.columns.id == int(threat_id))
delete(g_threat_table).where(
g_threat_table.columns.id == int(threat_id))
)
return result

View File

@@ -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.070221f5.js></script><script defer src=js/app.3ea8aeff.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.8b656787.js></script><script defer src=js/app.3ff22fb9.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>

View File

@@ -1 +1 @@
"use strict";(globalThis["webpackChunksyseye"]=globalThis["webpackChunksyseye"]||[]).push([[193],{2193:(e,t,s)=>{s.r(t),s.d(t,{default:()=>p});var l=s(3673);const n={class:"fullscreen bg-blue text-white text-center q-pa-md flex flex-center"},o=(0,l._)("div",{style:{"font-size":"30vh"}}," 404 ",-1),c=(0,l._)("div",{class:"text-h2",style:{opacity:".4"}}," Oops. Nothing here... ",-1);function a(e,t,s,a,r,i){const u=(0,l.up)("q-btn");return(0,l.wg)(),(0,l.iD)("div",n,[(0,l._)("div",null,[o,c,(0,l.Wm)(u,{class:"q-mt-xl",color:"white","text-color":"blue",unelevated:"",to:"/",label:"Go Home","no-caps":""})])])}const r=(0,l.aZ)({name:"Error404"});var i=s(4260),u=s(9400),h=s(7518),b=s.n(h);const d=(0,i.Z)(r,[["render",a]]),p=d;b()(r,"components",{QBtn:u.Z})}}]);
"use strict";(globalThis["webpackChunksyseye"]=globalThis["webpackChunksyseye"]||[]).push([[193],{2193:(e,t,s)=>{s.r(t),s.d(t,{default:()=>p});var l=s(3673);const n={class:"fullscreen bg-blue text-white text-center q-pa-md flex flex-center"},o=(0,l._)("div",{style:{"font-size":"30vh"}}," 404 ",-1),c=(0,l._)("div",{class:"text-h2",style:{opacity:".4"}}," Oops. Nothing here... ",-1);function a(e,t,s,a,r,i){const u=(0,l.up)("q-btn");return(0,l.wg)(),(0,l.iD)("div",n,[(0,l._)("div",null,[o,c,(0,l.Wm)(u,{class:"q-mt-xl",color:"white","text-color":"blue",unelevated:"",to:"/",label:"Go Home","no-caps":""})])])}const r=(0,l.aZ)({name:"Error404"});var i=s(4260),u=s(8240),h=s(7518),b=s.n(h);const d=(0,i.Z)(r,[["render",a]]),p=d;b()(r,"components",{QBtn:u.Z})}}]);

View File

@@ -0,0 +1 @@
"use strict";(globalThis["webpackChunksyseye"]=globalThis["webpackChunksyseye"]||[]).push([[315],{7315:(e,a,t)=>{t.r(a),t.d(a,{default:()=>_});var n=t(3673),s=t(2323);function o(e,a,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:e.$q.screen.lt.md,title:"白名单列表",columns:e.data_columns,rows:e.data_columns_data,loading:e.loading,pagination:e.pagination,"onUpdate:pagination":a[0]||(a[0]=a=>e.pagination=a),onRequest:e.onRequest},{body:(0,n.w5)((a=>[(0,n.Wm)(d,{props:a},{default:(0,n.w5)((()=>[(0,n.Wm)(r,{key:"path",props:a},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(a.row.path),1)])),_:2},1032,["props"]),(0,n.Wm)(r,{key:"hash",props:a},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(a.row.hash),1)])),_:2},1032,["props"]),(0,n.Wm)(r,{key:"reason",props:a},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(a.row.reason),1)])),_:2},1032,["props"]),(0,n.Wm)(r,{key:"timestamp",props:a},{default:(0,n.w5)((()=>[(0,n.Uk)((0,s.zw)(e.time_parase(a.row.timestamp)),1)])),_:2},1032,["props"]),(0,n.Wm)(r,{key:"action",props:a},{default:(0,n.w5)((()=>[(0,n.Wm)(p,{color:"red",label:"移除白名单",onClick:t=>e.delete_white_hash(a.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(e){l().get("/api/v1/del/white_list?hash="+e).then((e=>{console.log("duck was gone")}))},time_parase(e){const a=e=>e<10?"0"+e:e,t=new Date(Number(e));console.log("time",e);const n=t.getFullYear(),s=t.getMonth()+1,o=t.getDate(),i=t.getHours(),l=t.getMinutes(),r=t.getSeconds();return n+"-"+a(s)+"-"+a(o)+" "+a(i)+":"+a(l)+":"+a(r)},onRequest(e){this.data_columns_data=[],this.loading=!0;const{page:a}=e.pagination;l().get("/api/v1/query/white_list_all").then((e=>{const t=e.data.result;console.log(t);for(let a=0;a<t.length;a++){const e=t[a];this.data_columns_data.push(e)}this.pagination.page=a,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),c=t(7518),m=t.n(c);const w=(0,p.Z)(r,[["render",o]]),_=w;m()(r,"components",{QTable:d.Z,QTr:h.Z,QTd:g.Z,QBtn:u.Z})}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -1 +0,0 @@
"use strict";(globalThis["webpackChunksyseye"]=globalThis["webpackChunksyseye"]||[]).push([[950],{950:(e,a,t)=>{t.r(a),t.d(a,{default:()=>T});var l=t(3673);const r=(0,l.Uk)(" DuckSysEye内部测试版本v0.0.0.1 "),i=(0,l.Uk)(" 仪表盘 "),n=(0,l.Uk)(" 未处理威胁列表 "),o=(0,l.Uk)(" 已处理威胁列表 "),u=(0,l.Uk)(" 已忽略威胁列表 ");function c(e,a,t,c,s,d){const m=(0,l.up)("q-toolbar-title"),w=(0,l.up)("q-btn"),p=(0,l.up)("q-toolbar"),b=(0,l.up)("q-header"),_=(0,l.up)("q-icon"),h=(0,l.up)("q-item-section"),v=(0,l.up)("q-item"),f=(0,l.up)("q-list"),W=(0,l.up)("q-scroll-area"),k=(0,l.up)("q-drawer"),g=(0,l.up)("router-view"),y=(0,l.up)("q-page-container"),L=(0,l.up)("q-layout"),Z=(0,l.Q2)("ripple");return(0,l.wg)(),(0,l.j4)(L,{view:"lHh Lpr lFf",style:{"background-color":"rgb(239, 243, 246)"}},{default:(0,l.w5)((()=>[(0,l.Wm)(b,{elevated:"","height-hint":"98"},{default:(0,l.w5)((()=>[(0,l.Wm)(p,{class:"text-primary bg-white"},{default:(0,l.w5)((()=>[(0,l.Wm)(m,null,{default:(0,l.w5)((()=>[r])),_:1}),(0,l.Wm)(w,{flat:"",round:"",dense:"",icon:"more_vert"})])),_:1})])),_:1}),(0,l.Wm)(k,{"show-if-above":"",mini:e.miniState,onMouseover:a[4]||(a[4]=a=>e.miniState=!1),onMouseout:a[5]||(a[5]=a=>e.miniState=!0),width:200,breakpoint:500,bordered:"",class:"bg-white text-primary"},{default:(0,l.w5)((()=>[(0,l.Wm)(W,{class:"fit"},{default:(0,l.w5)((()=>[(0,l.Wm)(f,{padding:""},{default:(0,l.w5)((()=>[(0,l.wy)(((0,l.wg)(),(0,l.j4)(v,{active:"dashboard"==e.selectLabel,clickable:"","active-class":"menu-active",onClick:a[0]||(a[0]=a=>e.selectLabel="dashboard"),to:"/page/dashboard"},{default:(0,l.w5)((()=>[(0,l.Wm)(h,{avatar:""},{default:(0,l.w5)((()=>[(0,l.Wm)(_,{name:"dashboard"})])),_:1}),(0,l.Wm)(h,null,{default:(0,l.w5)((()=>[i])),_:1})])),_:1},8,["active"])),[[Z]]),(0,l.wy)(((0,l.wg)(),(0,l.j4)(v,{active:"non_hanlde_report"==e.selectLabel,clickable:"","active-class":"menu-active",onClick:a[1]||(a[1]=a=>{e.selectLabel="non_hanlde_report",e.routerToThreatList(0)})},{default:(0,l.w5)((()=>[(0,l.Wm)(h,{avatar:""},{default:(0,l.w5)((()=>[(0,l.Wm)(_,{name:"report"})])),_:1}),(0,l.Wm)(h,null,{default:(0,l.w5)((()=>[n])),_:1})])),_:1},8,["active"])),[[Z]]),(0,l.wy)(((0,l.wg)(),(0,l.j4)(v,{active:"handle_report"==e.selectLabel,clickable:"","active-class":"menu-active",onClick:a[2]||(a[2]=a=>{e.selectLabel="handle_report",e.routerToThreatList(1)})},{default:(0,l.w5)((()=>[(0,l.Wm)(h,{avatar:""},{default:(0,l.w5)((()=>[(0,l.Wm)(_,{name:"done"})])),_:1}),(0,l.Wm)(h,null,{default:(0,l.w5)((()=>[o])),_:1})])),_:1},8,["active"])),[[Z]]),(0,l.wy)(((0,l.wg)(),(0,l.j4)(v,{active:"ingore_report"==e.selectLabel,clickable:"","active-class":"menu-active",onClick:a[3]||(a[3]=a=>{e.selectLabel="ingore_report",e.routerToThreatList(2)})},{default:(0,l.w5)((()=>[(0,l.Wm)(h,{avatar:""},{default:(0,l.w5)((()=>[(0,l.Wm)(_,{name:"texture"})])),_:1}),(0,l.Wm)(h,null,{default:(0,l.w5)((()=>[u])),_:1})])),_:1},8,["active"])),[[Z]])])),_:1})])),_:1})])),_:1},8,["mini"]),(0,l.Wm)(y,null,{default:(0,l.w5)((()=>[(0,l.Wm)(g)])),_:1})])),_:1})}const s=(0,l.aZ)({name:"MainLayout",setup(){return{}},data:function(){return{selectLabel:"non_hanlde_report",drawer:!1,miniState:!0}},methods:{routerToThreatList(e){this.$router.push({name:"index",params:{queryIndex:e}})}}});var d=t(4260),m=t(9214),w=t(3812),p=t(9570),b=t(3747),_=t(9400),h=t(2901),v=t(7704),f=t(7011),W=t(3414),k=t(2035),g=t(4554),y=t(2652),L=t(6489),Z=t(7518),q=t.n(Z);const Q=(0,d.Z)(s,[["render",c]]),T=Q;q()(s,"components",{QLayout:m.Z,QHeader:w.Z,QToolbar:p.Z,QToolbarTitle:b.Z,QBtn:_.Z,QDrawer:h.Z,QScrollArea:v.Z,QList:f.Z,QItem:W.Z,QItemSection:k.Z,QIcon:g.Z,QPageContainer:y.Z}),q()(s,"directives",{Ripple:L.Z})}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -1,3 +1,4 @@
import hash_white_list
import json
from flask import Flask
from flask import request
@@ -8,6 +9,7 @@ import config
from flask import Flask, render_template, request
import plugin
import logging
import html
app = Flask(
__name__,
@@ -53,7 +55,8 @@ def threat_statistics():
return "Access Denied"
# sqlite的count啥的还不如自己查出来自己统计
threat_datas = sql.query_all_threat_log(-1)
return_data = {"all": len(threat_datas), "confirm": 0, "ingore": 0, "working": 0}
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
@@ -64,6 +67,59 @@ def threat_statistics():
return {"data": return_data}
@app.route("/api/v1/query/white_list_all", methods=["GET"])
def white_list_query_all():
if request.remote_addr not in config.ALLOW_ACCESS_IP:
return "Access Denied"
all_list = sql.query_all_white_list()
result = []
for iter in all_list:
result.append({
"hash": iter[1],
"path": iter[2],
"timestamp": iter[3],
"reason": iter[4]
})
return {"status": "success", "result": result}
@app.route("/api/v1/query/white_list", methods=["GET"])
def white_list_query():
hash = request.args.get("hash")
if request.remote_addr not in config.ALLOW_ACCESS_IP or hash is None or len(hash) == 0:
return "Access Denied"
hash = hash.lower()
result = 0
if hash in hash_white_list.g_white_list:
result = 1
return {"status": "success", "result": result}
@app.route("/api/v1/del/white_list", methods=["GET"])
def white_list_del():
hash = request.args.get("hash")
if request.remote_addr not in config.ALLOW_ACCESS_IP or hash is None or len(hash) == 0:
return "Access Denied"
hash = hash.lower()
if hash in hash_white_list.g_white_list:
sql.delete_white_list(hash)
hash_white_list.g_white_list.remove(hash)
return {"status": "success"}
@app.route("/api/v1/set/white_list", methods=["POST"])
def white_list_set():
body_data = request.data.decode()
if request.remote_addr not in config.ALLOW_ACCESS_IP:
return "Access Denied"
json_data = json.loads(body_data)
hash = html.escape(json_data["hash"]).lower()
path = html.escape(json_data["path"]).lower()
reason = html.escape(json_data["reason"])
hash_white_list.add_white_list(path, hash, reason)
return {"status": "success"}
@app.route("/api/v1/get/process_chain/handle", methods=["GET"])
def handle_chain_data():
id = request.args.get("id")
@@ -148,7 +204,8 @@ def log_rescan():
return "Access Denied"
start_time = request.args.get("start_time")
end_time = request.args.get("end_time")
raw_logs = sql.select_process_raw_log_by_time(int(start_time), int(end_time))
raw_logs = sql.select_process_raw_log_by_time(
int(start_time), int(end_time))
threat_data = log.process_raw_log(raw_logs)
return {"data": threat_data}
@@ -157,6 +214,7 @@ if __name__ == "__main__":
plugin.reload_plugs()
sql.init()
rule.init_rule()
hash_white_list.synchronization_white_list()
# 如果你觉得日志太多了,去掉这个注释...
flask_log = logging.getLogger("werkzeug")

View File

@@ -2,7 +2,7 @@
<q-layout view="lHh Lpr lFf" style="background-color: rgb(239, 243, 246)">
<q-header elevated height-hint="98">
<q-toolbar class="text-primary bg-white">
<q-toolbar-title> DuckSysEye内部测试版本v0.0.0.1 </q-toolbar-title>
<q-toolbar-title> RmEye内部测试版本v0.0.0.1 </q-toolbar-title>
<q-btn flat round dense icon="more_vert"></q-btn>
</q-toolbar>
</q-header>
@@ -77,23 +77,21 @@
</q-item-section>
<q-item-section> 已忽略威胁列表 </q-item-section>
</q-item>
<template v-for="(item, index) in plugin" v-bind:key="index">
<q-item
:active="selectLabel == item['name']"
clickable
v-ripple
active-class="menu-active"
@click="
selectLabel = item['name'];
routerToPlugin(item['html']);
"
>
<q-item-section avatar>
<q-icon :name="item['icon']" />
</q-item-section>
<q-item-section> {{ item["name"] }} </q-item-section>
</q-item>
</template>
<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>
@@ -116,7 +114,9 @@ import { defineComponent } from 'vue'
import HtmlPanel from '../components/Html.vue' // 根据实际路径导入
import axios from 'axios'
export default defineComponent({
components: { HtmlPanel },
components: {
HtmlPanel
},
name: 'MainLayout',
setup () {
return {}
@@ -132,9 +132,20 @@ export default defineComponent({
}
},
methods: {
routerToWhiteList () {
this.isInPlugin = false
this.$router.push({
name: 'whitelist'
})
},
routerToThreatList (index) {
this.isInPlugin = false
this.$router.push({ name: 'index', params: { queryIndex: index } })
this.$router.push({
name: 'index',
params: {
queryIndex: index
}
})
},
routerToPlugin (url) {
this.isInPlugin = true

View File

@@ -1,203 +1,184 @@
<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">{{
<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>
<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="col"></div>
<div class="col">
<div class="row q-gutter-md q-mb-sm q-pa-lg">
<q-timeline layout="dense" side="right" color="red">
<template
v-if="!server_threat.data || server_threat.data.length == 0"
>
<h4>暂无可用数据,下次刷新时间 {{last_refresh}}...</h4>
</template>
<template
v-for="(threat, index) in server_threat.data"
:key="index"
>
<q-timeline-entry :subtitle="'主机:' + threat.host" side="left">
<div>
<q-card
flat
bordered
style="overflow: auto"
:thumb-style="thumbStyle"
:bar-style="barStyle"
>
<q-card-section horizontal>
<div class="bg-red-5">&nbsp;</div>
<q-card-actions vertical class="justify-around q-px-md">
<div>进程链hash: {{ threat.chain_hash }}</div>
<div>进程: {{ threat.start_process.path }}</div>
<div>用户: {{ threat.start_process.user }}</div>
<div>
分数:
<q-chip
square
color="orange"
text-color="white"
icon-right="visibility"
>
{{ threat.risk_score }}
</q-chip>
</div>
<div>
活动状态:
<q-chip
square
:color="threat.is_end == 1 ? 'negative' : 'red'"
text-color="white"
>
{{ threat.is_end == 1 ? "已结束" : "进行中" }}
</q-chip>
</div>
<div>
产生的威胁:
<template
v-for="(index, operation) in threat.hit_rule"
:key="index"
>
<q-chip square color="rgb(239,243,246)">
{{ operation }}&nbsp;({{ index }})
</q-chip>
</template>
</div>
<div>
<q-btn
flat
color="accent"
@click="show_details(threat.id)"
icon="open_in_new"
>
查看详情
</q-btn>
<q-btn
flat
color="accent"
@click="search_vt(threat.start_process.hash)"
icon="search"
>
在VT上搜索
</q-btn>
<q-btn
flat
color="accent"
@click="handle_threat(threat.id, 1)"
icon="done"
>
确认威胁
</q-btn>
<q-btn
flat
color="accent"
@click="handle_threat(threat.id, 2)"
icon="texture"
>
忽略威胁
</q-btn>
<q-btn
flat
color="accent"
icon="close"
@click="delete_threat(threat.id)"
>
删除报警
</q-btn>
</div>
</q-card-actions>
</q-card-section>
</q-card>
</div>
</q-timeline-entry>
</template>
</q-timeline>
<div class="col"></div>
<div class="col">
<div class="row q-gutter-md q-mb-sm q-pa-lg">
<q-timeline layout="dense" side="right" color="red">
<template v-if="!server_threat.data || server_threat.data.length == 0">
<h4>暂无可用数据,下次刷新时间 {{last_refresh}}...</h4>
</template>
<template v-for="(threat, index) in server_threat.data" :key="index">
<q-timeline-entry :subtitle="'主机:' + threat.host" side="left">
<div>
<q-card flat bordered style="overflow: auto" :thumb-style="thumbStyle" :bar-style="barStyle">
<q-card-section horizontal>
<div class="bg-red-5">&nbsp;</div>
<q-card-actions vertical class="justify-around q-px-md">
<div>进程链hash: {{ threat.chain_hash }}</div>
<div>进程: {{ threat.start_process.path }}</div>
<div>用户: {{ threat.start_process.user }}</div>
<div>
分数:
<q-chip square color="orange" text-color="white" icon-right="visibility">
{{ threat.risk_score }}
</q-chip>
</div>
<div>
活动状态:
<q-chip square :color="threat.is_end == 1 ? 'negative' : 'red'" text-color="white">
{{ threat.is_end == 1 ? "已结束" : "进行中" }}
</q-chip>
</div>
<div>
产生的威胁:
<template v-for="(index, operation) in threat.hit_rule" :key="index">
<q-chip square color="rgb(239,243,246)">
{{ operation }}&nbsp;({{ index }})
</q-chip>
</template>
</div>
<div>
<q-btn flat color="accent" @click="show_details(threat.id)" icon="open_in_new">
查看详情
</q-btn>
<q-btn flat color="accent" @click="search_vt(threat.start_process.hash)" icon="search">
在VT上搜索
</q-btn>
<q-btn flat color="accent" @click="handle_threat(threat.id, 1)" icon="done">
确认威胁
</q-btn>
<q-btn flat color="accent" @click="handle_threat(threat.id, 2)" icon="texture">
忽略威胁
</q-btn>
<q-btn flat color="accent" icon="close" @click="delete_threat(threat.id)">
删除报警
</q-btn>
</div>
</q-card-actions>
</q-card-section>
</q-card>
</div>
</q-timeline-entry>
</template>
</q-timeline>
</div>
</div>
</div>
<div class="col"></div>
<div class="col"></div>
</div>
</div>
<q-dialog
v-model="dialog"
persistent
:maximized="maximizedToggle"
transition-show="slide-up"
transition-hide="slide-down"
>
<q-card class="text-white">
<q-bar>
<q-space></q-space>
<q-btn
dense
flat
icon="minimize"
@click="maximizedToggle = false"
:disable="!maximizedToggle"
>
<q-tooltip
v-if="maximizedToggle"
content-class="bg-white text-primary"
>Minimize</q-tooltip
>
</q-btn>
<q-btn
dense
flat
icon="crop_square"
@click="maximizedToggle = true"
:disable="maximizedToggle"
>
<q-tooltip
v-if="!maximizedToggle"
content-class="bg-white text-primary"
>Maximize</q-tooltip
>
</q-btn>
<q-btn dense flat icon="close" v-close-popup>
<q-tooltip content-class="bg-white text-primary">Close</q-tooltip>
</q-btn>
</q-bar>
<div class="row" style="width: 100%; height: 100%">
<div ref="main_draw" style="width: 100%; height: 100%; margin-left: 5%">
1
</div>
</div>
</div>
<q-dialog v-model="addwhiteListHash" persistent transition-show="scale" transition-hide="scale">
<q-card style="min-width: 350px">
<q-card-section>
<div class="text-h6">填写缘由</div>
</q-card-section>
<q-card-section class="q-pt-none">
<q-input dense v-model="this.whiteListPostData.reason" autofocus />
</q-card-section>
<q-card-actions align="right" class="text-primary">
<q-btn flat label="取消" @click="addwhiteListHash = false" v-close-popup />
<q-btn flat label="加入白名单" v-close-popup @click="add_to_white_hash_post()" />
</q-card-actions>
</q-card>
</q-dialog>
</q-dialog>
<q-dialog v-model="dialog" persistent :maximized="maximizedToggle" transition-show="slide-up" transition-hide="slide-down">
<q-card class="text-white">
<q-bar>
<q-space></q-space>
<q-btn dense flat icon="close" v-close-popup>
<q-tooltip content-class="bg-white text-primary">Close</q-tooltip>
</q-btn>
</q-bar>
<div class="row" style="width: 100%; height: 100%">
<div ref="main_draw" style="width: 100%; height: 100%; margin-left: 5%">
1
</div>
</div>
<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-item>
<q-item-section>活跃状态: {{processChainDetails.active ? "运行中" : "已结束"}}</q-item-section>
</q-item>
<q-separator />
<q-item>
<q-item-section>进程名字: {{processChainDetails.name}}</q-item-section>
</q-item>
<q-separator />
<q-item>
<q-item-section>进程路径: {{processChainDetails.path}}</q-item-section>
</q-item>
<q-separator />
<q-item>
<q-item-section>进程参数: {{processChainDetails.params}}</q-item-section>
</q-item>
<q-separator />
<q-item>
<q-item-section>进程id: {{processChainDetails.pid}}</q-item-section>
</q-item>
<q-separator />
<q-item>
<q-item-section>父进程id: {{processChainDetails.ppid}}</q-item-section>
</q-item>
<q-separator />
<q-item>
<q-item-section>进程hash: {{processChainDetails.md5}}</q-item-section>
</q-item>
<q-separator />
<q-item>
<q-item-section>是否在白名单中: {{processChainDetails.isWhite ? "是" : "否"}}</q-item-section>
</q-item>
<q-separator />
<q-item>
<q-item-section>进程命中的规则: <template v-for="(index, operation) in processChainDetails.hitRules" :key="index">
<q-chip square color="rgb(239,243,246)">
{{ operation }}&nbsp;({{ index }})
</q-chip>
</template></q-item-section>
</q-item>
<q-item>
<q-btn icon="search" outline style="color: grey;width: 100%;" label="搜索hash" @click="search_vt(processChainDetails.md5)" />
</q-item>
<q-item>
<template v-if="processChainDetails.isWhite == false">
<q-btn icon="texture" outline style="color: grey;width: 100%;" label="加入白名单" @click="add_to_white_hash_pre(processChainDetails.path,processChainDetails.md5)" />
</template>
<template v-else>
<q-btn icon="clear" outline style="color: grey;width: 100%;" label="从白名单中删除" @click="delete_white_hash(processChainDetails.md5)" />
</template>
</q-item>
</q-list>
</q-drawer>
</q-card>
</q-dialog>
</template>
<script>
import { defineComponent } from 'vue'
import {
defineComponent
} from 'vue'
import axios from 'axios'
import * as echarts from 'echarts'
@@ -205,7 +186,21 @@ export default defineComponent({
name: 'PageIndex',
data: function () {
return {
addwhiteListHash: false,
whiteListPostData: {
path: '',
hash: '',
reason: ''
},
processChainShowDetails: false,
last_refresh: 360,
processChainDetails: {
hash: '',
prams: '',
hitRule: [],
isWhite: false,
whiteListReason: ''
},
thumbStyle: {
right: '4px',
borderRadius: '5px',
@@ -226,37 +221,35 @@ export default defineComponent({
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'
}
],
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,
maximizedToggle: true,
server_threat: {},
@@ -264,6 +257,32 @@ export default defineComponent({
}
},
methods: {
delete_white_hash (hash) {
axios.get('/api/v1/del/white_list?hash=' + hash).then(res => {
this.processChainDetails.isWhite = false
})
},
query_white_hash (hash) {
axios.get('/api/v1/query/white_list?hash=' + hash).then(res => {
this.processChainDetails.isWhite = res.data.result === 1
})
},
add_to_white_hash_pre (path, hash) {
this.whiteListPostData = {
path: path,
hash: hash,
reason: ''
}
this.addwhiteListHash = true
console.log('addwhiteListHash', this.addwhiteListHash)
},
add_to_white_hash_post () {
axios
.post('/api/v1/set/white_list', this.whiteListPostData)
.then((response) => {
this.processChainDetails.isWhite = true
})
},
set_chain_data (data) {
if (data.path) {
const str = data.path.split('\\')
@@ -285,66 +304,79 @@ export default defineComponent({
formatter: function (params) {
const contextData = params.data
let result =
'<div>参数: ' +
contextData.params +
'</div>' +
'<div> hash: ' +
contextData.md5 +
'</div><div>命名规则列表: '
'<div>参数: ' +
contextData.params +
'</div>' +
'<div> hash: ' +
contextData.md5 +
'</div><div>命名规则列表: '
if (contextData.operationlist.length === 0) {
result += '无'
}
for (const key in contextData.operationlist) {
result +=
' ' + key + '[' + contextData.operationlist[key] + ']' + ' '
' ' + key + '[' + contextData.operationlist[key] + ']' + ' '
}
result += '</div>'
return result
}
},
series: [
{
roam: true,
type: 'tree',
id: 0,
name: 'tree1',
data: [this.select_chain_data],
top: '5%',
left: '15%',
bottom: '22%',
right: '20%',
edgeShape: 'polyline',
edgeForkPosition: '63%',
initialTreeDepth: 60,
lineStyle: {
width: 2
},
series: [{
roam: true,
type: 'tree',
id: 0,
name: 'tree1',
data: [this.select_chain_data],
top: '5%',
left: '15%',
bottom: '22%',
right: '20%',
edgeShape: 'polyline',
edgeForkPosition: '63%',
initialTreeDepth: 60,
lineStyle: {
width: 2
},
label: {
backgroundColor: '#fff',
position: 'left',
verticalAlign: 'middle',
align: 'right'
},
leaves: {
label: {
backgroundColor: '#fff',
position: 'left',
position: 'right',
verticalAlign: 'middle',
align: 'right'
},
leaves: {
label: {
position: 'right',
verticalAlign: 'middle',
align: 'left'
}
},
emphasis: {
focus: 'descendant'
},
symbolSize: [40, 50], // 宽40 高50
symbol:
'image://data:image/png;base64,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',
expandAndCollapse: true,
animationDuration: 550,
animationDurationUpdate: 750
}
]
align: 'left'
}
},
emphasis: {
focus: 'descendant'
},
symbolSize: [30, 30], // 宽40 高50
symbol: 'image://data:image/png;base64,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',
expandAndCollapse: false,
animationDuration: 350,
animationDurationUpdate: 450
}]
}
myChart.setOption(option)
myChart.on('click', params => {
const data = params.data
this.processChainDetails = {
path: data.path,
active: data.active,
md5: data.md5,
name: data.name,
params: data.params,
pid: data.pid,
ppid: data.ppid,
hitRules: data.operationlist,
isWhite: false
}
this.query_white_hash(data.md5)
this.processChainShowDetails = true
})
},
search_vt (hash) {
window.open('https://www.virustotal.com/gui/search/' + hash, '_blank')

View File

@@ -0,0 +1,137 @@
<template>
<q-table
class="q-pa-lg"
:dense="$q.screen.lt.md"
title="白名单列表"
:columns="data_columns"
:rows="data_columns_data"
:loading="loading"
v-model:pagination="pagination"
@request="onRequest"
>
<template v-slot:body="props">
<q-tr :props="props">
<q-td key="path" :props="props">{{ props.row.path }}</q-td>
<q-td key="hash" :props="props">{{ props.row.hash }}</q-td>
<q-td key="reason" :props="props">{{ props.row.reason }}</q-td>
<q-td key="timestamp" :props="props">{{ time_parase(props.row.timestamp) }}</q-td>
<q-td key="action" :props="props">
<q-btn color="red" label="移除白名单" @click="delete_white_hash(props.row.hash)"/>
</q-td>
</q-tr>
</template>
</q-table>
</template>
<script>
import {
defineComponent
} from 'vue'
import axios from 'axios'
export default defineComponent({
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: false,
pagination: {
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 10,
rowsNumber: 10
}
}
},
mounted () {
this.onRequest({
pagination: this.pagination,
filter: undefined
})
},
methods: {
delete_white_hash (hash) {
axios.get('/api/v1/del/white_list?hash=' + hash).then(res => {
console.log('duck was gone')
})
},
time_parase (pTime) {
// shijianchuo是整数否则要parseInt转换
const add0 = m => {
return m < 10 ? '0' + m : m
}
const time = new Date(Number(pTime))
console.log('time', pTime)
const y = time.getFullYear()
const m = time.getMonth() + 1
const d = time.getDate()
const h = time.getHours()
const mm = time.getMinutes()
const s = time.getSeconds()
return (
y +
'-' +
add0(m) +
'-' +
add0(d) +
' ' +
add0(h) +
':' +
add0(mm) +
':' +
add0(s)
)
},
onRequest (props) {
this.data_columns_data = []
this.loading = true
const { page } = props.pagination
axios.get('/api/v1/query/white_list_all').then(response => {
const data = response.data.result
console.log(data)
for (let index = 0; index < data.length; index++) {
const element = data[index]
this.data_columns_data.push(element)
}
this.pagination.page = page
this.pagination.rowsNumber = this.data_columns_data.length
this.pagination.rowsPerPage = this.data_columns_data.length
this.loading = false
})
}
}
})
</script>

View File

@@ -12,7 +12,8 @@ const routes = [
component: () => import('layouts/MainLayout.vue'),
children: [
{ path: 'dashboard', component: () => import('pages/Dashboard.vue') },
{ path: 'index', name: 'index', component: () => import('pages/Index.vue') }
{ path: 'index', name: 'index', component: () => import('pages/Index.vue') },
{ path: 'index', name: 'whitelist', component: () => import('pages/Whitelist.vue') }
]
},
// Always leave this as last one,