mirror of
https://github.com/Security-Onion-Solutions/securityonion.git
synced 2026-02-21 22:45:27 +01:00
Merge remote-tracking branch 'remotes/origin/dev' into delta
This commit is contained in:
@@ -9,6 +9,11 @@ rmvariablesfile:
|
||||
file.absent:
|
||||
- name: /tmp/variables.txt
|
||||
|
||||
dockergroup:
|
||||
group.present:
|
||||
- name: docker
|
||||
- gid: 920
|
||||
|
||||
# Add socore Group
|
||||
socoregroup:
|
||||
group.present:
|
||||
@@ -101,6 +106,7 @@ commonpkgs:
|
||||
- python3-m2crypto
|
||||
- python3-mysqldb
|
||||
- python3-packaging
|
||||
- python3-lxml
|
||||
- git
|
||||
- vim
|
||||
|
||||
@@ -143,6 +149,7 @@ commonpkgs:
|
||||
- python36-m2crypto
|
||||
- python36-mysql
|
||||
- python36-packaging
|
||||
- python36-lxml
|
||||
- yum-utils
|
||||
- device-mapper-persistent-data
|
||||
- lvm2
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||
#
|
||||
@@ -15,152 +15,199 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
. /usr/sbin/so-common
|
||||
import ipaddress
|
||||
import textwrap
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import argparse
|
||||
import re
|
||||
from lxml import etree as ET
|
||||
from xml.dom import minidom
|
||||
from datetime import datetime as dt
|
||||
from datetime import timezone as tz
|
||||
|
||||
local_salt_dir=/opt/so/saltstack/local
|
||||
|
||||
SKIP=0
|
||||
|
||||
function usage {
|
||||
|
||||
cat << EOF
|
||||
|
||||
Usage: $0 [-abefhoprsw] [ -i IP ]
|
||||
|
||||
This program allows you to add a firewall rule to allow connections from a new IP address or CIDR range.
|
||||
|
||||
If you run this program with no arguments, it will present a menu for you to choose your options.
|
||||
|
||||
If you want to automate and skip the menu, you can pass the desired options as command line arguments.
|
||||
|
||||
EXAMPLES
|
||||
|
||||
To add 10.1.2.3 to the analyst role:
|
||||
so-allow -a -i 10.1.2.3
|
||||
|
||||
To add 10.1.2.0/24 to the osquery role:
|
||||
so-allow -o -i 10.1.2.0/24
|
||||
|
||||
EOF
|
||||
|
||||
LOCAL_SALT_DIR='/opt/so/saltstack/local'
|
||||
WAZUH_CONF='/nsm/wazuh/etc/ossec.conf'
|
||||
VALID_ROLES = {
|
||||
'a': { 'role': 'analyst','desc': 'Analyst - 80/tcp, 443/tcp' },
|
||||
'b': { 'role': 'beats_endpoint', 'desc': 'Logstash Beat - 5044/tcp' },
|
||||
'e': { 'role': 'elasticsearch_rest', 'desc': 'Elasticsearch REST API - 9200/tcp' },
|
||||
'f': { 'role': 'strelka_frontend', 'desc': 'Strelka frontend - 57314/tcp' },
|
||||
'o': { 'role': 'osquery_endpoint', 'desc': 'Osquery endpoint - 8090/tcp' },
|
||||
's': { 'role': 'syslog', 'desc': 'Syslog device - 514/tcp/udp' },
|
||||
'w': { 'role': 'wazuh_agent', 'desc': 'Wazuh agent - 1514/tcp/udp' },
|
||||
'p': { 'role': 'wazuh_api', 'desc': 'Wazuh API - 55000/tcp' },
|
||||
'r': { 'role': 'wazuh_authd', 'desc': 'Wazuh registration service - 1515/tcp' }
|
||||
}
|
||||
|
||||
while getopts "ahfesprbowi:" OPTION
|
||||
do
|
||||
case $OPTION in
|
||||
h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
a)
|
||||
FULLROLE="analyst"
|
||||
SKIP=1
|
||||
;;
|
||||
b)
|
||||
FULLROLE="beats_endpoint"
|
||||
SKIP=1
|
||||
;;
|
||||
e)
|
||||
FULLROLE="elasticsearch_rest"
|
||||
SKIP=1
|
||||
;;
|
||||
f)
|
||||
FULLROLE="strelka_frontend"
|
||||
SKIP=1
|
||||
;;
|
||||
i) IP=$OPTARG
|
||||
;;
|
||||
o)
|
||||
FULLROLE="osquery_endpoint"
|
||||
SKIP=1
|
||||
;;
|
||||
w)
|
||||
FULLROLE="wazuh_agent"
|
||||
SKIP=1
|
||||
;;
|
||||
s)
|
||||
FULLROLE="syslog"
|
||||
SKIP=1
|
||||
;;
|
||||
p)
|
||||
FULLROLE="wazuh_api"
|
||||
SKIP=1
|
||||
;;
|
||||
r)
|
||||
FULLROLE="wazuh_authd"
|
||||
SKIP=1
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$SKIP" -eq 0 ]; then
|
||||
def validate_ip_cidr(ip_cidr: str) -> bool:
|
||||
try:
|
||||
ipaddress.ip_address(ip_cidr)
|
||||
except ValueError:
|
||||
try:
|
||||
ipaddress.ip_network(ip_cidr)
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
echo "This program allows you to add a firewall rule to allow connections from a new IP address."
|
||||
echo ""
|
||||
echo "Choose the role for the IP or Range you would like to add"
|
||||
echo ""
|
||||
echo "[a] - Analyst - ports 80/tcp and 443/tcp"
|
||||
echo "[b] - Logstash Beat - port 5044/tcp"
|
||||
echo "[e] - Elasticsearch REST API - port 9200/tcp"
|
||||
echo "[f] - Strelka frontend - port 57314/tcp"
|
||||
echo "[o] - Osquery endpoint - port 8090/tcp"
|
||||
echo "[s] - Syslog device - 514/tcp/udp"
|
||||
echo "[w] - Wazuh agent - port 1514/tcp/udp"
|
||||
echo "[p] - Wazuh API - port 55000/tcp"
|
||||
echo "[r] - Wazuh registration service - 1515/tcp"
|
||||
echo ""
|
||||
echo "Please enter your selection:"
|
||||
read -r ROLE
|
||||
echo "Enter a single ip address or range to allow (example: 10.10.10.10 or 10.10.0.0/16):"
|
||||
read -r IP
|
||||
|
||||
if [ "$ROLE" == "a" ]; then
|
||||
FULLROLE=analyst
|
||||
elif [ "$ROLE" == "b" ]; then
|
||||
FULLROLE=beats_endpoint
|
||||
elif [ "$ROLE" == "e" ]; then
|
||||
FULLROLE=elasticsearch_rest
|
||||
elif [ "$ROLE" == "f" ]; then
|
||||
FULLROLE=strelka_frontend
|
||||
elif [ "$ROLE" == "o" ]; then
|
||||
FULLROLE=osquery_endpoint
|
||||
elif [ "$ROLE" == "w" ]; then
|
||||
FULLROLE=wazuh_agent
|
||||
elif [ "$ROLE" == "s" ]; then
|
||||
FULLROLE=syslog
|
||||
elif [ "$ROLE" == "p" ]; then
|
||||
FULLROLE=wazuh_api
|
||||
elif [ "$ROLE" == "r" ]; then
|
||||
FULLROLE=wazuh_authd
|
||||
else
|
||||
echo "I don't recognize that role"
|
||||
exit 1
|
||||
fi
|
||||
def role_prompt() -> str:
|
||||
print()
|
||||
print('Choose the role for the IP or Range you would like to allow')
|
||||
print()
|
||||
for role in VALID_ROLES:
|
||||
print(f'[{role}] - {VALID_ROLES[role]["desc"]}')
|
||||
print()
|
||||
role = input('Please enter your selection: ')
|
||||
if role in VALID_ROLES.keys():
|
||||
return VALID_ROLES[role]['role']
|
||||
else:
|
||||
print(f'Invalid role \'{role}\', please try again.', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
fi
|
||||
def ip_prompt() -> str:
|
||||
ip = input('Enter a single ip address or range to allow (ex: 10.10.10.10 or 10.10.0.0/16): ')
|
||||
if validate_ip_cidr(ip):
|
||||
return ip
|
||||
else:
|
||||
print(f'Invalid IP address or CIDR block \'{ip}\', please try again.', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
echo "Adding $IP to the $FULLROLE role. This can take a few seconds"
|
||||
/usr/sbin/so-firewall includehost $FULLROLE $IP
|
||||
salt-call state.apply firewall queue=True
|
||||
|
||||
# Check if Wazuh enabled
|
||||
if grep -q -R "wazuh: 1" $local_salt_dir/pillar/*; then
|
||||
# If analyst, add to Wazuh AR whitelist
|
||||
if [ "$FULLROLE" == "analyst" ]; then
|
||||
WAZUH_MGR_CFG="/nsm/wazuh/etc/ossec.conf"
|
||||
if ! grep -q "<white_list>$IP</white_list>" $WAZUH_MGR_CFG ; then
|
||||
DATE=$(date)
|
||||
sed -i 's/<\/ossec_config>//' $WAZUH_MGR_CFG
|
||||
sed -i '/^$/N;/^\n$/D' $WAZUH_MGR_CFG
|
||||
echo -e "<!--Address $IP added by /usr/sbin/so-allow on \"$DATE\"-->\n <global>\n <white_list>$IP</white_list>\n </global>\n</ossec_config>" >> $WAZUH_MGR_CFG
|
||||
echo "Added whitelist entry for $IP in $WAZUH_MGR_CFG."
|
||||
echo
|
||||
echo "Restarting OSSEC Server..."
|
||||
/usr/sbin/so-wazuh-restart
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
def wazuh_enabled() -> bool:
|
||||
for file in os.listdir(f'{LOCAL_SALT_DIR}/pillar'):
|
||||
with open(file, 'r') as pillar:
|
||||
if 'wazuh: 1' in pillar.read():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def root_to_str(root: ET.ElementTree) -> str:
|
||||
xml_str = ET.tostring(root, encoding='unicode', method='xml').replace('\n', '')
|
||||
xml_str = re.sub(r'(?:(?<=>) *)', '', xml_str)
|
||||
xml_str = re.sub(r' -', '', xml_str)
|
||||
xml_str = re.sub(r' -->', ' -->', xml_str)
|
||||
dom = minidom.parseString(xml_str)
|
||||
return dom.toprettyxml(indent=" ")
|
||||
|
||||
|
||||
def add_wl(ip):
|
||||
parser = ET.XMLParser(remove_blank_text=True)
|
||||
with open(WAZUH_CONF, 'rb') as wazuh_conf:
|
||||
tree = ET.parse(wazuh_conf, parser)
|
||||
root = tree.getroot()
|
||||
|
||||
source_comment = ET.Comment(f'Address {ip} added by /usr/sbin/so-allow on {dt.utcnow().replace(tzinfo=tz.utc).strftime("%a %b %e %H:%M:%S %Z %Y")}')
|
||||
new_global = ET.Element("global")
|
||||
new_wl = ET.SubElement(new_global, 'white_list')
|
||||
new_wl.text = ip
|
||||
|
||||
root.append(source_comment)
|
||||
root.append(new_global)
|
||||
|
||||
with open(WAZUH_CONF, 'w') as add_out:
|
||||
add_out.write(root_to_str(root))
|
||||
|
||||
|
||||
def apply(role: str, ip: str) -> int:
|
||||
firewall_cmd = ['so-firewall', 'includehost', role, ip]
|
||||
salt_cmd = ['salt-call', 'state.apply', '-l', 'quiet', 'firewall', 'queue=True']
|
||||
restart_wazuh_cmd = ['so-wazuh-restart']
|
||||
print(f'Adding {ip} to the {role} role. This can take a few seconds...')
|
||||
cmd = subprocess.run(firewall_cmd)
|
||||
if cmd.returncode == 0:
|
||||
cmd = subprocess.run(salt_cmd, stdout=subprocess.DEVNULL)
|
||||
else:
|
||||
return cmd.returncode
|
||||
if cmd.returncode == 0:
|
||||
if wazuh_enabled and role=='analyst':
|
||||
try:
|
||||
add_wl(ip)
|
||||
print(f'Added whitelist entry for {ip} from {WAZUH_CONF}', file=sys.stderr)
|
||||
except Exception as e:
|
||||
print(f'Failed to add whitelist entry for {ip} from {WAZUH_CONF}', file=sys.stderr)
|
||||
print(e)
|
||||
return 1
|
||||
print('Restarting OSSEC Server...')
|
||||
cmd = subprocess.run(restart_wazuh_cmd)
|
||||
else:
|
||||
return cmd.returncode
|
||||
else:
|
||||
print(f'Commmand \'{" ".join(salt_cmd)}\' failed.', file=sys.stderr)
|
||||
return cmd.returncode
|
||||
if cmd.returncode != 0:
|
||||
print('Failed to restart OSSEC server.')
|
||||
return cmd.returncode
|
||||
|
||||
|
||||
def main():
|
||||
if os.geteuid() != 0:
|
||||
print('You must run this script as root', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
main_parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog=textwrap.dedent(f'''\
|
||||
additional information:
|
||||
To use this script in interactive mode call it with no arguments
|
||||
'''
|
||||
))
|
||||
|
||||
group = main_parser.add_argument_group(title='roles')
|
||||
group.add_argument('-a', dest='roles', action='append_const', const=VALID_ROLES['a']['role'], help="Analyst - 80/tcp, 443/tcp")
|
||||
group.add_argument('-b', dest='roles', action='append_const', const=VALID_ROLES['b']['role'], help="Logstash Beat - 5044/tcp")
|
||||
group.add_argument('-e', dest='roles', action='append_const', const=VALID_ROLES['e']['role'], help="Elasticsearch REST API - 9200/tcp")
|
||||
group.add_argument('-f', dest='roles', action='append_const', const=VALID_ROLES['f']['role'], help="Strelka frontend - 57314/tcp")
|
||||
group.add_argument('-o', dest='roles', action='append_const', const=VALID_ROLES['o']['role'], help="Osquery endpoint - 8090/tcp")
|
||||
group.add_argument('-s', dest='roles', action='append_const', const=VALID_ROLES['s']['role'], help="Syslog device - 514/tcp/udp")
|
||||
group.add_argument('-w', dest='roles', action='append_const', const=VALID_ROLES['w']['role'], help="Wazuh agent - 1514/tcp/udp")
|
||||
group.add_argument('-p', dest='roles', action='append_const', const=VALID_ROLES['p']['role'], help="Wazuh API - 55000/tcp")
|
||||
group.add_argument('-r', dest='roles', action='append_const', const=VALID_ROLES['r']['role'], help="Wazuh registration service - 1515/tcp")
|
||||
|
||||
ip_g = main_parser.add_argument_group(title='allow')
|
||||
ip_g.add_argument('-i', help="IP or CIDR block to disallow connections from, requires at least one role argument", metavar='', dest='ip')
|
||||
|
||||
args = main_parser.parse_args(sys.argv[1:])
|
||||
|
||||
if args.roles is None:
|
||||
role = role_prompt()
|
||||
ip = ip_prompt()
|
||||
try:
|
||||
return_code = apply(role, ip)
|
||||
except Exception as e:
|
||||
print(f'Unexpected exception occurred: {e}', file=sys.stderr)
|
||||
return_code = e.errno
|
||||
sys.exit(return_code)
|
||||
elif args.roles is not None and args.ip is None:
|
||||
if os.environ.get('IP') is None:
|
||||
main_parser.print_help()
|
||||
sys.exit(1)
|
||||
else:
|
||||
args.ip = os.environ['IP']
|
||||
|
||||
if validate_ip_cidr(args.ip):
|
||||
try:
|
||||
for role in args.roles:
|
||||
return_code = apply(role, args.ip)
|
||||
if return_code > 0:
|
||||
break
|
||||
except Exception as e:
|
||||
print(f'Unexpected exception occurred: {e}', file=sys.stderr)
|
||||
return_code = e.errno
|
||||
else:
|
||||
print(f'Invalid IP address or CIDR block \'{args.ip}\', please try again.', file=sys.stderr)
|
||||
return_code = 1
|
||||
|
||||
sys.exit(return_code)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
213
salt/common/tools/sbin/so-deny
Executable file
213
salt/common/tools/sbin/so-deny
Executable file
@@ -0,0 +1,213 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import ipaddress
|
||||
import textwrap
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import argparse
|
||||
import re
|
||||
from lxml import etree as ET
|
||||
from xml.dom import minidom
|
||||
|
||||
|
||||
LOCAL_SALT_DIR='/opt/so/saltstack/local'
|
||||
WAZUH_CONF='/nsm/wazuh/etc/ossec.conf'
|
||||
VALID_ROLES = {
|
||||
'a': { 'role': 'analyst','desc': 'Analyst - 80/tcp, 443/tcp' },
|
||||
'b': { 'role': 'beats_endpoint', 'desc': 'Logstash Beat - 5044/tcp' },
|
||||
'e': { 'role': 'elasticsearch_rest', 'desc': 'Elasticsearch REST API - 9200/tcp' },
|
||||
'f': { 'role': 'strelka_frontend', 'desc': 'Strelka frontend - 57314/tcp' },
|
||||
'o': { 'role': 'osquery_endpoint', 'desc': 'Osquery endpoint - 8090/tcp' },
|
||||
's': { 'role': 'syslog', 'desc': 'Syslog device - 514/tcp/udp' },
|
||||
'w': { 'role': 'wazuh_agent', 'desc': 'Wazuh agent - 1514/tcp/udp' },
|
||||
'p': { 'role': 'wazuh_api', 'desc': 'Wazuh API - 55000/tcp' },
|
||||
'r': { 'role': 'wazuh_authd', 'desc': 'Wazuh registration service - 1515/tcp' }
|
||||
}
|
||||
|
||||
|
||||
def validate_ip_cidr(ip_cidr: str) -> bool:
|
||||
try:
|
||||
ipaddress.ip_address(ip_cidr)
|
||||
except ValueError:
|
||||
try:
|
||||
ipaddress.ip_network(ip_cidr)
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def role_prompt() -> str:
|
||||
print()
|
||||
print('Choose the role for the IP or Range you would like to deny')
|
||||
print()
|
||||
for role in VALID_ROLES:
|
||||
print(f'[{role}] - {VALID_ROLES[role]["desc"]}')
|
||||
print()
|
||||
role = input('Please enter your selection: ')
|
||||
if role in VALID_ROLES.keys():
|
||||
return VALID_ROLES[role]['role']
|
||||
else:
|
||||
print(f'Invalid role \'{role}\', please try again.', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def ip_prompt() -> str:
|
||||
ip = input('Enter a single ip address or range to deny (ex: 10.10.10.10 or 10.10.0.0/16): ')
|
||||
if validate_ip_cidr(ip):
|
||||
return ip
|
||||
else:
|
||||
print(f'Invalid IP address or CIDR block \'{ip}\', please try again.', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def wazuh_enabled() -> bool:
|
||||
for file in os.listdir(f'{LOCAL_SALT_DIR}/pillar'):
|
||||
with open(file, 'r') as pillar:
|
||||
if 'wazuh: 1' in pillar.read():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def root_to_str(root: ET.ElementTree) -> str:
|
||||
xml_str = ET.tostring(root, encoding='unicode', method='xml').replace('\n', '')
|
||||
xml_str = re.sub(r'(?:(?<=>) *)', '', xml_str)
|
||||
|
||||
# Remove specific substrings to better format comments on intial parse/write
|
||||
xml_str = re.sub(r' -', '', xml_str)
|
||||
xml_str = re.sub(r' -->', ' -->', xml_str)
|
||||
|
||||
dom = minidom.parseString(xml_str)
|
||||
return dom.toprettyxml(indent=" ")
|
||||
|
||||
|
||||
def rem_wl(ip):
|
||||
parser = ET.XMLParser(remove_blank_text=True)
|
||||
with open(WAZUH_CONF, 'rb') as wazuh_conf:
|
||||
tree = ET.parse(wazuh_conf, parser)
|
||||
root = tree.getroot()
|
||||
|
||||
global_elems = root.findall(f"global/white_list[. = '{ip}']/..")
|
||||
if len(global_elems) > 0:
|
||||
for g_elem in global_elems:
|
||||
ge_index = list(root).index(g_elem)
|
||||
if ge_index > 0 and root[list(root).index(g_elem) - 1].tag == ET.Comment:
|
||||
root.remove(root[ge_index - 1])
|
||||
root.remove(g_elem)
|
||||
|
||||
with open(WAZUH_CONF, 'w') as out:
|
||||
out.write(root_to_str(root))
|
||||
|
||||
|
||||
def apply(role: str, ip: str) -> int:
|
||||
firewall_cmd = ['so-firewall', 'excludehost', role, ip]
|
||||
salt_cmd = ['salt-call', 'state.apply', '-l', 'quiet', 'firewall', 'queue=True']
|
||||
restart_wazuh_cmd = ['so-wazuh-restart']
|
||||
print(f'Removing {ip} from the {role} role. This can take a few seconds...')
|
||||
cmd = subprocess.run(firewall_cmd)
|
||||
if cmd.returncode == 0:
|
||||
cmd = subprocess.run(salt_cmd, stdout=subprocess.DEVNULL)
|
||||
else:
|
||||
return cmd.returncode
|
||||
if cmd.returncode == 0:
|
||||
if wazuh_enabled and role=='analyst':
|
||||
try:
|
||||
rem_wl(ip)
|
||||
print(f'Removed whitelist entry for {ip} from {WAZUH_CONF}', file=sys.stderr)
|
||||
except Exception as e:
|
||||
print(f'Failed to remove whitelist entry for {ip} from {WAZUH_CONF}', file=sys.stderr)
|
||||
print(e)
|
||||
return 1
|
||||
print('Restarting OSSEC Server...')
|
||||
cmd = subprocess.run(restart_wazuh_cmd)
|
||||
else:
|
||||
return cmd.returncode
|
||||
else:
|
||||
print(f'Commmand \'{" ".join(salt_cmd)}\' failed.', file=sys.stderr)
|
||||
return cmd.returncode
|
||||
if cmd.returncode != 0:
|
||||
print('Failed to restart OSSEC server.')
|
||||
return cmd.returncode
|
||||
|
||||
|
||||
def main():
|
||||
if os.geteuid() != 0:
|
||||
print('You must run this script as root', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
main_parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog=textwrap.dedent(f'''\
|
||||
additional information:
|
||||
To use this script in interactive mode call it with no arguments
|
||||
'''
|
||||
))
|
||||
|
||||
group = main_parser.add_argument_group(title='roles')
|
||||
group.add_argument('-a', dest='roles', action='append_const', const=VALID_ROLES['a']['role'], help="Analyst - 80/tcp, 443/tcp")
|
||||
group.add_argument('-b', dest='roles', action='append_const', const=VALID_ROLES['b']['role'], help="Logstash Beat - 5044/tcp")
|
||||
group.add_argument('-e', dest='roles', action='append_const', const=VALID_ROLES['e']['role'], help="Elasticsearch REST API - 9200/tcp")
|
||||
group.add_argument('-f', dest='roles', action='append_const', const=VALID_ROLES['f']['role'], help="Strelka frontend - 57314/tcp")
|
||||
group.add_argument('-o', dest='roles', action='append_const', const=VALID_ROLES['o']['role'], help="Osquery endpoint - 8090/tcp")
|
||||
group.add_argument('-s', dest='roles', action='append_const', const=VALID_ROLES['s']['role'], help="Syslog device - 514/tcp/udp")
|
||||
group.add_argument('-w', dest='roles', action='append_const', const=VALID_ROLES['w']['role'], help="Wazuh agent - 1514/tcp/udp")
|
||||
group.add_argument('-p', dest='roles', action='append_const', const=VALID_ROLES['p']['role'], help="Wazuh API - 55000/tcp")
|
||||
group.add_argument('-r', dest='roles', action='append_const', const=VALID_ROLES['r']['role'], help="Wazuh registration service - 1515/tcp")
|
||||
|
||||
ip_g = main_parser.add_argument_group(title='allow')
|
||||
ip_g.add_argument('-i', help="IP or CIDR block to disallow connections from, requires at least one role argument", metavar='', dest='ip')
|
||||
|
||||
args = main_parser.parse_args(sys.argv[1:])
|
||||
|
||||
if args.roles is None:
|
||||
role = role_prompt()
|
||||
ip = ip_prompt()
|
||||
try:
|
||||
return_code = apply(role, ip)
|
||||
except Exception as e:
|
||||
print(f'Unexpected exception occurred: {e}', file=sys.stderr)
|
||||
return_code = e.errno
|
||||
sys.exit(return_code)
|
||||
elif args.roles is not None and args.ip is None:
|
||||
if os.environ.get('IP') is None:
|
||||
main_parser.print_help()
|
||||
sys.exit(1)
|
||||
else:
|
||||
args.ip = os.environ['IP']
|
||||
|
||||
if validate_ip_cidr(args.ip):
|
||||
try:
|
||||
for role in args.roles:
|
||||
return_code = apply(role, args.ip)
|
||||
if return_code > 0:
|
||||
break
|
||||
except Exception as e:
|
||||
print(f'Unexpected exception occurred: {e}', file=sys.stderr)
|
||||
return_code = e.errno
|
||||
else:
|
||||
print(f'Invalid IP address or CIDR block \'{args.ip}\', please try again.', file=sys.stderr)
|
||||
return_code = 1
|
||||
|
||||
sys.exit(return_code)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(1)
|
||||
@@ -70,7 +70,7 @@ do
|
||||
done
|
||||
|
||||
docker_exec(){
|
||||
CMD="docker exec -it so-elastalert elastalert-test-rule /opt/elastalert/rules/$RULE_NAME --config /opt/config/elastalert_config.yaml $OPTIONS"
|
||||
CMD="docker exec -it so-elastalert elastalert-test-rule /opt/elastalert/rules/$RULE_NAME --config /opt/elastalert/config.yaml $OPTIONS"
|
||||
if [ "${RESULTS_TO_LOG,,}" = "y" ] ; then
|
||||
$CMD > "$FILE_SAVE_LOCATION"
|
||||
else
|
||||
|
||||
0
salt/common/tools/sbin/so-elasticsearch-roles-load
Normal file → Executable file
0
salt/common/tools/sbin/so-elasticsearch-roles-load
Normal file → Executable file
@@ -54,7 +54,7 @@ PIPELINES=$({{ ELASTICCURL }} -sk https://"$ELASTICSEARCH_HOST":"$ELASTICSEARCH_
|
||||
if [[ "$PIPELINES" -lt 5 ]]; then
|
||||
echo "Setting up ingest pipeline(s)"
|
||||
|
||||
for MODULE in activemq apache auditd aws azure barracuda bluecoat cef checkpoint cisco coredns crowdstrike cyberark cylance elasticsearch envoyproxy f5 fortinet gcp google_workspace googlecloud gsuite haproxy ibmmq icinga iis imperva infoblox iptables juniper kafka kibana logstash microsoft misp mongodb mssql mysql nats netscout nginx o365 okta osquery panw postgresql rabbitmq radware redis santa snort snyk sonicwall sophos squid suricata system tomcat traefik zeek zscaler
|
||||
for MODULE in activemq apache auditd aws azure barracuda bluecoat cef checkpoint cisco coredns crowdstrike cyberark cylance elasticsearch envoyproxy f5 fortinet gcp google_workspace googlecloud gsuite haproxy ibmmq icinga iis imperva infoblox iptables juniper kafka kibana logstash microsoft mongodb mssql mysql nats netscout nginx o365 okta osquery panw postgresql rabbitmq radware redis santa snort snyk sonicwall sophos squid suricata system threatintel tomcat traefik zeek zscaler
|
||||
do
|
||||
echo "Loading $MODULE"
|
||||
docker exec -i so-filebeat filebeat setup modules -pipelines -modules $MODULE -c $FB_MODULE_YML
|
||||
|
||||
8
salt/common/tools/sbin/so-import-evtx
Normal file → Executable file
8
salt/common/tools/sbin/so-import-evtx
Normal file → Executable file
@@ -25,6 +25,7 @@
|
||||
|
||||
INDEX_DATE=$(date +'%Y.%m.%d')
|
||||
RUNID=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 8 | head -n 1)
|
||||
LOG_FILE=/nsm/import/evtx-import.log
|
||||
|
||||
. /usr/sbin/so-common
|
||||
|
||||
@@ -41,14 +42,17 @@ function evtx2es() {
|
||||
EVTX=$1
|
||||
HASH=$2
|
||||
|
||||
ES_PW=$(lookup_pillar "auth:users:so_elastic_user:pass" "elasticsearch")
|
||||
ES_USER=$(lookup_pillar "auth:users:so_elastic_user:user" "elasticsearch")
|
||||
|
||||
docker run --rm \
|
||||
-v "$EVTX:/tmp/$RUNID.evtx" \
|
||||
--entrypoint evtx2es \
|
||||
{{ MANAGER }}:5000/{{ IMAGEREPO }}/so-pcaptools:{{ VERSION }} \
|
||||
--host {{ MANAGERIP }} --scheme https \
|
||||
--index so-beats-$INDEX_DATE --pipeline import.wel \
|
||||
--login {{ES_USER}} --pwd {{ES_PW}} \
|
||||
"/tmp/$RUNID.evtx" 1>/dev/null 2>/dev/null
|
||||
--login $ES_USER --pwd $ES_PW \
|
||||
"/tmp/$RUNID.evtx" >> $LOG_FILE 2>&1
|
||||
|
||||
docker run --rm \
|
||||
-v "$EVTX:/tmp/import.evtx" \
|
||||
|
||||
@@ -8,9 +8,9 @@ fi
|
||||
|
||||
echo "This tool will update a manager's IP address to the new IP assigned to the management network interface."
|
||||
|
||||
echo
|
||||
echo ""
|
||||
echo "WARNING: This tool is still undergoing testing, use at your own risk!"
|
||||
echo
|
||||
echo ""
|
||||
|
||||
if [ -z "$OLD_IP" ]; then
|
||||
OLD_IP=$(lookup_pillar "managerip")
|
||||
@@ -27,7 +27,7 @@ if [ -z "$NEW_IP" ]; then
|
||||
NEW_IP=$(ip -4 addr list $iface | grep inet | cut -d' ' -f6 | cut -d/ -f1)
|
||||
|
||||
if [ -z "$NEW_IP" ]; then
|
||||
fail "Unable to detect new IP on interface $iface. "
|
||||
fail "Unable to detect new IP on interface $iface."
|
||||
fi
|
||||
|
||||
echo "Detected new IP $NEW_IP on interface $iface."
|
||||
@@ -39,15 +39,20 @@ fi
|
||||
|
||||
echo "About to change old IP $OLD_IP to new IP $NEW_IP."
|
||||
|
||||
echo
|
||||
echo ""
|
||||
read -n 1 -p "Would you like to continue? (y/N) " CONTINUE
|
||||
echo
|
||||
echo ""
|
||||
|
||||
if [ "$CONTINUE" == "y" ]; then
|
||||
for file in $(grep -rlI $OLD_IP /opt/so/saltstack /etc); do
|
||||
echo "Updating file: $file"
|
||||
sed -i "s|$OLD_IP|$NEW_IP|g" $file
|
||||
done
|
||||
for file in $(grep -rlI $OLD_IP /opt/so/saltstack /etc); do
|
||||
echo "Updating file: $file"
|
||||
sed -i "s|$OLD_IP|$NEW_IP|g" $file
|
||||
done
|
||||
|
||||
echo "Granting MySQL root user permissions on $NEW_IP"
|
||||
docker exec -i so-mysql mysql --user=root --password=$(lookup_pillar_secret 'mysql') -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'$NEW_IP' IDENTIFIED BY '$(lookup_pillar_secret 'mysql')' WITH GRANT OPTION;" &> /dev/null
|
||||
echo "Removing MySQL root user from $OLD_IP"
|
||||
docker exec -i so-mysql mysql --user=root --password=$(lookup_pillar_secret 'mysql') -e "DROP USER 'root'@'$OLD_IP';" &> /dev/null
|
||||
|
||||
echo "The IP has been changed from $OLD_IP to $NEW_IP."
|
||||
|
||||
@@ -60,4 +65,4 @@ if [ "$CONTINUE" == "y" ]; then
|
||||
fi
|
||||
else
|
||||
echo "Exiting without changes."
|
||||
fi
|
||||
fi
|
||||
|
||||
30
salt/common/tools/sbin/so-kibana-savedobjects-defaults
Executable file
30
salt/common/tools/sbin/so-kibana-savedobjects-defaults
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2014,2015,2016,2017,2018,2019,2020,2021 Security Onion Solutions, LLC
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
. /usr/sbin/so-common
|
||||
|
||||
echo $banner
|
||||
echo "Running kibana.so_savedobjects_defaults Salt state to restore default saved objects."
|
||||
printf "This could take a while if another Salt job is running. \nRun this command with --force to stop all Salt jobs before proceeding.\n"
|
||||
echo $banner
|
||||
|
||||
if [ "$1" = "--force" ]; then
|
||||
printf "\nForce-stopping all Salt jobs before proceeding\n\n"
|
||||
salt-call saltutil.kill_all_jobs
|
||||
fi
|
||||
|
||||
salt-call state.apply kibana.so_savedobjects_defaults -linfo queue=True
|
||||
0
salt/common/tools/sbin/so-playbook-import
Normal file → Executable file
0
salt/common/tools/sbin/so-playbook-import
Normal file → Executable file
@@ -17,4 +17,4 @@
|
||||
|
||||
. /usr/sbin/so-common
|
||||
|
||||
docker exec -it so-redis redis-cli llen logstash:unparsed
|
||||
docker exec so-redis redis-cli llen logstash:unparsed
|
||||
|
||||
@@ -182,6 +182,10 @@ function ensureRoleFileExists() {
|
||||
echo "Database file does not exist yet, installation is likely not yet complete."
|
||||
fi
|
||||
|
||||
if [[ -d "$socRolesFile" ]]; then
|
||||
echo "Removing invalid roles directory created by Docker"
|
||||
rm -fr "$socRolesFile"
|
||||
fi
|
||||
mv "${rolesTmpFile}" "${socRolesFile}"
|
||||
fi
|
||||
}
|
||||
@@ -445,7 +449,7 @@ function deleteUser() {
|
||||
|
||||
rolesTmpFile="${socRolesFile}.tmp"
|
||||
createFile "$rolesTmpFile" "$soUID" "$soGID"
|
||||
grep -v "$id" "$socRolesFile" > "$rolesTmpFile"
|
||||
grep -v "$identityId" "$socRolesFile" > "$rolesTmpFile"
|
||||
mv "$rolesTmpFile" "$socRolesFile"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user