diff --git a/Pages/ufw-autoupdate.html b/Pages/ufw-autoupdate.html new file mode 100644 index 0000000..9aeb833 --- /dev/null +++ b/Pages/ufw-autoupdate.html @@ -0,0 +1,89 @@ +ufw-ipset-blocklist-autoupdate + +Latest Version Maintenance Status License GitHub Issues GitHub Pull Requests Donate with PayPal Sponsor with GitHub GitHub Stars GitHub Forks GitHub Contributors + +This collection of scripts automatically pulls IP blocklists (e.g. Spamhaus, Blocklist, ...) and drops packages from listed IP addresses. It integrates with the uncomplicated firewall (ufw) and makes use of ipset for storing IP addresses and network ranges. Both IPv4 and IPv6 blocklists are supported. +Installation + + Install ufw and ipset. + Deploy after.init script via executing: ./setup-ufw.sh + Determine the blocklist you would like to use. + Get initial set of blocklists: ./update-ip-blocklists.sh -l "blocklist https://lists.blocklist.de/lists/all.txt" -l "spamhaus https://www.spamhaus.org/drop/drop.txt" + Add update-ip-blocklists.sh to your crontab: + +@daily /path/to/update-ip-blocklists.sh -l "blocklist https://lists.blocklist.de/lists/all.txt" -l "spamhaus https://www.spamhaus.org/drop/drop.txt" + +Usage + +Usage: ./update-ip-blocklists.sh [-h] +Blocking lists of IPs from public blocklists / blacklists (e.g. blocklist.de, spamhaus.org) + +Options: + -l : Blocklist to use. Can be specified multiple times. + Format: "$name $url" (space-separated). See examples below. + -4 : Run in IPv4 only mode. Ignore IPv6 addresses. + -6 : Run in IPv6 only mode. Ignore IPv4 addresses. + -q : Quiet mode. Outputs are suppressed if flag is present. + -v : Verbose mode. Prints additional information during execution. + -h : Print this help message. + +Example usage: +./update-ip-blocklists.sh -l "spamhaus https://www.spamhaus.org/drop/drop.txt" +./update-ip-blocklists.sh -l "blocklist https://lists.blocklist.de/lists/all.txt" -l "spamhaus https://www.spamhaus.org/drop/drop.txt" +./update-ip-blocklists.sh -l "spamhaus https://www.spamhaus.org/drop/drop.txt" -l "spamhaus6 https://www.spamhaus.org/drop/dropv6.txt" + +Supplying blocklist sources + +Blocklists can be passed to the script using the -l CLI argument. Each entry consists of a name and download URL, separated by a space. Examples: + + -l "spamhaus https://www.spamhaus.org/drop/drop.txt" + -l "mylist http://mylist.local/list.txt" + -l "spamhaus6 https://www.spamhaus.org/drop/dropv6.txt" + +Lists are stripped of comments. This means all text after one of the following characters is removed before parsing: ;, #. Valid IPv4/IPv6 addresses with an optional CIDR are loaded into the ipset to block. + +Processing of either IPv6 or IPv4 addresses can be disabled by supplying the -4 (IPv4 only) or -6 (IPv6 only) flags respectively. +Listing blocked IPs + +The total number of blocked IPs is indicated by running ipset -t list. A full list of all blocked addresses is given by ipset list. +Components + + update-ip-blocklist.sh: Pulls the latest versions of requested blocklists, updates ipsets, and exports created ipsets to $IPSET_DIR (default: /var/lib/ipset). Ipsets are swapped during update to minimize the update downtime. + ufw/after.init: Inserts and deletes the required iptables rules on ufw reloads. Ipsets are loaded from $IPSET_DIR. + setup-ufw.sh: Helper script to deploy ufw/after.init. + +Available blocklists + +This script can parse all blocklists that list IPv4 or IPv6 addresses with optional CIDR notation row per row in a plain text format (see Supplying blocklist sources). + +The following blocklists are known to work. They can be enabled by passing the respective -l argument to the update-ip-blocklists.sh script. + + Binary Defense Systems Artillery Threat Intelligence Banlist: + -l "bdsatib https://www.binarydefense.com/banlist.txt" + Blocklist.de Fail2Ban Reporting (all): + -l "blocklist https://lists.blocklist.de/lists/all.txt" + BruteForceBlocker: + -l "bfblocker https://danger.rulez.sk/projects/bruteforceblocker/blist.php" + CINS Army List: + -l "cnisarmy http://cinsscore.com/list/ci-badguys.txt" + FEODO Tracker: Botnet C2 (Recommended): + -l "feodoc2 https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt" + FEODO Tracker: Botnet C2 IoC (Recommended): + -l "feodoc2ioc https://feodotracker.abuse.ch/downloads/ipblocklist.txt" + FEODO Tracker: Botnet C2 IoC (Aggressive): + -l "feodoc2ioca https://feodotracker.abuse.ch/downloads/ipblocklist_aggressive.txt" + FireHOL IP List Level 1: + -l "firehol1 https://iplists.firehol.org/files/firehol_level1.netset" + GreenSnow: + -l "greensnow https://blocklist.greensnow.co/greensnow.txt" + IPsum: + -l "ipsum https://raw.githubusercontent.com/stamparm/ipsum/master/levels/3.txt" + Spamhaus Don't Route Or Peer List (DROP): + -l "spamhaus https://www.spamhaus.org/drop/drop.txt" + Spamhaus IPv6 DROP List (DROPv6): + -l "spamhaus6 https://www.spamhaus.org/drop/dropv6.txt" + Spamhaus Extended DROP List (EDROP): + -l "spamhausex https://www.spamhaus.org/drop/edrop.txt" + +Acknowledgments +This project is inspired by this post on Xela's Linux Blog. \ No newline at end of file diff --git a/Test-Scripts/list-ufw-blocks.sh b/Test-Scripts/list-ufw-blocks.sh new file mode 100644 index 0000000..da96401 --- /dev/null +++ b/Test-Scripts/list-ufw-blocks.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Install geoiplookup if needed +if [ ! "$(command -v geoiplookup)" ]; then + apt -y install geoip-bin +fi + +# Colors for Location/Address +BB="\033[1;34m" # Blue bold +BW="\033[1;37m" # Bold White +BY="\033[1;33m" # Bold Yellow +GR="\033[0;32m" # Green +LY="\033[3;33m" # Light Yellow +RB="\033[1;31m" # Red bold (Default) + +LOGFILE=/var/log/auth.log # Log file +LINE=0 # Where to start count +NC="\033[00m" # Color Reset + +while true + do + for i in $(cat $LOGFILE | awk "NR>$LINE" | grep Invalid | awk '{print $(NF-2)}' | uniq) + do + LINE=$(cat $LOGFILE | wc -l) + # Detect if IPv4 address for lookups + if [ "$i" != "${i#*[0-9].[0-9]}" ]; then + LOCATION=$(geoiplookup "$i" | awk '{print $5 " " $6}') + else + LOCATION=$(geoiplookup6 "$i" | awk '{print $6 " " $7}') + fi + echo -e "[*] The Attacker's Country: ${RB}$LOCATION ${NC}[IP ADDRESS:${RB} $i] ${NC}" + + done + sleep 2 + done \ No newline at end of file diff --git a/UFW-Blocklist/after.init b/UFW-Blocklist/after.init index f320d02..a92353a 100644 --- a/UFW-Blocklist/after.init +++ b/UFW-Blocklist/after.init @@ -1,172 +1,80 @@ #!/bin/bash +# ################################################## +# ufw-ipset-blocklist-autoupdate # -# after.init: if executable, called by ufw-init. See 'man ufw-framework' for -# details. Note that output from these scripts is not seen via the -# the ufw command, but instead via ufw-init. +# Blocking lists of IPs from public blocklists / blacklists (e.g. blocklist.de, spamhaus.org) # -############################################################################### -#### #### -#### Based on ufw-blocklist edition: IP blocklist extension for Ubuntu ufw #### -#### https://github.com/poddmo/ufw-blocklist #### -#### #### -#### Modified https://mylinux.work #### -#### Version 1.0.2.061324 #### -#### Contact: contact@mylinux.work #### -#### #### -############################################################################### -set -e +# Version: 1.1.1 +# +# See: https://github.com/ngandrass/ufw-ipset-blocklist-autoupdate +# +# +# MIT License +# +# Copyright (c) 2023 Niels Gandraß +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ################################################## -export ipsetname=ufw-blocklist-ipsum +IPSET_BIN="$(which ipset)" +IPSET_DIR="/var/lib/ipset" -# seed file containing the list of IP addresses to be blocked, one per line -export seedlist=/etc/ipsum.ipv4.txt +# Check prerequisites +if [ ! -x "${IPSET_BIN}" ]; then + echo "ERROR: ipset binary not found in ${IPSET_BIN}" + return +fi -export IPSET_EXE="/sbin/ipset" -# check ipset exists and is executable -[ -x "$IPSET_EXE" ] || { - echo "$IPSET_EXE is not executable" - exit 1 - } - -# Function to check if a chain exists (chain_exists ufw_blocklist_input && action if true || action if false) -chain_exists() { - { - [ $# -lt 1 ] || [ $# -gt 2 ] && { - echo "Usage: chain_exists [table]" >&2 - return 1 - } - - local chain_name="$1" ; shift - [ $# -eq 1 ] && local table="--table $1" - iptables "$table" -n --list "$chain_name" >/dev/null 2>&1 - } -} - -# Function to check if an set exists (set_exists setname && action if true || action if false) -set_exists() { - { - [ $# -ne 1 ] && { - echo "Usage: set_exists " >&2 - return 1 - } - - local set_name="$1" - ipset list "$set_name" -name >/dev/null 2>&1 - } -} +if [ ! -d "${IPSET_DIR}" ]; then + echo "ERROR: ipset data directory does not exist: ${IPSET_DIR}" >&2 + return +fi +savefiles=$(find "$IPSET_DIR" -name "*-inet.save") case "$1" in start) - # check that blocklist seed file exists - if [ ! -f "$seedlist" ]; then - echo "ufw after.init: $seedlist does not exist." - exit 1 - fi + for f in $savefiles; do + listname=$(basename -s ".save" "$f") - # create an empty ipset - $IPSET_EXE create $ipsetname hash:net -exist - $IPSET_EXE flush $ipsetname - - ## Insert firewall rules to take precedence, removing them and adding them back if they already existed - # Block inbound to localhost from blocklist - if chain_exists ufw-blocklist-input; then - iptables -D INPUT -m set --match-set $ipsetname src -j ufw-blocklist-input || true - iptables -F ufw-blocklist-input - iptables -X ufw-blocklist-input - fi - - iptables -N ufw-blocklist-input - iptables -A ufw-blocklist-input -j DROP -m comment --comment "ufw-blocklist-input" - iptables -I INPUT -m set --match-set $ipsetname src -j ufw-blocklist-input - - # Log and drop outbound to blocklist. Hits here may indicate compromised localhost - if chain_exists ufw-blocklist-output; then - iptables -D OUTPUT -m set --match-set $ipsetname dst -j ufw-blocklist-output || true - iptables -F ufw-blocklist-output - iptables -X ufw-blocklist-output - fi - - iptables -N ufw-blocklist-output - iptables -A ufw-blocklist-output -j LOG --log-level 3 --log-prefix "[UFW BLOCKLIST OUTPUT] " -m limit --limit 3/minute --limit-burst 10 - iptables -A ufw-blocklist-output -j DROP -m comment --comment "ufw-blocklist-output" - iptables -I OUTPUT -m set --match-set $ipsetname dst -j ufw-blocklist-output - - # Log and drop forwarding to blocklist. Hits here may indicate compromised internal hosts - if chain_exists ufw-blocklist-forward; then - iptables -D FORWARD -m set --match-set $ipsetname dst -j ufw-blocklist-forward || true - iptables -F ufw-blocklist-forward - iptables -X ufw-blocklist-forward - fi - - iptables -N ufw-blocklist-forward - iptables -A ufw-blocklist-forward -j LOG --log-level 3 --log-prefix "[UFW BLOCKLIST FORWARD] " -m limit --limit 3/minute --limit-burst 10 - iptables -A ufw-blocklist-forward -j DROP -m comment --comment "ufw-blocklist-forward" - iptables -I FORWARD -m set --match-set $ipsetname dst -j ufw-blocklist-forward - - # add members to the ipset - # start this in a subshell and then disown the job so we return quickly. - ( - while read -r ip < "$seedlist" - do - $IPSET_EXE add "$ipsetname" "$ip" - done - ) < /dev/null &> /dev/null & disown -h + $IPSET_BIN restore -! <"$f" + iptables -I INPUT -m set --match-set "$listname" src -j DROP + iptables -I INPUT -m set --match-set "$listname" src -j LOG --log-prefix "[UFW BLOCK $listname] " + done ;; stop) + for f in $savefiles; do + listname=$(basename -s ".save" "$f") - # delete resources created above - if chain_exists ufw-blocklist-input; then - iptables -D INPUT -m set --match-set $ipsetname src -j ufw-blocklist-input || true - iptables -F ufw-blocklist-input - iptables -X ufw-blocklist-input - fi - - if chain_exists ufw-blocklist-output; then - iptables -D OUTPUT -m set --match-set $ipsetname dst -j ufw-blocklist-output || true - iptables -F ufw-blocklist-output - iptables -X ufw-blocklist-output - fi - - if chain_exists ufw-blocklist-forward; then - iptables -D FORWARD -m set --match-set $ipsetname dst -j ufw-blocklist-forward || true - iptables -F ufw-blocklist-forward - iptables -X ufw-blocklist-forward - fi - - if set_exists $ipsetname; then - $IPSET_EXE flush $ipsetname - $IPSET_EXE destroy $ipsetname - fi + iptables -D INPUT -m set --match-set "$listname" src -j DROP || true + iptables -D INPUT -m set --match-set "$listname" src -j LOG --log-prefix "[UFW BLOCK $listname] " || true + $IPSET_BIN destroy -q "$listname" || true + done ;; status) - # display details of the ipset - $IPSET_EXE list "$ipsetname" -t - + echo "= after.init =" + $IPSET_BIN -t list # show iptables hit/byte counts - iptables -L -nvx | grep "$ipsetname" | grep 'match-set' - - # show the last 10 lines from the logs - journalctl | grep -i blocklist | tail - ;; -flush-all) - # flush sets created above. Use /etc/cron.daily/ufw-blocklist-ipsum to repopulate - $IPSET_EXE flush $ipsetname - - # reset iptables accounting - ipz=$( iptables -L INPUT -nvx --line-numbers | grep ufw-blocklist-input | awk '{print $1}') - iptables -Z INPUT "$ipz" - iptables -Z ufw-blocklist-input - - ipz=$( iptables -L OUTPUT -nvx --line-numbers | grep ufw-blocklist-output | awk '{print $1}') - iptables -Z OUTPUT "$ipz" - iptables -Z ufw-blocklist-output - - ipz=$( iptables -L FORWARD -nvx --line-numbers | grep ufw-blocklist-forward | awk '{print $1}') - iptables -Z FORWARD "$ipz" - iptables -Z ufw-blocklist-forward + iptables -L -nvx | grep "$listname" | grep 'match-set' + echo "" ;; *) echo "'$1' not supported" - echo "Usage: /etc/ufw/after.init {start|stop|flush-all|status}" + echo "Usage: after.init {start|stop|status}" ;; esac diff --git a/UFW-Blocklist/after6.init b/UFW-Blocklist/after6.init new file mode 100644 index 0000000..d2b5f3e --- /dev/null +++ b/UFW-Blocklist/after6.init @@ -0,0 +1,93 @@ +#!/bin/sh +# ################################################## +# ufw-ipset-blocklist-autoupdate +# +# Blocking lists of IPs from public blocklists / blacklists (e.g. blocklist.de, spamhaus.org) +# +# Version: 1.1.1 +# +# See: https://github.com/ngandrass/ufw-ipset-blocklist-autoupdate +# +# +# MIT License +# +# Copyright (c) 2023 Niels Gandraß +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ################################################## + +IPSET_BIN="$(which ipset)" +IPSET_DIR="/var/lib/ipset" + +# Check prerequisites +if [ ! -x "${IPSET_BIN}" ]; then + echo "ERROR: ipset binary not found in ${IPSET_BIN}" + return +fi + +if [ ! -d "${IPSET_DIR}" ]; then + echo "ERROR: ipset data directory does not exist: ${IPSET_DIR}" >&2 + return +fi + +savefiles=$(find "$IPSET_DIR" -name "*-inet\.save") +savefiles6=$(find "$IPSET_DIR" -name "*-inet6\.save") +case "$1" in +start) + for f in $savefiles; do + listname=$(basename -s ".save" "$f") + + $IPSET_BIN restore -! <"$f" + iptables -I INPUT -m set --match-set "$listname" src -j DROP + iptables -I INPUT -m set --match-set "$listname" src -j LOG --log-prefix "[UFW BLOCK $listname] " + done + for f in $savefiles6; do + listname=$(basename -s ".save" "$f") + + $IPSET_BIN restore -! <"$f" + ip6tables -I INPUT -m set --match-set "$listname" src -j DROP + ip6tables -I INPUT -m set --match-set "$listname" src -j LOG --log-prefix "[UFW BLOCK $listname] " + done + ;; +stop) + for f in $savefiles; do + listname=$(basename -s ".save" "$f") + + iptables -D INPUT -m set --match-set "$listname" src -j DROP || true + iptables -D INPUT -m set --match-set "$listname" src -j LOG --log-prefix "[UFW BLOCK $listname] " || true + $IPSET_BIN destroy -q "$listname" || true + done + for f in $savefiles6; do + listname=$(basename -s ".save" "$f") + + ip6tables -D INPUT -m set --match-set "$listname" src -j DROP || true + ip6tables -D INPUT -m set --match-set "$listname" src -j LOG --log-prefix "[UFW BLOCK $listname] " || true + $IPSET_BIN destroy -q "$listname" || true + done + ;; +status) + echo "= after.init =" + $IPSET_BIN -t list + echo "" + ;; +*) + echo "'$1' not supported" + echo "Usage: after.init {start|stop|status}" + ;; +esac diff --git a/UFW-Blocklist/f3_menu.sh b/UFW-Blocklist/f3_menu.sh new file mode 100644 index 0000000..2141ccb --- /dev/null +++ b/UFW-Blocklist/f3_menu.sh @@ -0,0 +1,249 @@ +#! /bin/bash +function bdsatib() { + { + ufw-blocklist -l "bdsatib https://www.binarydefense.com/banlist.txt" + if ! crontab -l | grep -q "bdsatib"; then + echo -e "$(crontab -u root -l)\n@daily /usr/local/bin/ufw-blocklists.sh -l "bdsatib https://www.binarydefense.com/banlist.txt"" | crontab -u root - + fi + } +} + +function f2ball() { + { + ufw-blocklist -l "f2ball https://lists.blocklist.de/lists/all.txt" + if ! crontab -l | grep -q "f2ball"; then + echo -e "$(crontab -u root -l)\n*/35 * * * * /usr/local/bin/ufw-blocklists.sh -l "f2ball https://lists.blocklist.de/lists/all.txt"" | crontab -u root - + fi + } +} + +function bfblocker() { + { + ufw-blocklist -l "bfblocker https://danger.rulez.sk/projects/bruteforceblocker/blist.php" + if ! crontab -l | grep -q "bfblocker"; then + echo -e "$(crontab -u root -l)\n@daily /usr/local/bin/ufw-blocklists.sh -l "bfblocker https://danger.rulez.sk/projects/bruteforceblocker/blist.php"" | crontab -u root - + fi + } +} + +function cinsarmy() { + { + ufw-blocklist -l "cinsarmy http://cinsscore.com/list/ci-badguys.txt" + if ! crontab -l | grep -q "cinsarmy"; then + echo -e "$(crontab -u root -l)\n@daily /usr/local/bin/ufw-blocklists.sh -l "cinsarmy http://cinsscore.com/list/ci-badguys.txt"" | crontab -u root - + fi + } +} + +function drop() { + { + if grep -q -E "IPV6=(yes|YES)" /etc/default/ufw; then + ufw-blocklist -l "drop https://www.spamhaus.org/drop/drop.txt" -l "dropv6 https://www.spamhaus.org/drop/dropv6.txt" + if ! crontab -l | grep -q "dropv6"; then + echo -e "$(crontab -u root -l)\n@daily /usr/local/bin/ufw-blocklists.sh -l "drop https://www.spamhaus.org/drop/drop.txt" -l "dropv6 https://www.spamhaus.org/drop/dropv6.txt"" | crontab -u root - + fi + else + ufw-blocklist -l "drop https://www.spamhaus.org/drop/drop.txt" + if ! crontab -l | grep -q "drop"; then + echo -e "$(crontab -u root -l)\n@daily /usr/local/bin/ufw-blocklists.sh -l "drop https://www.spamhaus.org/drop/drop.txt"" | crontab -u root - + fi + fi + } +} + +function edrop() { + { + ufw-blocklist -l "edrop https://www.spamhaus.org/drop/edrop.txt" + if ! crontab -l | grep -q "edrop"; then + echo -e "$(crontab -u root -l)\n@daily /usr/local/bin/ufw-blocklists.sh -l "edrop https://www.spamhaus.org/drop/edrop.txt"" | crontab -u root - + fi + } +} + +function feodoc2() { + { + ufw-blocklist -l "feodoc2 https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt" + if ! crontab -l | grep -q "feodoc2"; then + echo -e "$(crontab -u root -l)\n@daily /usr/local/bin/ufw-blocklists.sh -l "feodoc2 https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt"" | crontab -u root - + fi + } +} + +function feodoioc() { + { + ufw-blocklist -l "feodoioc https://feodotracker.abuse.ch/downloads/ipblocklist.txt" + if ! crontab -l | grep -q "fedoioc"; then + echo -e "$(crontab -u root -l)\n@daily /usr/local/bin/ufw-blocklists.sh -l "feodoioc https://feodotracker.abuse.ch/downloads/ipblocklist.txt"" | crontab -u root - + fi + } +} + +function firehol() { + { + ufw-blocklist -l "firehol https://iplists.firehol.org/files/firehol_level1.netset" + if ! crontab -l | grep -q "firehol"; then + echo -e "$(crontab -u root -l)\n@daily /usr/local/bin/ufw-blocklists.sh -l "firehol https://iplists.firehol.org/files/firehol_level1.netset"" | crontab -u root - + fi + } +} + +function greensnow() { + { + ufw-blocklist -l "greensnow https://blocklist.greensnow.co/greensnow.txt" + if ! crontab -l | grep -q "bdsatib"; then + echo -e "$(crontab -u root -l)\n@daily /usr/local/bin/ufw-blocklists.sh -l "greensnow https://blocklist.greensnow.co/greensnow.txt"" | crontab -u root - + fi + } +} + +function ipsum() { + { + ufw-blocklist -l "ipsum https://raw.githubusercontent.com/stamparm/ipsum/master/levels/2.txt" + if ! crontab -l | grep -q "ipsum"; then + echo -e "$(crontab -u root -l)\n@daily /usr/local/bin/ufw-blocklists.sh -l "ipsum https://raw.githubusercontent.com/stamparm/ipsum/master/levels/2.txt"" | crontab -u root - + fi + } +} + +function maxmind(){ + { + ufw-blocklist -l "maxmind https://www.maxmind.com/en/anonymous_proxies" + if ! crontab -l | grep -q "maxmind"; then + echo -e "$(crontab -u root -l)\n@daily /usr/local/bin/ufw-blocklists.sh -l "maxmind https://www.maxmind.com/en/anonymous_proxies"" | crontab -u root - + fi + } +} + +function blocklist_menu() { + { + clear + echo "Please select which blocklist from the list below" + printf "\n" + echo "1 - Binary Defense Systems Artillery Threat Intelligence Banlist" + echo "2 - Blocklist.de Fail2Ban Reporting (all)" + echo "3 - BruteForceBlocker" + echo "4 - CINS Army List" + echo "5 - FEODO Tracker: Botnet C2 - (Recommended)" + echo "6 - FEODO Tracker: Botnet C2 IoC - (Recommended)" + echo "7 - FireHOL IP List Level 1" + echo "8 - MaxMind" + echo "9 - GreenSnow" + echo "10 - IPsum - (Recommended)" + echo "11 - Spamhaus Don't Route Or Peer List (DROP)" + echo "12 - Spamhaus Extended DROP List (EDROP):" + echo "B - Go Back" + echo "X - Exit" + + read -rn 1 user_input + if [[ "$user_input" == '1' ]]; then + bdsatib + blocklist_menu + elif [[ "$user_input" == '2' ]]; then + f2ball + blocklist_menu + elif [[ "$user_input" == '3' ]]; then + bfblocker + blocklist_menu + elif [[ "$user_input" == '4' ]]; then + cins + blocklist_menu + elif [[ "$user_input" == '5' ]]; then + feodoc2 + blocklist_menu + elif [[ "$user_input" == '6' ]]; then + feodoioc + blocklist_menu + elif [[ "$user_input" == '7' ]]; then + firehol + blocklist_menu + elif [[ "$user_input" == '8' ]]; then + maxmind + blocklist_menu + elif [[ "$user_input" == '9' ]]; then + greensnow + blocklist_menu + elif [[ "$user_input" == '10' ]]; then + ipsum + blocklist_menu + elif [[ "$user_input" == '11' ]]; then + drop + blocklist_menu + elif [[ "$user_input" == '12' ]]; then + edrop + blocklist_menu + elif [[ "$user_input" == xX ]]; then + exit 0 + elif [[ "$user_input" == bB ]]; then + Main_Menu + fi + } +} + +function ipv6_install() { + { + # Check that ufw has IPv6 enabled + if ! grep -q -E "IPV6=(yes|YES)" /etc/default/ufw; then + echo "ERROR: IPv6 rules requested but UFW is not configured to use IPv6. Set IPV6=yes in /etc/default/ufw and rerun this script." + Main_Menu + fi + + wget https://files.mylinux.work/s/aRXEsCe5G8b43QB/download/after6.init + chmod 750 after6.init + mv /tmp/after6.init /etc/ufw/after6.init + + blocklist_menu + } +} + +function ipv6_menu() { + { + clear + echo "Would you like to enable IPv6 support? [Y/n]" + printf "\n" + echo "Y - Yes" + echo "N - No" + + read -rn 1 user_input + if [[ "$user_input" == [yY] ]]; then + ipv6_install + elif [[ "$user_input" == [nN] ]]; then + blocklist_menu + fi + } +} + +function ipv4_install() { + { + if [ ! "$(command -v ipset)" ]; then + apt -y install ipset + fi + cd /tmp || exit 2 + wget https://files.mylinux.work/s/cqKc2CkzmHMpBXW/download/after.init + chmod 750 after.init + mv /tmp/after.init /etc/ufw/after.init + + wget https://files.mylinux.work/s/KfDSRWCcrxiTftf/download/ufw-blocklists.sh + chmod 755 ufw-blocklists.sh + mv /tmp/ufw-blocklists.sh /usr/local/bin/ + ipv6_menu + } +} + +function Main_Menu() { + { + clear + echo "Configure UFW to block IPs listed in blocklist ipsets? [Y/n]" + printf "\n" + echo "Y - Yes" + echo "N - No" + + read -rn 1 user_input + if [[ "$user_input" == [yY] ]]; then + ipv4_install + elif [[ "$user_input" == [nN] ]]; then + exit 0 + fi + } +} + +Main_Menu \ No newline at end of file diff --git a/UFW-Blocklist/f4_menu.sh b/UFW-Blocklist/f4_menu.sh new file mode 100644 index 0000000..cc66828 --- /dev/null +++ b/UFW-Blocklist/f4_menu.sh @@ -0,0 +1,349 @@ +#!/bin/bash + + + +E='echo -e' +e='echo -en' +trap "R; exit" 2 +ESC=$( $e "\e") + +TPUT() { + $e "\e[${1};${2}H" +} + +CLEAR() { + $e "\ec" +} + +CIVIS() { + $e "\e[?25l" +} + +MARK() { + $e "\e[7m" +} + +UNMARK() { + $e "\e[27m" +} + +R() { + CLEAR + stty + sane + CLEAR +} + +HEAD() { + for each in $(seq 1 30) + do + $E " \xE2\x94\x82 \xE2\x94\x82" + done + MARK + TPUT 1 10 + $E " UFW BlockList Install " + UNMARK + TPUT 2 10 + $E " Select a Bloclist from the List " + UNMARK +} + +i=0 +CLEAR +CIVIS +NULL=/dev/null + +FOOT() { + MARK + TPUT 15 5 + $E " UP \xE2\x86\x91 \xE2\x86\x93 DOWN ENTER - SELECT,NEXT " + UNMARK +} + +ARROW() { + IFS= read -sr -n1 key 2>/dev/null >&2 + if [[ $key = "$ESC" ]]; then + read -sr -n1 key 2>/dev/null >&2 + if [[ $key = \[ ]]; then + read -sr -n1 key 2>/dev/null >&2 + if [[ $key = A ]]; then + echo up + fi + if [[ $key = B ]]; then + echo dn + fi + fi + fi + if [[ "$key" == "$($e \\x0A)" ]]; then + echo enter + fi +} + +M0() { + TPUT 4 20 + $e "Binary Defense Systems Artillery Threat Intelligence Banlist" +} + +M1() { + TPUT 5 20 + $e "Blocklist.de Fail2Ban Reporting (all)" +} + +M2() { + TPUT 6 20 + $e "BruteForceBlocker" +} + +M3() { + TPUT 7 20 + $e "CINS Army List" +} + +M4() { + TPUT 8 20 + $e "FEODO Tracker: Botnet C2" +} + +M5() { + TPUT 9 20 + $e "FEODO Tracker: Botnet C2 IoC" +} + +M6() { + TPUT 10 20 + $e "FireHOL IP List Level 1" +} + +M7() { + TPUT 11 20 + $e "GreenSnow" +} + +M8() { + TPUT 12 20 + $e "IPsum - (Recommended)" +} + +M9() { + TPUT 12 20 + $e "Spamhaus Don't Route Or Peer List (DROP)" +} + +M10() { + TPUT 13 20 + $e "Spamhaus Extended DROP List (EDROP)" +} + +M11() { + TPUT 14 20 + $e "MaxMind" +} + +M12() { + TPUT 15 20 + $e "Main Menu" +} +M13() { + TPUT 16 20 + $e "EXIT " +} + +LM=8 +MENU() { + for each in $(seq 0 $LM) + do + M"${each}" + done +} + +POS() { + if [[ $cur == up ]]; then + ((i--)) + fi + + if [[ $cur == dn ]]; then + ((i++)) + fi + + if [[ $i -lt 0 ]]; then + i=$LM + fi + + if [[ $i -gt $LM ]]; then + i=0 + fi +} + +REFRESH() { + after=$((i+1)) + before=$((i-1)) + + if [[ $before -lt 0 ]]; then + before=$LM + fi + + if [[ $after -gt $LM ]]; then + after=0 + fi + + if [[ $j -lt $i ]]; then + UNMARK + M$before + else + UNMARK + M$after + fi + + if [[ $after -eq 0 ]] || [ $before -eq $LM ]; then + UNMARK + M$before + M$after + fi + + j=$i + UNMARK + M$before + M$after +} + +INIT() { + R + HEAD + FOOT + MENU +} + +SC() { + REFRESH + MARK + $S + $b + cur=$(ARROW) +} + +ES() { + MARK + $e "ENTER = Main Menu " + $b + read -r + INIT +} + +INIT +while [[ "$O" != " " ]]; + do + case $i in + 0) S=M0 + SC + if [[ $cur == enter ]]; then + R + $e "\n$($e Binary Defense Systems Artillery Threat Intelligence Banlist)\n" + ES + fi + ;; + 1) S=M1 + SC + if [[ $cur == enter ]]; then + R + $e "\n$($e Blocklist.de Fail2Ban Reporting - all)\n" + ES + fi + ;; + 2) S=M2 + SC + if [[ $cur == enter ]]; then + R + $e "\n$($e BruteForceBlocker)\n" + ES + fi + ;; + 3) S=M3 + SC + if [[ $cur == enter ]]; then + R + $e "\n$($e CINS Army List)\n" + ES + fi + ;; + 4) S=M4 + SC + if [[ $cur == enter ]]; then + R + $e "\n$($e FEODO Tracker: Botnet C2)\n" + ES + fi + ;; + 5) S=M5 + SC + if [[ $cur == enter ]]; then + R + $e "\n$($e FEODO Tracker: Botnet C2 IoC)\n" + ES + fi + ;; + 6) S=M6 + SC + if [[ $cur == enter ]]; then + R + $e "\n$($e FireHOL IP List Level 1)\n" + ES + fi + ;; + 7) S=M7 + SC + if [[ $cur == enter ]]; then + R + $e "\n$($e GreenSnow)\n" + ES + fi + ;; + 8) S=M8 + SC + if [[ $cur == enter ]]; then + R + $e "\n$($e IPsum - \(Recommended\))\n" + ES + fi + ;; + 9) S=M9 + SC + if [[ $cur == enter ]]; then + R + $e "\n$($e Spamhaus Don\'t Route Or Peer List \(DROP))\n" + ES + fi + ;; + 10) S=M10 + SC + if [[ $cur == enter ]]; then + R + $e "\n$($e Spamhaus Extended DROP List \(EDROP))\n" + ES + fi + ;; + 11) S=M11 + SC + if [[ $cur == enter ]]; then + R + $e "\n$($e MaxMind)\n" + ES + fi + ;; + 12) S=M12 + SC + if [[ $cur == enter ]]; then + R + $e "\n$($e Main Menu)\n" + ES + fi + ;; + 13) S=M13 + SC + if [[ $cur == enter ]]; then + R + exit 0 + fi + ;; + esac + POS + done diff --git a/UFW-Blocklist/f5_menu.sh b/UFW-Blocklist/f5_menu.sh new file mode 100644 index 0000000..72b63ce --- /dev/null +++ b/UFW-Blocklist/f5_menu.sh @@ -0,0 +1,223 @@ +#!/bin/bash + +# Wrapper for desktopify Misko_2083 +# Menu code adapted from https://askubuntu.com/questions/1705/how-can-i-create-a-select-menu-in-a-shell-script +# Run from the same dir as desktopify + + + E='echo -e';e='echo -en';trap "R;exit" 2 + ESC=$( $e "\e") + TPUT(){ $e "\e[${1};${2}H" ;} + CLEAR(){ $e "\ec";} + CIVIS(){ $e "\e[?25l";} + MARK(){ $e "\e[7m";} + UNMARK(){ $e "\e[27m";} +cursor_blink_on() { printf "$ESC[?25h"; } +cursor_blink_off() { printf "$ESC[?25l"; } + R(){ CLEAR ;stty sane;CLEAR;}; + HEAD(){ for each in $(seq 1 15);do + $E " \xE2\x94\x82 \xE2\x94\x82" + done + MARK;TPUT 1 5 + $E " DESKTOPIFY " ;UNMARK; + TPUT 2 5 + $E " SELECT A DESKTOP ENVIRONMENT " ;} +HEAD_II(){ for each in $(seq 1 15);do + $E " \xE2\x94\x82 \xE2\x94\x82" + done + MARK;TPUT 1 5 + $E " DESKTOPIFY " ;UNMARK; + TPUT 2 5 + $E " SELECT ADDITIONAL OPTIONS " ; + TPUT 4 10 + $E " Desktop Environment $1" ;} + i=0; CLEAR; CIVIS; + FOOT(){ MARK;TPUT 15 5 + $E " UP \xE2\x86\x91 \xE2\x86\x93 DOWN \xE2\x94\x82 \xe2\x86\xb5 ENTER - NEXT \xE2\x94\x82 EXIT - X ";UNMARK;} +FOOT_II(){ MARK;TPUT 14 5 + $E " \xe2\x86\x90 BACK \xE2\x94\x82 SPACE - SELECT \xE2\x94\x82 "; + TPUT 15 5 + $E " UP \xE2\x86\x91 \xE2\x86\x93 DOWN \xE2\x94\x82 \xe2\x86\xb5 ENTER - NEXT \xE2\x94\x82 EXIT - X ";UNMARK;} + ARROW(){ IFS= read -s -n1 key 2>/dev/null >&2 + if [[ $key = $ESC ]];then + read -s -n2 key 2>/dev/null >&2; + if [[ $key = \[A ]]; then echo up;fi + if [[ $key = \[B ]]; then echo dn;fi + fi + if [[ $key = [xX] ]]; then echo exit;fi; + if [[ "$key" = "" ]];then echo enter;fi;} + M0(){ TPUT 4 20; $e "Lubuntu";} + M1(){ TPUT 5 20; $e "Kubuntu";} + M2(){ TPUT 6 20; $e "Ubuntu";} + M3(){ TPUT 7 20; $e "Ubuntu-Budgie";} + M4(){ TPUT 8 20; $e "Ubuntu-Kylin";} + M5(){ TPUT 9 20; $e "Ubuntu-Mate";} + M6(){ TPUT 10 20; $e "Ubuntu-Studio";} + M7(){ TPUT 11 20; $e "Xubuntu";} + M8(){ TPUT 12 20; $e "EXIT ";} + LM=8 + MENU(){ for each in $(seq 0 $LM);do M${each};done;} + POS(){ if [[ $cur == up ]];then ((i--));fi + if [[ $cur == dn ]];then ((i++));fi + if [[ $i -lt 0 ]];then i=$LM;fi + if [[ $i -gt $LM ]];then i=0;fi;} +REFRESH(){ after=$((i+1)); before=$((i-1)) + if [[ $before -lt 0 ]];then before=$LM;fi + if [[ $after -gt $LM ]];then after=0;fi + if [[ $j -lt $i ]];then UNMARK;M$before;else UNMARK;M$after;fi + if [[ $after -eq 0 ]] || [ $before -eq $LM ];then + UNMARK; M$before; M$after;fi;j=$i;UNMARK;M$before;M$after;} + INIT(){ R;HEAD;FOOT;MENU;} + SC(){ REFRESH;MARK;$S;$b;cur=`ARROW`;} + ES(){ INIT;};INIT + MSEL() { cursor_blink_on() { printf "$ESC[?25h"; } + cursor_blink_off() { printf "$ESC[?25l"; } + cursor_to() { printf "$ESC[$1;${2:-1}H"; } + print_inactive() { printf "$2 $1 "; } + print_active() { printf "$2 $ESC[7m$1 $ESC[27m"; } + get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; } + key_input() { + local key + IFS= read -rsn1 key 2>/dev/null >&2 + if [[ $key = "" ]]; then echo enter; fi; + if [[ $key = [xX] ]]; then echo exit; fi; + if [[ $key = $'\x20' ]]; then echo space; fi; + if [[ $key = $'\x1b' ]]; then + read -rsn2 key + if [[ $key = [A ]]; then echo up; fi; + if [[ $key = [B ]]; then echo down; fi; + if [[ $key = [D ]]; then echo back; fi; + fi;} + toggle_option() { + local arr_name=$1 + eval "local arr=(\"\${${arr_name}[@]}\")" + local option=$2 + if [[ ${arr[option]} == true ]]; then + arr[option]= + else + arr[option]=true + fi + eval $arr_name='("${arr[@]}")';} + + local retval=$1 + local options + local defaults + + IFS=';' read -r -a options <<< "$2" + if [[ -z $3 ]]; then + defaults=() + else + IFS=';' read -r -a defaults <<< "$3" + fi + local selected=() + + for ((i=0; i<${#options[@]}; i++)); do + selected+=("${defaults[i]}") + printf "\n" + done + + # determine current screen position for overwriting the options + local lastrow=`get_cursor_row` + local startrow=$(($lastrow - ${#options[@]})) + + # ensure cursor and input echoing back on upon a ctrl+c during read -s + trap "cursor_blink_on; stty echo; printf '\n'; exit" 2 + cursor_blink_off + local active=0 + while true; do + # print options by overwriting the last lines + local idx=0 + for option in "${options[@]}"; do + local prefix="[ ]" + if [[ ${selected[idx]} == true ]]; then + prefix="[x]" + fi + + cursor_to $(($startrow + $idx)) + if [ $idx -eq $active ]; then + if [ $option == OEM ]; then + TPUT $((idx+6)) 6 + print_active "$option" "$prefix" + TPUT $((idx+7)) 11 + $e "Run a setup wizard on the next boot" + elif [ $option == FORCE ]; then + TPUT $((idx+8)) 6 + print_active "$option" "$prefix" + TPUT $((idx+9)) 11 + $e "Force desktop package install" + fi + else + if [ $option == OEM ]; then + TPUT $((idx+6)) 6 + print_inactive "$option" "$prefix" + TPUT $((idx+7)) 11 + $e "Run a setup wizard on the next boot" + elif [ $option == FORCE ]; then + TPUT $((idx+8)) 6 + print_inactive "$option" "$prefix" + TPUT $((idx+9)) 11 + $e "Force desktop package install" + fi + fi + ((idx++)) + done + + # user key control + case `key_input` in + space) toggle_option selected $active;; + enter) break;; + up) ((active--)); + if [ $active -lt 0 ]; then active=$((${#options[@]} - 1)); fi;; + down) ((active++)); + if [ $active -ge ${#options[@]} ]; then active=0; fi;; + back) CLEAR; exec $0;; + exit) CLEAR;exit 0;; + esac + done + + # cursor position back to normal + cursor_to $lastrow + printf "\n" + cursor_blink_on + eval $retval='("${selected[@]}")' + } + + RUN(){ + if [[ $cur != back ]];then + R;HEAD_II "$1" + FOOT_II; + + MSEL result "OEM;FORCE" "false;;false" + CLEAR + ARG= + if [[ ${result[0]} == true ]]; then + ARG="--oem" + fi + if [[ ${result[1]} == true ]]; then + ARG="$ARG --force" + fi + + $E "sudo ./desktopify $ARG --de $1" + sudo ./desktopify $ARG --de $1 + + break + fi + } + + # ensure cursor and input echoing back on upon a ctrl+c during read -s + trap "cursor_blink_on; stty echo; printf '\n'; exit" 2 + cursor_blink_off + while [[ "$O" != " " ]] && [[ $cur != exit ]]; do case $i in + 0) S=M0;SC;if [[ $cur == enter ]];then RUN lubuntu; fi;; + 1) S=M1;SC;if [[ $cur == enter ]];then RUN kubuntu; fi;; + 2) S=M2;SC;if [[ $cur == enter ]];then RUN ubuntu; fi;; + 3) S=M3;SC;if [[ $cur == enter ]];then RUN ubuntu-budgie; fi;; + 4) S=M4;SC;if [[ $cur == enter ]];then RUN ubuntu-kylin; fi;; + 5) S=M5;SC;if [[ $cur == enter ]];then RUN ubuntu-mate; fi;; + 6) S=M6;SC;if [[ $cur == enter ]];then RUN ubuntu-studio; fi;; + 7) S=M7;SC;if [[ $cur == enter ]];then RUN xubuntu; fi;; + 8) S=M8;SC;if [[ $cur == enter ]];then R;exit 0;fi;; + esac;POS;done + + CLEAR + cursor_blink_on \ No newline at end of file diff --git a/UFW-Blocklist/README.md b/UFW-Blocklist/old_blocklist/README.md similarity index 100% rename from UFW-Blocklist/README.md rename to UFW-Blocklist/old_blocklist/README.md diff --git a/UFW-Blocklist/old_blocklist/after.init b/UFW-Blocklist/old_blocklist/after.init new file mode 100644 index 0000000..749581b --- /dev/null +++ b/UFW-Blocklist/old_blocklist/after.init @@ -0,0 +1,172 @@ +#!/bin/bash +# +# after.init: if executable, called by ufw-init. See 'man ufw-framework' for +# details. Note that output from these scripts is not seen via the +# the ufw command, but instead via ufw-init. +# +############################################################################### +#### #### +#### Based on ufw-blocklist edition: IP blocklist extension for Ubuntu ufw #### +#### https://github.com/poddmo/ufw-blocklist #### +#### #### +#### Modified https://mylinux.work #### +#### Version 1.0.2.061324 #### +#### Contact: contact@mylinux.work #### +#### #### +############################################################################### +set -e + +export ipsetname=ufw-blocklist-ipsum + +# seed file containing the list of IP addresses to be blocked, one per line +export seedlist=/etc/ipsum.ipv4.txt + +export IPSET_EXE="/sbin/ipset" +# check ipset exists and is executable +[ -x "$IPSET_EXE" ] || { + echo "$IPSET_EXE is not executable" + exit 1 + } + +# Function to check if a chain exists +chain_exists() { + { + [ $# -lt 1 ] || [ $# -gt 2 ] && { + echo "Usage: chain_exists [table]" >&2 + return 1 + } + + local chain_name="$1" ; shift + [ $# -eq 1 ] && local table="--table $1" + iptables "$table" -n --list "$chain_name" >/dev/null 2>&1 + } +} + +# Function to check if an set exists (set_exists setname && action if true || action if false) +set_exists() { + { + [ $# -ne 1 ] && { + echo "Usage: set_exists " >&2 + return 1 + } + + local set_name="$1" + ipset list "$set_name" -name >/dev/null 2>&1 + } +} + +case "$1" in +start) + # check that blocklist seed file exists + if [ ! -f "$seedlist" ]; then + echo "ufw after.init: $seedlist does not exist." + exit 1 + fi + + # create an empty ipset + $IPSET_EXE create $ipsetname hash:net -exist + $IPSET_EXE flush $ipsetname + + ## Insert firewall rules to take precedence, removing them and adding them back if they already existed + # Block inbound to localhost from blocklist + if chain_exists ufw-blocklist-input; then + iptables -D INPUT -m set --match-set $ipsetname src -j ufw-blocklist-input || true + iptables -F ufw-blocklist-input + iptables -X ufw-blocklist-input + fi + + iptables -N ufw-blocklist-input + iptables -A ufw-blocklist-input -j DROP -m comment --comment "ufw-blocklist-input" + iptables -I INPUT -m set --match-set $ipsetname src -j ufw-blocklist-input + + # Log and drop outbound to blocklist. Hits here may indicate compromised localhost + if chain_exists ufw-blocklist-output; then + iptables -D OUTPUT -m set --match-set $ipsetname dst -j ufw-blocklist-output || true + iptables -F ufw-blocklist-output + iptables -X ufw-blocklist-output + fi + + iptables -N ufw-blocklist-output + iptables -A ufw-blocklist-output -j LOG --log-level 3 --log-prefix "[UFW BLOCKLIST OUTPUT] " -m limit --limit 3/minute --limit-burst 10 + iptables -A ufw-blocklist-output -j DROP -m comment --comment "ufw-blocklist-output" + iptables -I OUTPUT -m set --match-set $ipsetname dst -j ufw-blocklist-output + + # Log and drop forwarding to blocklist. Hits here may indicate compromised internal hosts + if chain_exists ufw-blocklist-forward; then + iptables -D FORWARD -m set --match-set $ipsetname dst -j ufw-blocklist-forward || true + iptables -F ufw-blocklist-forward + iptables -X ufw-blocklist-forward + fi + + iptables -N ufw-blocklist-forward + iptables -A ufw-blocklist-forward -j LOG --log-level 3 --log-prefix "[UFW BLOCKLIST FORWARD] " -m limit --limit 3/minute --limit-burst 10 + iptables -A ufw-blocklist-forward -j DROP -m comment --comment "ufw-blocklist-forward" + iptables -I FORWARD -m set --match-set $ipsetname dst -j ufw-blocklist-forward + + # add members to the ipset + # start this in a subshell and then disown the job so we return quickly. + ( + while read -r ip < "$seedlist" + do + $IPSET_EXE add "$ipsetname" "$ip" + done + ) < /dev/null &> /dev/null & disown -h + ;; +stop) + + # delete resources created above + if chain_exists ufw-blocklist-input; then + iptables -D INPUT -m set --match-set $ipsetname src -j ufw-blocklist-input || true + iptables -F ufw-blocklist-input + iptables -X ufw-blocklist-input + fi + + if chain_exists ufw-blocklist-output; then + iptables -D OUTPUT -m set --match-set $ipsetname dst -j ufw-blocklist-output || true + iptables -F ufw-blocklist-output + iptables -X ufw-blocklist-output + fi + + if chain_exists ufw-blocklist-forward; then + iptables -D FORWARD -m set --match-set $ipsetname dst -j ufw-blocklist-forward || true + iptables -F ufw-blocklist-forward + iptables -X ufw-blocklist-forward + fi + + if set_exists $ipsetname; then + $IPSET_EXE flush $ipsetname + $IPSET_EXE destroy $ipsetname + fi + ;; +status) + # display details of the ipset + $IPSET_EXE list "$ipsetname" -t + + # show iptables hit/byte counts + iptables -L -nvx | grep "$ipsetname" | grep 'match-set' + + # show the last 10 lines from the logs + journalctl | grep -i blocklist | tail + ;; +flush-all) + # flush sets created above. Use /etc/cron.daily/ufw-blocklist-ipsum to repopulate + $IPSET_EXE flush $ipsetname + + # reset iptables accounting + ipz=$( iptables -L INPUT -nvx --line-numbers | grep ufw-blocklist-input | awk '{print $1}') + iptables -Z INPUT "$ipz" + iptables -Z ufw-blocklist-input + + ipz=$( iptables -L OUTPUT -nvx --line-numbers | grep ufw-blocklist-output | awk '{print $1}') + iptables -Z OUTPUT "$ipz" + iptables -Z ufw-blocklist-output + + ipz=$( iptables -L FORWARD -nvx --line-numbers | grep ufw-blocklist-forward | awk '{print $1}') + iptables -Z FORWARD "$ipz" + iptables -Z ufw-blocklist-forward + ;; +*) + echo "'$1' not supported" + echo "Usage: /etc/ufw/after.init {start|stop|flush-all|status}" + ;; +esac diff --git a/UFW-Blocklist/after.init_run-parts b/UFW-Blocklist/old_blocklist/after.init_run-parts similarity index 100% rename from UFW-Blocklist/after.init_run-parts rename to UFW-Blocklist/old_blocklist/after.init_run-parts diff --git a/UFW-Blocklist/old_blocklist/setup-ufw.sh b/UFW-Blocklist/old_blocklist/setup-ufw.sh new file mode 100644 index 0000000..4053f58 --- /dev/null +++ b/UFW-Blocklist/old_blocklist/setup-ufw.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash + +# ################################################## +# ufw-ipset-blocklist-autoupdate +# +# Blocking lists of IPs from public blacklists / blocklists (e.g. blocklist.de, spamhaus.org) +# +# Version: 1.1.1 +# +# See: https://github.com/ngandrass/ufw-ipset-blacklist-autoupdate +# ################################################## + +UFW_CONF_DIR=/etc/ufw +UFW_AFTER_INIT_FILE=$UFW_CONF_DIR/after.init +IPSET_DIR="/var/lib/ipset" # Folder to write ipset save files to +CONFIGURE_IPV6=0 + +# Let user abort +read -r -p "Configure UFW to block IPs listed in blocklist ipsets? [Y/n] " ret +case "$ret" in + [nN][oO]|[nN]) exit + ;; + *) + ;; +esac + +read -r -p "Would you like to enable IPv6 support? [Y/n] " ret +case "$ret" in + [nN][oO]|[nN]) CONFIGURE_IPV6=0 + ;; + *) + CONFIGURE_IPV6=1 + ;; +esac + +#get required files +cd /tmp || exit 2 +wget autoupdate-blocklist.sh +mv /tmp/autoupdate-blocklist.sh /usr/local/bin/ +chmod 755 /usr/local/bin/autoupdate-blocklist.sh + +wget https://files.mylinux.work/ /download/after.init.ipv4 +wget https://after.init.ipv6/ /download/after.init.ipv6 + +# Ensure that IPSET_DIR exists +if [ ! -d "$IPSET_DIR" ]; then + mkdir -p "$IPSET_DIR" || exit +fi + +# Check that ufw has IPv6 enabled +if [[ "$CONFIGURE_IPV6" == 1 ]]; then + if ! grep -q -E "IPV6=(yes|YES)" /etc/default/ufw; then + echo "ERROR: IPv6 rules requested but UFW is not configured to use IPv6. Set IPV6=yes in /etc/default/ufw and rerun this script." + exit 1 + fi +fi + +# Check if file already exists. +if [ -f "$UFW_AFTER_INIT_FILE" ]; then + read -r -p "The file $UFW_UFW_AFTER_INIT_FILE already exists. Are you sure that you want to overwrite it? [y/N] " ret + case "$ret" in + [yY][eE][sS]|[yY]) + # continue + ;; + *) + exit + ;; + esac +fi + +# Deploy after.init +if [[ "$CONFIGURE_IPV6" == 1 ]]; then + mv /tmp/after.init.ipv6 /tmp/after6.init + mv "/tmp/after6.init" "$UFW_AFTER_INIT_FILE" || exit +else + mv /tmp/after.init.ipv6 /tmp/after.init + mv "/tmp/after.init" "$UFW_AFTER_INIT_FILE" || exit +fi +chmod 755 "$UFW_AFTER_INIT_FILE" +echo "Deployed $UFW_UFW_AFTER_INIT_FILE" + +# Restart ufw +read -r -p "Reload ufw to apply changes? [Y/n] " ret +case "$ret" in + [nN][oO]|[nN]) exit + ;; + *) + ufw reload + ;; +esac \ No newline at end of file diff --git a/UFW-Blocklist/ufw-blocklist-ipsum b/UFW-Blocklist/old_blocklist/ufw-blocklist-ipsum similarity index 100% rename from UFW-Blocklist/ufw-blocklist-ipsum rename to UFW-Blocklist/old_blocklist/ufw-blocklist-ipsum diff --git a/UFW-Blocklist/ufw_blocklist.sh b/UFW-Blocklist/old_blocklist/ufw_blocklist.sh similarity index 100% rename from UFW-Blocklist/ufw_blocklist.sh rename to UFW-Blocklist/old_blocklist/ufw_blocklist.sh diff --git a/UFW-Blocklist/ufw-blocklists.sh b/UFW-Blocklist/ufw-blocklists.sh new file mode 100644 index 0000000..8b6ad05 --- /dev/null +++ b/UFW-Blocklist/ufw-blocklists.sh @@ -0,0 +1,284 @@ +#!/usr/bin/env bash + +# ################################################## +# ufw-ipset-blocklist-autoupdate +# +# Blocking lists of IPs from public blocklists / blacklists (e.g. blocklist.de, spamhaus.org) +# +# Version: 1.1.1 +# +# See: https://github.com/ngandrass/ufw-ipset-blocklist-autoupdate +# ################################################## + +IPSET_BIN="/usr/bin/ipset" # Path to ipset binary. Updated by detect_ipset(). +IPSET_DIR="/var/lib/ipset" # Folder to write ipset save files to +IPSET_PREFIX="bl" # Prefix for ipset names +IPSET_TYPE="hash:net" # Type of created ipsets +IPV4=1 # Enable IPv4 by default +IPV6=1 # Enable IPv6 by default +QUIET=0 # Default quiet mode setting +VERBOSE=0 # Default verbosity level +declare -A BLOCKLISTS # Array for blocklists to use. Populated by CLI args, +IPV4_REGEX="(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(/[1-3]?[0-9])?" # Regex for a valid IPv4 address with optional subnet part +IPV6_REGEX="(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(/[1-6]?[0-9])?" # Regef for a valid IPv6 address with optional subnet part + +## +# Prints the help/usage message +## +function print_usage() { + { + cat << EOF + Usage: $0 [-h] + Blocking lists of IPs from public blocklists / blacklists (e.g. blocklist.de, spamhaus.org) + + Options: + -l : Blocklist to use. Can be specified multiple times. + Format: "\$name \$url" (space-separated). See examples below. + -4 : Run in IPv4 only mode. Ignore IPv6 addresses. + -6 : Run in IPv6 only mode. Ignore IPv4 addresses. + -q : Quiet mode. Outputs are suppressed if flag is present. + -v : Verbose mode. Prints additional information during execution. + -h : Print this help message. + + Example usage: + $0 -l "spamhaus https://www.spamhaus.org/drop/drop.txt" + $0 -l "blocklist https://lists.blocklist.de/lists/all.txt" -l "spamhaus https://www.spamhaus.org/drop/drop.txt" + $0 -l "spamhaus https://www.spamhaus.org/drop/drop.txt" -l "spamhaus6 https://www.spamhaus.org/drop/dropv6.txt" +EOF + } +} + +## +# Writes argument $1 to stdout if $QUIET is not set +# +# Arguments: +# $1 Message to write to stdout +## +function log() { + { + if [[ $QUIET -eq 0 ]]; then + echo "$1" + fi + } +} + +## +# Writes argument $1 to stdout if $VERBOSE is set and $QUIET is not set +# +# Arguments: +# $1 Message to write to stdout +## +function log_verbose() { + { + if [[ $VERBOSE -eq 1 ]]; then + if [[ $QUIET -eq 0 ]]; then + echo "$1" + fi + fi + } +} + +## +# Writes argument $1 to stderr. Ignores $QUIET. +# +# Arguments: +# $1 Message to write to stderr +## +function log_error() { + { + >&2 echo "[ERROR]: $1" + } +} + +## +# Detects ipset binary +# +# Return: Path to ipset +# +function detect_ipset() { + { + IPSET_BIN=$(which ipset) + if [ ! -x "${IPSET_BIN}" ]; then + log_error "ipset binary not found." + exit 1 + fi + + echo "${IPSET_BIN}" + } +} + +## +# Validates the correctness of the BLOCKLISTS array. Exits upon error. +# +function validate_blocklists() { + { + if [ ${#BLOCKLISTS[@]} -eq 0 ]; then + log_error "No blocklists given. Exiting..." + print_usage + exit 1 + fi + + for list in "${BLOCKLISTS[@]}" + do + list_name=$(echo "$list" | cut -d ' ' -f 1) + list_url=$(echo "$list" | cut -d ' ' -f 2) + + if [ -z "$list_name" ]; then + log_error "Invalid name for list: $list" + exit 1 + fi + + if [ -z "$list_url" ]; then + log_error "Invalid url for list: $list" + exit 1 + fi + + log_verbose "Found valid blocklist: name=${list_name}, url=${list_url}" + done + } +} + +## +# Updates an ipset based on a list of IP addresses +# +# Arguments: +# $1 Name of the ipset to update +# $2 File containing all IP addresses to store in ipset +# $3 Procotol family (e.g. inet OR inet6) +function update_ipset() { + { + # Setup local vars + local setname=$1 + local ipfile=$2 + local family=$3 + + # Create temporary ipset to build and ensure existence of live ipset + local livelist="$setname-$family" + local templist="$setname-$family-T" + + $IPSET_BIN create -q "$livelist" "$IPSET_TYPE" family "$family" + $IPSET_BIN create -q "$templist" "$IPSET_TYPE" family "$family" + log_verbose "Prepared ipset lists: livelist='$livelist', templist='$templist'" + + while read -r ip; do + if $IPSET_BIN add "$templist" "$ip"; then + log_verbose "Added '$ip' to '$templist'" + else + log "Failed to add '$ip' to '$templist'" + fi + done < "$ipfile" + + $IPSET_BIN swap "$templist" "$livelist" + log_verbose "Swapped ipset: $livelist" + + $IPSET_BIN destroy "$templist" + log_verbose "Destroyed ipset: $templist" + + # Write ipset savefile + $IPSET_BIN save "$livelist" > "$IPSET_DIR/$livelist.save" + log_verbose "Wrote savefile for '$livelist' to: $IPSET_DIR/$livelist.save" + log "Added $(wc -l < "$ipfile") to ipset '$livelist'" + } +} + +## +# Updates the given blocklist from an URL +# +# Arguments: +# $1 Name of the blocklist +# $2 URL of the blocklist +# +function update_blocklist() { + { + # Download blocklist + log "Updating blacklist '$1' ..." + log_verbose "Downloading blocklist '$1' from: $2 ..." + tempfile=$(mktemp "/tmp/blocklist.$1.XXXXXXXX") + wget -q -O "$tempfile" "$2" + + # Check downloaded list + linecount=$(wc -l < "$tempfile") + if [ "$linecount" -lt 10 ]; then + log_error "Blacklist '$1' containes only $linecount lines. This seems to short. Exiting..." + exit 1 + fi + + # Extract ips from raw list data + if [[ $IPV4 -eq 1 ]]; then + grep -v '^[#;]' "$tempfile" | grep -E -o "$IPV4_REGEX" | cut -d ' ' -f 1 > "$tempfile.filtered" + numips=$(wc -l < "$tempfile.filtered") + log_verbose "Got $numips IPv4 entries from blocklist '$1'" + + if [[ $numips -gt 0 ]]; then + update_ipset "${IPSET_PREFIX}-$1" "$tempfile.filtered" "inet" + else + log_verbose "No IPv4 addresses found in blocklist '$1'. Skipping" + fi + elif [[ $IPV6 -eq 1 ]]; then + grep -v '^[#;]' "$tempfile" | grep -E -o "$IPV6_REGEX" | cut -d ' ' -f 1 > "$tempfile.filtered6" + numips=$(wc -l < "$tempfile.filtered6") + log_verbose "Got $numips IPv6 entries from blocklist '$1'" + + if [[ $numips -gt 0 ]]; then + update_ipset "${IPSET_PREFIX}-$1" "$tempfile.filtered6" "inet6" + else + log_verbose "No IPv6 addresses found in blocklist '$1'. Skipping" + fi + fi + + # Cleanup + rm "$tempfile"* + } +} + +## +# Main program loop +## +function main() { + { + # Check arguments + validate_blocklists + + # Setup ipset + IPSET_BIN=$(detect_ipset) + mkdir -p "${IPSET_DIR}" + + # Update blocklists + for list in "${BLOCKLISTS[@]}"; do + list_name=$(echo "$list" | cut -d ' ' -f 1) + list_url=$(echo "$list" | cut -d ' ' -f 2) + + update_blocklist "$list_name" "$list_url" + done + } +} + +# Parse arguments +while getopts ":hqv46l:" opt + do + case ${opt} in + l) BLOCKLISTS[${#BLOCKLISTS[@]}]=${OPTARG} + ;; + 4) IPV4=1 + IPV6=0 + log "Using IPv4 only mode. Skipping IPv6 addresses." + ;; + 6) IPV4=0 + IPV6=1 + log "Using IPv6 only mode. Skipping IPv4 addresses." + ;; + q) QUIET=1 + ;; + v) VERBOSE=1 + ;; + h) print_usage; exit + ;; + :) print_usage; exit + ;; + \?) print_usage; exit + ;; + esac + done + +# Entry point +main \ No newline at end of file diff --git a/UFW-Blocklist/ufw-test.sh b/UFW-Blocklist/ufw-test.sh new file mode 100644 index 0000000..c99ce35 --- /dev/null +++ b/UFW-Blocklist/ufw-test.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +TMP_DIR="/tmp" +URL_LINKS=$"http://www.blocklist.de/lists/ssh.txt +http://www.blocklist.de/lists/apache.txt +http://www.blocklist.de/lists/asterisk.txt +http://www.blocklist.de/lists/bots.txt +http://www.blocklist.de/lists/courierimap.txt +http://www.blocklist.de/lists/courierpop3.txt +http://www.blocklist.de/lists/email.txt +http://www.blocklist.de/lists/ftp.txt +http://www.blocklist.de/lists/imap.txt +http://www.blocklist.de/lists/ircbot.txt +http://www.blocklist.de/lists/pop3.txt +http://www.blocklist.de/lists/postfix.txt +http://www.blocklist.de/lists/proftpd.txt +http://www.blocklist.de/lists/sip.txt +http://www.ciarmy.com/list/ci-badguys.txt +http://charles.the-haleys.org/ssh_dico_attack_hdeny_format.php/hostsdeny.txt +http://www.nothink.org/blacklist/blacklist_ssh_day.txt +http://malc0de.com/bl/IP_Blacklist.txt +http://www.nothink.org/blacklist/blacklist_malware_dns.txt +http://www.nothink.org/blacklist/blacklist_malware_http.txt +http://www.nothink.org/blacklist/blacklist_malware_irc.txt" + + +function denyHost() { + sudo ufw deny from $1; +} + +function getLists() { + if [[ ! -d "${BACKUP_DIR}" ]]; then + mkdir -p "${BACKUP_DIR}"; + fi; + for line in echo ${URL_LINKS}; do + filename=$(python -c 'import string; import random; acc=string.ascii_letters; d=["".join([random.choice(acc) for _ in range(1)]) for _ in range(7)]; print("".join(d))') + writeTo="${TMP_DIR}/${filename}.deny"; + touch $writeTo; + curl -o "${writeTo}" $line; + while read item; do + denyHost $item; + done < "${writeTo}"; + done; +} + +getLists; \ No newline at end of file diff --git a/auth-log-lookup.sh b/auth-log-lookup.sh new file mode 100644 index 0000000..9210d91 --- /dev/null +++ b/auth-log-lookup.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Install geoiplookup if needed +if [ ! "$(command -v geoiplookup)" ]; then + apt -y install geoip-bin +fi + +# Colors for Location/Address +BB="\033[1;34m" # Blue bold +BW="\033[1;37m" # Bold White +BY="\033[1;33m" # Bold Yellow +GR="\033[0;32m" # Green +LY="\033[3;33m" # Light Yellow +RB="\033[1;31m" # Red bold (Default) + +LOGFILE=/var/log/auth.log # Log file +LINE=0 # Where to start count +NC="\033[00m" # Color Reset + +while true + do + for i in $(cat $LOGFILE | awk "NR>$LINE" | grep Invalid | awk '{print $(NF-2)}' | uniq) + do + LINE=$(cat $LOGFILE | wc -l) + # Detect if IPv4 address for lookups + if [ "$i" != "${i#*[0-9].[0-9]}" ]; then + LOCATION=$(geoiplookup "$i" | awk '{print $5 " " $6}') + else + LOCATION=$(geoiplookup6 "$i" | awk '{print $6 " " $7}') + fi + echo -e "[*] The Attacker's Country: ${RB}$LOCATION ${NC}[IP ADDRESS:${RB} $i] ${NC}" + + done + sleep 2 + done \ No newline at end of file diff --git a/firewalld-blocklist/ipset-blacklist.conf b/firewalld-blocklist/ipset-blacklist.conf new file mode 100644 index 0000000..2f85865 --- /dev/null +++ b/firewalld-blocklist/ipset-blacklist.conf @@ -0,0 +1,27 @@ +IPSET_BLACKLIST_NAME=blacklist # change it if it collides with a pre-existing ipset list +IPSET_TMP_BLACKLIST_NAME=${IPSET_BLACKLIST_NAME}-tmp + +# ensure the directory for IP_BLACKLIST/IP_BLACKLIST_RESTORE exists (it won't be created automatically) +IP_BLACKLIST_RESTORE=/etc/ipset-blacklist/ip-blacklist.restore +IP_BLACKLIST=/etc/ipset-blacklist/ip-blacklist.list + +VERBOSE=yes # probably set to "no" for cron jobs, default to yes +FORCE=yes # will create the ipset-iptable binding if it does not already exist +let IPTABLES_IPSET_RULE_NUMBER=1 # if FORCE is yes, the number at which place insert the ipset-match rule (default to 1) + +# Sample (!) list of URLs for IP blacklists. Currently, only IPv4 is supported in this script, everything else will be filtered. +BLACKLISTS=( + # "file:///etc/ipset-blacklist/ip-blacklist-custom.list" # optional, for your personal nemeses (no typo, plural) + "https://www.projecthoneypot.org/list_of_ips.php?t=d&rss=1" # Project Honey Pot Directory of Dictionary Attacker IPs + "https://check.torproject.org/cgi-bin/TorBulkExitList.py?ip=1.1.1.1" # TOR Exit Nodes + "http://danger.rulez.sk/projects/bruteforceblocker/blist.php" # BruteForceBlocker IP List + "https://www.spamhaus.org/drop/drop.lasso" # Spamhaus Don't Route Or Peer List (DROP) + "https://cinsscore.com/list/ci-badguys.txt" # C.I. Army Malicious IP List + "https://lists.blocklist.de/lists/all.txt" # blocklist.de attackers + "https://blocklist.greensnow.co/greensnow.txt" # GreenSnow + "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset" # Firehol Level 1 + "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/stopforumspam_7d.ipset" # Stopforumspam via Firehol + # "https://raw.githubusercontent.com/ipverse/rir-ip/master/country/zz/ipv4-aggregated.txt" # Ban an entire country(-code), see https://github.com/ipverse/rir-ip + # "https://raw.githubusercontent.com/ipverse/asn-ip/master/as/1234/ipv4-aggregated.txt" # Ban a specific autonomous system (ISP), see https://github.com/ipverse/asn-ip +) +MAXELEM=131072 \ No newline at end of file diff --git a/firewalld-blocklist/rh-blocklist b/firewalld-blocklist/rh-blocklist new file mode 100644 index 0000000..e6ba257 --- /dev/null +++ b/firewalld-blocklist/rh-blocklist @@ -0,0 +1,83 @@ +#!/bin/bash +exec 3>&1 4>&2 +trap 'exec 2>&4 1>&3' 0 1 2 3 +exec 1>log.out 2>&1 +set -x +# Everything below will go to the file 'log.out': +source pid.sh +IP_TMP=/tmp/ip.tmp +IP_BLOCKLIST=/etc/ip-blocklist.conf +IP_BLOCKLIST_TMP=/tmp/ip-blocklist.tmp +IP_BLOCKLIST_CUSTOM=/etc/ip-blocklist-custom.conf # optional +BLACKLISTS=( +"http://www.projecthoneypot.org/list_of_ips.php?t=d&rss=1" # Project Honey Pot Directory of Dictionary Attacker IPs +"http://check.torproject.org/cgi-bin/TorBulkExitList.py?ip=1.1.1.1" # TOR Exit Nodes +"http://www.maxmind.com/en/anonymous_proxies" # MaxMind GeoIP Anonymous Proxies +"https://www.maxmind.com/en/high-risk-ip-sample-list" # MaxMind High Risk Sample List +"http://danger.rulez.sk/projects/bruteforceblocker/blist.php" # BruteForceBlocker IP List +"https://rules.emergingthreats.net/blockrules/compromised-ips.txt" # Emerging Threats - Russian Business Networks List +"http://www.spamhaus.org/drop/drop.lasso" # Spamhaus Don't Route Or Peer List (DROP) +"http://cinsscore.com/list/ci-badguys.txt" # C.I. Army Malicious IP List +"http://www.autoshun.org/files/shunlist.csv" # Autoshun Shun List +"http://lists.blocklist.de/lists/all.txt" # blocklist.de fail2ban reporting service +"https://fx.vc-mp.eu/shared/iplist.txt" # ferex badlist +"https://feodotracker.abuse.ch/downloads/ipblocklist_aggressive.txt" # FEODO tracker +"https://reputation.alienvault.com/reputation.generic" # ALIENVAULT REPUTATION +"http://www.darklist.de/raw.php" # DARKLIST DE +"http://osint.bambenekconsulting.com/feeds/c2-dommasterlist-high.txt" +"http://osint.bambenekconsulting.com/feeds/c2-dommasterlist.txt" +"http://osint.bambenekconsulting.com/feeds/c2-ipmasterlist-high.txt" +"http://osint.bambenekconsulting.com/feeds/c2-ipmasterlist.txt" +"http://osint.bambenekconsulting.com/feeds/c2-masterlist.txt" +"http://osint.bambenekconsulting.com/feeds/dga-feed.txt" +"https://www.binarydefense.com/banlist.txt" # Binary Defense Systems +"https://raw.githubusercontent.com/stamparm/ipsum/master/ipsum.txt" # https://github.com/stamparm/ipsum +"http://sblam.com/blacklist.txt" # SBLAM +"http://blocklist.greensnow.co/greensnow.txt" +"http://charles.the-haleys.org/ssh_dico_attack_hdeny_format.php/hostsdeny.txt" +"https://www.malwaredomainlist.com/hostslist/ip.txt" +"https://www.stopforumspam.com/downloads/toxic_ip_cidr.txt" +) + +for i in "${BLACKLISTS[@]}" + do + curl "$i" > $IP_TMP + grep -Po '(?:\d{1,3}.){3}\d{1,3}(?:/\d{1,2})?' $IP_TMP >> $IP_BLOCKLIST_TMP + done + +#Get the iblocklist +wget -qO- http://list.iblocklist.com/?list=erqajhwrxiuvjxqrrwfj&fileformat=p2p&archiveformat=gz > $_input || { echo "$0: Unable to download ip list."; exit 1; } + +#Consolidate iblocklist into master list +cat "$_input" >> $IP_BLOCKLIST_TMP + +#Consolidate the shodan.io IP addresses database +cat /opt/blocklist/shodan.txt >> $IP_BLOCKLIST_TMP + +#Sort the list +sort $IP_BLOCKLIST_TMP -n | uniq > $IP_BLOCKLIST + +#Remove temporary list +rm $IP_BLOCKLIST_TMP + +#count how many IP addresses are in the list +wc -l $IP_BLOCKLIST + +#Flush the ipset +/usr/sbin/ipset flush blocklist + +#Add IP addresses to the ipset +grep -v "^#|^$" $IP_BLOCKLIST | while IFS= read -r ip; +do + /usr/sbin/ipset add blocklist "$ip"; +done + +### Section for firewalld +firewall-cmd --delete-ipset=blocklist --permanent +firewall-cmd --permanent --new-ipset=blocklist --type=hash:net --option=family=inet --option=hashsize=1048576 --option=maxelem=1048576 +firewall-cmd --permanent --ipset=blocklist --add-entries-from-file=/etc/ip-blocklist.conf +firewall-cmd --reload +echo "Firewalld ipset list entries:" +firewall-cmd --permanent --ipset=blocklist --get-entries | wc -l +echo "ipset list entries:" +cat /etc/ip-blocklist.conf | wc -l diff --git a/firewalld-blocklist/update-blacklist.sh b/firewalld-blocklist/update-blacklist.sh new file mode 100644 index 0000000..d54eb00 --- /dev/null +++ b/firewalld-blocklist/update-blacklist.sh @@ -0,0 +1,117 @@ +#!/usr/bin/env bash +# +# usage update-blacklist.sh +# eg: update-blacklist.sh /etc/ipset-blacklist/ipset-blacklist.conf +# +function exists() { command -v "$1" >/dev/null 2>&1; } + +if [[ -z "$1" ]]; then + echo "Error: please specify a configuration file, e.g. $0 /etc/ipset-blacklist/ipset-blacklist.conf" + exit 1 +fi + +# shellcheck source=ipset-blacklist.conf +if ! source "$1"; then + echo "Error: can't load configuration file $1" + exit 1 +fi + +if ! exists curl && exists egrep && exists grep && exists ipset && exists iptables && exists sed && exists sort && exists wc; then + echo >&2 "Error: searching PATH fails to find executables among: curl egrep grep ipset iptables sed sort wc" + exit 1 +fi + +DO_OPTIMIZE_CIDR=no +if exists iprange && [[ ${OPTIMIZE_CIDR:-yes} != no ]]; then + DO_OPTIMIZE_CIDR=yes +fi + +if [[ ! -d $(dirname "$IP_BLACKLIST") || ! -d $(dirname "$IP_BLACKLIST_RESTORE") ]]; then + echo >&2 "Error: missing directory(s): $(dirname "$IP_BLACKLIST" "$IP_BLACKLIST_RESTORE" | sort -u)" + exit 1 +fi + +# create the ipset if needed (or abort if does not exists and FORCE=no) +if ! ipset list -n | command grep -q "$IPSET_BLACKLIST_NAME"; then + if [[ ${FORCE:-no} != yes ]]; then + echo >&2 "Error: ipset does not exist yet, add it using:" + echo >&2 "# ipset create $IPSET_BLACKLIST_NAME -exist hash:net family inet hashsize ${HASHSIZE:-16384} maxelem ${MAXELEM:-65536}" + exit 1 + fi + + if ! ipset create "$IPSET_BLACKLIST_NAME" -exist hash:net family inet hashsize "${HASHSIZE:-16384}" maxelem "${MAXELEM:-65536}"; then + echo >&2 "Error: while creating the initial ipset" + exit 1 + fi +fi + +# create the iptables binding if needed (or abort if does not exists and FORCE=no) +if ! iptables -nvL INPUT | command grep -q "match-set $IPSET_BLACKLIST_NAME"; then + # we may also have assumed that INPUT rule n°1 is about packets statistics (traffic monitoring) + if [[ ${FORCE:-no} != yes ]]; then + echo >&2 "Error: iptables does not have the needed ipset INPUT rule, add it using:" + echo >&2 "# iptables -I INPUT ${IPTABLES_IPSET_RULE_NUMBER:-1} -m set --match-set $IPSET_BLACKLIST_NAME src -j DROP" + exit 1 + fi + + if ! iptables -I INPUT "${IPTABLES_IPSET_RULE_NUMBER:-1}" -m set --match-set "$IPSET_BLACKLIST_NAME" src -j DROP; then + echo >&2 "Error: while adding the --match-set ipset rule to iptables" + exit 1 + fi +fi + +IP_BLACKLIST_TMP=$(mktemp) +for i in "${BLACKLISTS[@]}"; do + IP_TMP=$(mktemp) + ((HTTP_RC = $(curl -L -A "blacklist-update/script/github" --connect-timeout 10 --max-time 10 -o "$IP_TMP" -s -w "%{http_code}" "$i"))) + if ((HTTP_RC == 200 || HTTP_RC == 302 || HTTP_RC == 0)); then # "0" because file:/// returns 000 + command grep -Po '^(?:\d{1,3}\.){3}\d{1,3}(?:/\d{1,2})?' "$IP_TMP" | sed -r 's/^0*([0-9]+)\.0*([0-9]+)\.0*([0-9]+)\.0*([0-9]+)$/\1.\2.\3.\4/' >>"$IP_BLACKLIST_TMP" + [[ ${VERBOSE:-yes} == yes ]] && echo -n "." + elif ((HTTP_RC == 503)); then + echo -e "\\nUnavailable (${HTTP_RC}): $i" + else + echo >&2 -e "\\nWarning: curl returned HTTP response code $HTTP_RC for URL $i" + fi + + rm -f "$IP_TMP" +done + +# sort -nu does not work as expected +sed -r -e '/^(0\.0\.0\.0|10\.|127\.|172\.1[6-9]\.|172\.2[0-9]\.|172\.3[0-1]\.|192\.168\.|22[4-9]\.|23[0-9]\.)/d' "$IP_BLACKLIST_TMP" | sort -n | sort -mu >|"$IP_BLACKLIST" +if [[ ${DO_OPTIMIZE_CIDR} == yes ]]; then + if [[ ${VERBOSE:-no} == yes ]]; then + echo -e "\\nAddresses before CIDR optimization: $(wc -l "$IP_BLACKLIST" | cut -d' ' -f1)" + fi + + iprange <"$IP_BLACKLIST" --optimize - >"$IP_BLACKLIST_TMP" 2>/dev/null + if [[ ${VERBOSE:-no} == yes ]]; then + echo "Addresses after CIDR optimization: $(wc -l "$IP_BLACKLIST_TMP" | cut -d' ' -f1)" + fi + + cp "$IP_BLACKLIST_TMP" "$IP_BLACKLIST" +fi + +rm -f "$IP_BLACKLIST_TMP" + +# family = inet for IPv4 only +cat >|"$IP_BLACKLIST_RESTORE" <>"$IP_BLACKLIST_RESTORE" + +cat >>"$IP_BLACKLIST_RESTORE" <