Cyril CONSTANTIN 4 weeks ago
parent
commit
30a02da435
  1. 39
      check_host.sh
  2. 18
      dnscap.service
  3. 41
      log.nft
  4. 89
      report.py

39
check_host.sh

@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
#!/usr/bin/env bash
if ! sudo which nft
then
echo "install nftables"
exit 1
fi
if ! sudo nft list ruleset |grep output
then
sudo nft -f log.nft
fi
if ! sudo nft list ruleset |grep output
then
echo "nft error"
exit 1
fi
if ! id | grep systemd-journal
then
echo "sudo adduser $(whoami) systemd-journal"
sudo adduser "$(whoami)" systemd-journal
exit 1
fi
packages="python3-systemd python3-tabulate python3-dns dnscap python3-pure-pcapy3 tshark"
apt -s install "${packages}"
echo "apt-get -s ${packages}"
if apt-get -s install "${packages}" |grep ^Inst
then
echo "install python packages"
exit 1
fi
echo "####################"
echo "### System Ready "
echo "####################"

18
dnscap.service

@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
[Unit]
Description=Dnscap Daemon
After=network-online.target
[Service]
Type=simple
User=root
Group=root
UMask=007
ExecStart=/usr/bin/dnscap -b -o pid_file=/var/run/dnscap.pid -i any -p -w - -t 600 -k /usr/bin/tshark -r - -T json | /usr/local/bin/report.py
Restart=on-failure
# Configures the time to wait before service is stopped forcefully.
TimeoutStopSec=10
[Install]
WantedBy=multi-user.target

41
log.nft

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept
ct state established,related accept
# Log and drop invalid packets
ct state invalid log prefix "INVALID: " level warn drop
# Log and accept SSH
tcp dport 22 ct state new log prefix "SSH: " level info accept
# Allow web traffic (no logging to reduce volume)
#tcp dport { 80, 443 } accept
# Log everything else that reaches the end (default drop)
log prefix "INPUT DROP: " level warn
}
chain forward {
type filter hook forward priority 0; policy drop;
log prefix "FORWARD DROP: " level warn
}
chain output {
type filter hook output priority 0; policy accept;
# dns request
udp dport 53 log prefix "DNS:" level info
# accept local connection
ip daddr 192.168.122.1 counter accept
ip daddr 192.168.0.253 counter accept
ip daddr 192.168.0.254 counter accept
# counter output packets
counter comment "Count accepted packets"
# not logging established
ct state established,related accept
# Log and accept output packets
log prefix "OUTPUT:" level info flags skuid accept
}
}

89
report.py

@ -0,0 +1,89 @@ @@ -0,0 +1,89 @@
#!/usr/bin/env python3
from systemd import journal
from datetime import datetime, timedelta
import re # read lines
# Import smtplib for the actual sending function
import smtplib
# Import the email modules we'll need
from email.message import EmailMessage
from tabulate import tabulate
import os
import socket
import logging
import logging.config
import sys
import json
class connection:
def __init__(self,logger):
self.logger = logger
self.records = []
def __get_list(self):
liste = []
for e in self.records:
self.logger.debug("interface {} source {} destination {} proto {} dport {} uid {} gid {}".format(e['interface'],e['source'],e['destination'],e['proto'],e['dport'],e['uid'],e['gid']))
try:
self.logger.debug("--- ask reverse lookup for : {}".format(e['destination']))
domain, alias, addresslist = socket.gethostbyaddr(e['destination'])
except socket.herror as he:
self.logger.debug("--- can't resolv {}".format(e['destination']))
domain = 'unknown'
item = [ e['interface'], e['source'], e['destination'], e['proto'], e['dport'], e['uid'], e['gid'] , domain ]
if not item in liste:
liste.append(item)
self.logger.debug(liste)
return liste
def report(self):
headers = { 'Interface':'', 'Source':'', 'Destination':'', 'Protocol':'', 'DestinationPort':'', 'UID':'', 'GID':'' , 'domain':'' }
header = headers.keys()
msg = EmailMessage()
msg.set_content(tabulate(self.__get_list(),headers))
msg['Subject'] = f'[ssh][attempts] Reporting'
msg['From'] = "{}@{}".format(os.getlogin(),socket.gethostname())
msg['To'] = "{}@{}".format(os.getlogin(),'192.168.0.238')
print(msg)
#s = smtplib.SMTP('localhost')
#s.send_message(msg)
#s.quit()
def addmessage(self, message:str):
self.logger.debug("-- scan {}".format(message))
nftop = r'''^OUTPUT:IN= OUT=(?P<interface>[a-z0-9]+)[ ]SRC=(?P<source>[0-9.]+)[ ]DST=(?P<destination>[0-9.]+)[ ]LEN=([0-9]+)[ ]TOS=([0-9x]+)[ ]PREC=([0-9x]+)[ ]TTL=([0-9]+)[ ]ID=([0-9]+)[ ]DF[ ]PROTO=(?P<proto>[CDTUP]+)[ ]SPT=([0-9]+)[ ]DPT=(?P<dport>[0-9]+)[ ]WINDOW=([0-9]+)[ ]RES=([0-9x]+)[ ]SYN[ ]URGP=([0-9]+)[ ]UID=(?P<uid>[0-9]+)[ ]GID=(?P<gid>[0-9]+)[ ]+$'''
nftsp = r'''^SSH:[ ]IN=(?P<interface>[a-z0-9]+)[ ]OUT=[ ]MAC=(?P<gid>[0-9a-f:]+)[ ]SRC=(?P<source>[0-9.]+)[ ]DST=(?P<destination>[0-9.]+)[ ]LEN=([0-9]+)[ ]TOS=([0-9x]+)[ ]PREC=([0-9A-Fx]+)[ ]TTL=([0-9]+)[ ]ID=([0-9]+)[ ]DF[ ]PROTO=(?P<proto>[CDTUP]+)[ ]SPT=([0-9]+)[ ]DPT=(?P<dport>[0-9]+)[ ]WINDOW=([0-9]+)[ ]RES=([0-9x]+)[ ](SYN |ACK )(PSH |)URGP=(?P<uid>[0-9]+)[ ]+$'''
nftom = re.match(re.compile(nftop),message)
nftsm = re.match(re.compile(nftsp),message)
if nftom:
self.logger.debug("$$$ matched: {}".format(nftom))
self.records.append(nftom.groupdict())
elif nftsm:
self.logger.debug("$$$ matched: {}".format(nftsm))
self.records.append(nftsm.groupdict())
# initiate
logging.basicConfig(filename='/tmp/outlog_reporting.log',level=logging.DEBUG)
logger=logging.getLogger(__name__)
c = connection(logger)
# read from dnscap
try:
queries = []
js = json.load(sys.stdin)
logger.debug("Json : {}".format(js))
for request in js:
for k,v in request['_source']['layers']['dns']['Queries'].items():
query = v['dns.qry.name']
logger.debug("query: {}".format(query))
queries.append(query)
logger.debug("queries: {}".format(queries))
except json.decoder.JSONDecodeError as jde:
logger.warning("No json found as input")
# read logs from kernel journal
j = journal.Reader()
j.seek_realtime(datetime.now() - timedelta(hours=1))
j.add_match('_TRANSPORT=kernel')
for entry in j:
logger.debug(entry['MESSAGE'])
c.addmessage(entry['MESSAGE'])
logger.debug("--- Generating report")
c.report()
Loading…
Cancel
Save