一次opencanary自定义实践
自定义修改模块
opencanary 是一个pyhton开发的开源的蜜罐系统。
github地址在: https://github.com/thinkst/opencanary。完成了常用的蜜罐捕获请求。但是,固有的opencanary 存在如下的问题:
只监听一个IP 日志存储到本地,无法外发 iptables 产生的数据存储到固定文件,无法进一步处理。 部署节点状态无法统一管理
针对以上的问题,对opencanry 完成了相关的自定义化操作。接下来挨个详述各个问题的解决办法。
监听多个IP
通过网卡的trunk 技术在本机上配置相应的子接口,可以让一个服务器包含多个不同网段的IP。一个支持trunk的网卡配置如下:
VLAN=yes
TYPE=vlan
DEVICE=eth0.1001
PHYSDEV=eth0
VLAN_ID=1001
REORDED_HDR=0
BOOTPROTO=static
NAME=eth0.1001
ONBOOT=yes
IPADDR=10.211.1.10
NETMASK=255.255.255.0
这样,同一台服务器就监听了多个IP地址。
通过opencanaryd —copyconfig 生成的配置文件中,修改 device.listen_addr 对应的配置项为 0.0.0.0 既可以完成所有地址的监听。
自定义日志处理器,外发报警日志
默认的日志处理文件在 opencanry/logger.py 中定义, 默认使用的 PyLogger 类的实现,我们只需要修改 该类的 log 方法即可, 修改逻辑如下:
def post2server(self, serverip, jsondata):
try:
import urllib2
url = 'http://'+serverip+'/log/'
req = urllib2.Request(url, jsondata, {'Content-Type':'application/json'})
f = urllib2.urlopen(req)
response = f.read()
self.logger.warn(response)
f.close()
except urllib2.URLError, e:
self.logger.error(e)
def log(self, logdata, retry=True):
logdata = self.sanitizeLog(logdata)
jsondata = json.dumps(logdata, sort_keys=True)
serverip = "10.210.245.22" # 日志服务器的地址
if logdata['src_host']!='127.0.0.1' and logdata['dst_host']!='':
import uuid
scheduler = TwistedScheduler()
scheduler.add_job(self.post2server, args=[serverip, jsondata], id=str(uuid.uuid1()))
scheduler.start()
elif logdata['src_host']!='127.0.0.1':
self.logger.warn(jsondata)
iptables 日志二次处理
默认的 iptables 产生的日志,通过rsyslog 存储在 /var/log/kern.log 中,通过FileSystemWatcher 完成相应的处理。某些环境下,FileSystemWatcher 依赖于 系统的 fsnotify 模块 偶尔不能正常工作。
通过配置rsylsog 的 转发配置,转发到本地监听的syslog 服务,完成iptables 日志的二次处理。
配置如下:
50i kern.* @127.0.0.1:7788
然后,本地在 7788 端口启动一个 syslog 服务完成相应的处理即可。
canaryLogger = logging.getLogger()
LOG_HOST = "127.0.0.1"
LOG_PORT = 7788
class SyslogHandler(SocketServer.BaseRequestHandler):
def handle(self):
addr = self.client_address
data = self.request[0]
self.handleLine(data)
def handleLine(self, line):
global canaryLogger
self.logger = canaryLogger
try:
if 'canaryfw: ' in line:
logtype = self.logger.LOG_PORT_SYN
(rubbish, log) = line.split('canaryfw: ')
elif "canarynmapNULL" in line:
logtype = self.logger.LOG_PORT_NMAPNULL
(rubbish, log) = line.split('canarynmapNULL: ')
elif "canarynmapXMAS" in line:
logtype = self.logger.LOG_PORT_NMAPXMAS
(rubbish, log) = line.split('canarynmapXMAS: ')
elif "canarynmapFIN" in line:
logtype = self.logger.LOG_PORT_NMAPFIN
(rubbish, log) = line.split('canarynmapFIN: ')
elif 'canarynmap: ' in line:
logtype = self.logger.LOG_PORT_NMAPOS
(rubbish, log) = line.split('canarynmap: ')
except ValueError:
return
tags = log.split(' ')
kv = {}
for tag in tags:
if tag.find('=') >= 0:
(key, val) = tag.split('=')
else:
key = tag
val = ''
kv[key] = val
try:
kv.pop('')
except:
pass
data = {}
data['src_host'] = kv.pop('SRC')
data['src_port'] = kv.pop('SPT')
data['dst_host'] = kv.pop('DST')
data['dst_port'] = kv.pop('DPT')
data['logtype'] = logtype
data['logdata'] = kv
canaryLogger.log(data)
class LogCollect:
def start(self, logger):
global canaryLogger
canaryLogger = logger
logging.basicConfig(
level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S')
try:
logging.debug("slog start at %s : %d ", LOG_HOST, LOG_PORT)
server = SocketServer.ThreadingUDPServer(
(LOG_HOST, LOG_PORT), SyslogHandler)
server.allow_reuse_address = True
#server.request_queue_size = 60
server.serve_forever(poll_interval=0.5)
except Exception as ex:
logging.debug("error start , exit .....")
except KeyboardInterrupt:
print ("Crtl+C Pressed. Shutting down.")
添加自定义模块收集服务器信息,发送到中心服务器
# coding=utf-8
# /usr/lib/python2.7/site-packages/opencanary/modules/host.py
from opencanary.modules import CanaryService
from twisted.internet import reactor
from datetime import datetime
from apscheduler.schedulers.twisted import TwistedScheduler
import psutil
import os
import json
class CanaryHost(CanaryService):
NAME = "host"
def __init__(self, config=None, logger=None):
CanaryService.__init__(self, config, logger)
self.hostname = config.getVal('device.node_id')
self.localip = config.getVal('device.listen_addr')
self.serverip = config.getVal('server.ip')
self.last_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
self.status = "online"
self.logtype = logger.LOG_HOST
def hoststatus(self):
hostjson = json.dumps({
"lasttime": datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"),
"hostname": self.hostname,
"ip": self.localip,
"status": self.status,
"bindIp": self.bindIp()
})
try:
import urllib2
url = 'http://' + self.serverip + '/host/'
req = urllib2.Request(
url, hostjson, {'Content-Type': 'application/json'})
f = urllib2.urlopen(req)
response = f.read()
f.close()
except urllib2.URLError, e:
e = {"Hoststatus urllib2 Error:": str(e)}
self.logger.error(e)
def bindIp(self):
netcard_info = []
info = psutil.net_if_addrs()
for k, v in info.items():
for item in v:
if item[0] == 2 and item[1] != '127.0.0.1':
netcard_info.append({
"name": str(k),
"ip": str(item[1])
})
return json.dumps(netcard_info)
def startYourEngines(self):
sched = TwistedScheduler()
sched.start()
if not sched.get_job('host_status'):
sched.add_job(self.hoststatus, 'interval',
seconds=10, id='host_status')
CanaryServiceFactory = CanaryHost
- 机器学习算法GBDT的面试要点总结
- 了解、接受和利用Java中的Optional (类)
- 一个强化学习 Q-learning 算法的简明教程
- 天池大赛—商场中精确定位用户所在店铺 作品分享
- 代码实战:从单体式应用到微服务的低风险演变
- 数据转换:从单体式应用到微服务的低风险演变
- JDK8 stream toMap() java.lang.IllegalStateException: Duplicate key异常解决(key重复)
- 如约而至,Java 10 正式发布!
- Intellij IDEA查看所有断点
- Spring Boot国际化支持
- 有记忆会推理的可微分神经计算机,DeepMind现在开源了代码
- Spring Boot整合Thymeleaf模板引擎
- Spring Boot实现热部署
- Java中的宏变量,宏替换详解。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法