Merge branch 'main' of https://github.com/RoomaSec/RmEye
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
|
import operator
|
||||||
|
|
||||||
import process
|
import process
|
||||||
import rule
|
import rule
|
||||||
@@ -193,3 +194,101 @@ def process_log(host, json_log, raw_log):
|
|||||||
if item.risk_score >= config.MAX_THREAT_SCORE:
|
if item.risk_score >= config.MAX_THREAT_SCORE:
|
||||||
item.print_process()
|
item.print_process()
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def process_raw_log(raw_logs: list) -> list:
|
||||||
|
return_data = []
|
||||||
|
process_chain_list = []
|
||||||
|
|
||||||
|
raw_logs.sort(key=operator.attrgetter("timestamp"))
|
||||||
|
|
||||||
|
def _get_process_chain(pid, host: str) -> process.ProcessChain:
|
||||||
|
for iter in process_chain_list:
|
||||||
|
chain_item: process.ProcessChain = iter
|
||||||
|
if chain_item.host != host:
|
||||||
|
continue
|
||||||
|
process_item = chain_item.find_process_by_pid(pid)
|
||||||
|
if process_item is not None:
|
||||||
|
return chain_item
|
||||||
|
return None
|
||||||
|
|
||||||
|
for log in raw_logs:
|
||||||
|
log: sql.raw_process_log = log
|
||||||
|
pid = log.pid
|
||||||
|
ppid = log.ppid
|
||||||
|
path = log.path
|
||||||
|
params = log.commandline
|
||||||
|
user = log.user
|
||||||
|
hash = log.hash
|
||||||
|
create_time = log.timestamp
|
||||||
|
host = log.host
|
||||||
|
current_process:process.Process = None
|
||||||
|
if path in process.skip_process_path :
|
||||||
|
continue
|
||||||
|
if log.action.lower() == "processcreate":
|
||||||
|
|
||||||
|
chain = _get_process_chain(pid, host)
|
||||||
|
if chain is not None:
|
||||||
|
parent_process = chain.find_process_by_pid(ppid)
|
||||||
|
else:
|
||||||
|
parent_process = None
|
||||||
|
|
||||||
|
if chain is None:
|
||||||
|
# build a process chain
|
||||||
|
current_process = process.Process(
|
||||||
|
pid, ppid, path, params, create_time, hash, user, host
|
||||||
|
)
|
||||||
|
chain = process.create_chain(current_process)
|
||||||
|
process_chain_list.append(chain)
|
||||||
|
else:
|
||||||
|
current_process = process.Process(
|
||||||
|
pid, ppid, path, params, create_time, hash, user, host
|
||||||
|
)
|
||||||
|
chain.add_process(current_process, ppid)
|
||||||
|
elif log.action.lower() == "processterminal":
|
||||||
|
chain = _get_process_chain(pid, host)
|
||||||
|
if chain is not None:
|
||||||
|
current_process = chain.find_process_by_pid(pid)
|
||||||
|
current_process.active = False
|
||||||
|
current_process.chain.terminate_count += 1
|
||||||
|
if (
|
||||||
|
current_process.chain.terminate_count
|
||||||
|
>= current_process.chain.active_count
|
||||||
|
):
|
||||||
|
current_process.chain.active = False
|
||||||
|
else:
|
||||||
|
# 不在指定时段内被创建的进程的结束事件
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
chain = _get_process_chain(pid, host)
|
||||||
|
if chain is None:
|
||||||
|
continue
|
||||||
|
current_process = chain.find_process_by_pid(pid)
|
||||||
|
if current_process is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# if current_process is None :
|
||||||
|
# breakpoint()
|
||||||
|
start_process = current_process.chain.root_process
|
||||||
|
start_process_info = {
|
||||||
|
"path": start_process.path,
|
||||||
|
"hash": start_process.md5,
|
||||||
|
"params": start_process.params,
|
||||||
|
"user": start_process.user,
|
||||||
|
"create_time": start_process.time,
|
||||||
|
}
|
||||||
|
return_data.append(
|
||||||
|
{
|
||||||
|
"host": current_process.host,
|
||||||
|
"chain_hash": current_process.chain.hash,
|
||||||
|
"hit_rule": log.hit,
|
||||||
|
"time": log.timestamp,
|
||||||
|
"type": log.type,
|
||||||
|
"risk_score": log.score,
|
||||||
|
"id": log.id,
|
||||||
|
"is_end": current_process.chain.active == False,
|
||||||
|
"start_process": start_process_info,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return return_data
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from sqlalchemy import Column, Integer, String, Table
|
|||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker
|
||||||
from sqlalchemy import delete
|
from sqlalchemy import delete
|
||||||
|
import sqlalchemy
|
||||||
import json
|
import json
|
||||||
|
|
||||||
g_engine = None
|
g_engine = None
|
||||||
@@ -166,18 +167,20 @@ def push_process_raw(
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def select_create_process_raw_log_by_time(start, end):
|
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)
|
||||||
|
# 用g_rawdata_table 不行, utf8编码问题?
|
||||||
raw_log = (
|
raw_log = (
|
||||||
sql_session()
|
sql_session()
|
||||||
.query(g_rawdata_table)
|
.query(raw_process_log)
|
||||||
.filter(
|
.filter(
|
||||||
raw_process_log.timestamp >= start,
|
sqlalchemy.and_(
|
||||||
raw_process_log.timestamp < end,
|
raw_process_log.timestamp >= start, raw_process_log.timestamp < end
|
||||||
raw_process_log.action == "processcreate",
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
sql_session().close()
|
sql_session().close()
|
||||||
return raw_log
|
return raw_log
|
||||||
|
|||||||
@@ -8,144 +8,157 @@ import config
|
|||||||
from flask import Flask, render_template, request
|
from flask import Flask, render_template, request
|
||||||
import plugin
|
import plugin
|
||||||
import logging
|
import logging
|
||||||
app = Flask(__name__,
|
|
||||||
|
app = Flask(
|
||||||
|
__name__,
|
||||||
template_folder="./templates",
|
template_folder="./templates",
|
||||||
static_folder="./templates",
|
static_folder="./templates",
|
||||||
static_url_path="")
|
static_url_path="",
|
||||||
app.jinja_env.variable_start_string = '{.<'
|
)
|
||||||
app.jinja_env.variable_end_string = '>.}'
|
app.jinja_env.variable_start_string = "{.<"
|
||||||
|
app.jinja_env.variable_end_string = ">.}"
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route("/")
|
||||||
def root():
|
def root():
|
||||||
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"
|
||||||
return render_template("index.html")
|
return render_template("index.html")
|
||||||
|
|
||||||
|
|
||||||
@app.route('/static/<path:path>')
|
@app.route("/static/<path:path>")
|
||||||
def on_vue_static(path):
|
def on_vue_static(path):
|
||||||
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"
|
||||||
return app.send_static_file("./" + path)
|
return app.send_static_file("./" + path)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/plugin/<path:path>')
|
@app.route("/plugin/<path:path>")
|
||||||
def on_plugin_access(path):
|
def on_plugin_access(path):
|
||||||
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"
|
||||||
return plugin.dispath_html_draw(path)
|
return plugin.dispath_html_draw(path)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/v1/get/plugin_menu')
|
@app.route("/api/v1/get/plugin_menu")
|
||||||
def plugin_menu():
|
def plugin_menu():
|
||||||
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"
|
||||||
return {'data': {'menu': plugin.dispath_html_menu()}}
|
return {"data": {"menu": plugin.dispath_html_menu()}}
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/v1/get/threat_statistics', methods=['GET'])
|
@app.route("/api/v1/get/threat_statistics", methods=["GET"])
|
||||||
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啥的还不如自己查出来自己统计
|
# sqlite的count啥的还不如自己查出来自己统计
|
||||||
threat_datas = sql.query_all_threat_log(-1)
|
threat_datas = sql.query_all_threat_log(-1)
|
||||||
return_data = {
|
return_data = {"all": len(threat_datas), "confirm": 0, "ingore": 0, "working": 0}
|
||||||
'all': len(threat_datas),
|
|
||||||
'confirm': 0,
|
|
||||||
'ingore': 0,
|
|
||||||
'working': 0
|
|
||||||
}
|
|
||||||
for iter in threat_datas:
|
for iter in threat_datas:
|
||||||
if iter[9] == 1:
|
if iter[9] == 1:
|
||||||
return_data['confirm'] += 1
|
return_data["confirm"] += 1
|
||||||
elif iter[9] == 2:
|
elif iter[9] == 2:
|
||||||
return_data['ingore'] += 1
|
return_data["ingore"] += 1
|
||||||
if iter[7] == 0:
|
if iter[7] == 0:
|
||||||
return_data['working'] += 1
|
return_data["working"] += 1
|
||||||
return {'data': return_data}
|
return {"data": return_data}
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/v1/get/process_chain/handle', methods=['GET'])
|
@app.route("/api/v1/get/process_chain/handle", methods=["GET"])
|
||||||
def handle_chain_data():
|
def handle_chain_data():
|
||||||
id = request.args.get('id')
|
id = request.args.get("id")
|
||||||
handletype = request.args.get('handletype')
|
handletype = request.args.get("handletype")
|
||||||
if request.remote_addr not in config.ALLOW_ACCESS_IP or (id is None or handletype is None):
|
if request.remote_addr not in config.ALLOW_ACCESS_IP or (
|
||||||
|
id is None or handletype is None
|
||||||
|
):
|
||||||
return "Access Denied"
|
return "Access Denied"
|
||||||
sql.handle_threat_log(id, handletype)
|
sql.handle_threat_log(id, handletype)
|
||||||
return {'data': {'success': 1}}
|
return {"data": {"success": 1}}
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/v1/get/process_chain/delete', methods=['GET'])
|
@app.route("/api/v1/get/process_chain/delete", methods=["GET"])
|
||||||
def delete_chain_data():
|
def delete_chain_data():
|
||||||
id = request.args.get('id')
|
id = request.args.get("id")
|
||||||
if request.remote_addr not in config.ALLOW_ACCESS_IP or id is None:
|
if request.remote_addr not in config.ALLOW_ACCESS_IP or id is None:
|
||||||
return "Access Denied"
|
return "Access Denied"
|
||||||
sql.delete_threat(id)
|
sql.delete_threat(id)
|
||||||
return {'data': {'success': 1}}
|
return {"data": {"success": 1}}
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/v1/get/process_chain/pull', methods=['GET'])
|
@app.route("/api/v1/get/process_chain/pull", methods=["GET"])
|
||||||
def pull_chain_data():
|
def pull_chain_data():
|
||||||
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"
|
||||||
id = request.args.get('id')
|
id = request.args.get("id")
|
||||||
return_data = {}
|
return_data = {}
|
||||||
if id is not None:
|
if id is not None:
|
||||||
threat_data = sql.query_one_threat(id)
|
threat_data = sql.query_one_threat(id)
|
||||||
return_data = {
|
return_data = {
|
||||||
'host': threat_data[1],
|
"host": threat_data[1],
|
||||||
'chain_hash': threat_data[2],
|
"chain_hash": threat_data[2],
|
||||||
'type': threat_data[3],
|
"type": threat_data[3],
|
||||||
'risk_score': threat_data[4],
|
"risk_score": threat_data[4],
|
||||||
'hit_rule': json.loads(threat_data[5]),
|
"hit_rule": json.loads(threat_data[5]),
|
||||||
'chain': json.loads(threat_data[6]),
|
"chain": json.loads(threat_data[6]),
|
||||||
'is_end': threat_data[7]
|
"is_end": threat_data[7],
|
||||||
}
|
}
|
||||||
return {'data': return_data}
|
return {"data": return_data}
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/v1/get/process_chain/all')
|
@app.route("/api/v1/get/process_chain/all")
|
||||||
def process_chain():
|
def process_chain():
|
||||||
# -1全部 0未处理的 1处理的 2忽略的
|
# -1全部 0未处理的 1处理的 2忽略的
|
||||||
query_type = request.args.get('query_type')
|
query_type = request.args.get("query_type")
|
||||||
if request.remote_addr not in config.ALLOW_ACCESS_IP or query_type is None:
|
if request.remote_addr not in config.ALLOW_ACCESS_IP or query_type is None:
|
||||||
return "Access Denied"
|
return "Access Denied"
|
||||||
threat_datas = sql.query_all_threat_log(query_type)
|
threat_datas = sql.query_all_threat_log(query_type)
|
||||||
return_data = []
|
return_data = []
|
||||||
for iter in threat_datas:
|
for iter in threat_datas:
|
||||||
return_data.append({
|
return_data.append(
|
||||||
'host': iter[0],
|
{
|
||||||
'chain_hash': iter[1],
|
"host": iter[0],
|
||||||
'hit_rule': json.loads(iter[2]),
|
"chain_hash": iter[1],
|
||||||
'time': iter[3],
|
"hit_rule": json.loads(iter[2]),
|
||||||
'type': iter[4],
|
"time": iter[3],
|
||||||
'risk_score': iter[5],
|
"type": iter[4],
|
||||||
'id': iter[6],
|
"risk_score": iter[5],
|
||||||
'is_end': iter[7],
|
"id": iter[6],
|
||||||
'start_process': json.loads(iter[8]),
|
"is_end": iter[7],
|
||||||
})
|
"start_process": json.loads(iter[8]),
|
||||||
return {'data': return_data}
|
}
|
||||||
|
)
|
||||||
|
return {"data": return_data}
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/v1/process', methods=['POST'])
|
@app.route("/api/v1/process", methods=["POST"])
|
||||||
def process():
|
def process():
|
||||||
if request.method == 'POST':
|
if request.method == "POST":
|
||||||
# print(request.data)
|
# print(request.data)
|
||||||
body_data = request.data.decode()
|
body_data = request.data.decode()
|
||||||
# 转小写
|
# 转小写
|
||||||
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)
|
||||||
|
|
||||||
return {'status': 'success'}
|
return {"status": "success"}
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
@app.route("/api/v1/log_hunt", methods=["POST"])
|
||||||
|
def log_rescan():
|
||||||
|
if request.remote_addr not in config.ALLOW_ACCESS_IP:
|
||||||
|
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))
|
||||||
|
threat_data = log.process_raw_log(raw_logs)
|
||||||
|
return {"data": threat_data}
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
plugin.reload_plugs()
|
plugin.reload_plugs()
|
||||||
sql.init()
|
sql.init()
|
||||||
rule.init_rule()
|
rule.init_rule()
|
||||||
|
|
||||||
# 如果你觉得日志太多了,去掉这个注释...
|
# 如果你觉得日志太多了,去掉这个注释...
|
||||||
flask_log = logging.getLogger('werkzeug')
|
flask_log = logging.getLogger("werkzeug")
|
||||||
flask_log.setLevel(logging.ERROR)
|
flask_log.setLevel(logging.ERROR)
|
||||||
app.run(debug=True, host="0.0.0.0")
|
app.run(debug=True, host="0.0.0.0")
|
||||||
|
|||||||
Reference in New Issue
Block a user