├── .gitignore ├── README.md ├── scan.conf-example ├── scan.sh └── targets-example /.gitignore: -------------------------------------------------------------------------------- 1 | scans/ 2 | scan.conf 3 | targets 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # scanner 2 | nmap/ndiff based scanner with template based notification system in case of infrastructure changes 3 | 4 | ## Purpose 5 | In situations you want to keep track of your network configuration (in this context: variation of open ports over time), `nmap` and `ndiff` come in handy. 6 | 7 | This script tries to solve a problem if you have to track several networks or individual hosts that you want to scan consecutively. 8 | In case a network change is detected, the difference is sent in a (templated) mail to a configurable recipient. 9 | 10 | ## Installation 11 | git pull this repository at a location of your choice. Make sure `nmap` and `ndiff` are installed. 12 | Sending emails should be working from command line using the `mail` command. `logger` is being used for logging. 13 | The user running the script should be in the sudoers file, especially for running `nmap`: 14 | 15 | `username ALL=NOPASSWD: /usr/bin/nmap` 16 | 17 | ## Configuration 18 | There are a few options in the example config file that can be changed, as well as all the templating for the mails. 19 | Copy the config file `scan.conf-example` to `scan.conf` and edit it accordingy your wishes. 20 | 21 | 22 | ## Running 23 | 24 | ### Running standalone 25 | `./scan.sh [IP]/[CIDR] [Email address]` 26 | 27 | ### Running through parallels 28 | Create a file called `targets` (see `targets-example` to get an idea) and define your targets, notification addresses and `nmap` options there. When reading from a file, `-r` needs to be specified to deal with the special condition. 29 | 30 | `cat targets |parallel -j 4 ./scan.sh -r {}` 31 | 32 | You can tune the number of parallel tasks with the '-j n' parameter. 33 | 34 | ## Sample output 35 | ``` 36 | This email contains information regarding a subsequent network port scan performed 37 | by ORG, which discovered a network change. 38 | Hereafter the result of the scan and the changes (additional open ports or new hosts 39 | indicated by a plus ('+') sign, closed ports indicated by a minus ('-') sign) 40 | regarding the network 127.0.0.1/32: 41 | PORT STATE SERVICE VERSION 42 | 22/tcp open ssh 43 | 25/tcp open smtp 44 | +23/tcp open Telnet 45 | 46 | If this network change was unexpected, please review what caused the change and 47 | react accordingly. 48 | ``` 49 | 50 | ## Copyright 51 | Copyright: Sascha Rommelfangen, CIRCL, Smile g.i.e, 2018-01-31 52 | 53 | ## License 54 | GNU General Public License v2.0 55 | 56 | Reminder of the Warranty clause of the GPLv2: 57 | BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 58 | 59 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 60 | -------------------------------------------------------------------------------- /scan.conf-example: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASEDIR="/home/of/scanner" 4 | 5 | DIR_NEW="new" 6 | DIR_OLD="old" 7 | DIR_ARCHIVE="archive" 8 | 9 | NMAP_BIN=`which nmap` 10 | NMAP_DEFAULT_OPTIONS="--open -n -T4" 11 | 12 | EMAIL_CONTACT_ORG="YOURORG" 13 | EMAIL_CONTACT_INFO="$EMAIL_CONTACT_ORG (mailto:info@your.org or +123 45 678)" 14 | EMAIL_SUBJECT_PREFIX="[$EMAIL_CONTACT_ORG NOTIFICATION]" 15 | EMAIL_SUBJECT_INITIAL="Initial network scan results for" 16 | EMAIL_SUBJECT_CHANGE="Network change detected for" 17 | EMAIL_HEADER_INITIAL="This email contains information regarding the initial network port scan performed by $EMAIL_CONTACT_ORG." 18 | EMAIL_HEADER_CHANGE="This email contains information regarding a subsequent network port scan performed by $EMAIL_CONTACT_ORG, which discovered a network change." 19 | EMAIL_BODY_INITIAL="Hereafter the result of the initial scan of" 20 | EMAIL_BODY_CHANGE="Hereafter the result of the scan and the changes (additional open ports or new hosts indicated by a plus ('+') sign, closed ports indicated by a minus ('-') sign) regarding the network" 21 | EMAIL_FOOTER_INITIAL="Should you discover any unexpected results (e.g. unexpected open ports, wrong IP range), or in case you need support to interpret the results, don't hesitate to get back to us." 22 | EMAIL_FOOTER_CHANGE="If this network change was unexpected, please review what caused the change and react accordingly. Should you need support to interpret the results or in case you have difficulties to find a good resolution, please get in touch with $EMAIL_CONTACT_ORG immediately." 23 | EMAIL_INFO="\nYou receiced this message because you or someone from your organization subscribed you for this service.\nShould you have any question, please get in touch with $EMAIL_CONTACT_INFO.\n$EMAIL_CONTACT_ORG uses Free and Open Source Software to realize this service, mainly GNU/Linux and Nmap [https://nmap.org]\n" 24 | -------------------------------------------------------------------------------- /scan.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## nmap/ndiff based scanner with template based notification 4 | ## system in case of infrastructure changes 5 | ## 6 | ## Copyright: Sascha Rommelfangen, CIRCL, Smile g.i.e, 2018-01-31 7 | ## GNU General Public License v2.0 8 | 9 | # Import configuration 10 | . scan.conf 11 | 12 | # In case GNU parallel is supposed to be used, to the following: 13 | # Create a "targets" file, format: [IP] [EMAIL] [NMAP OPTIONS] 14 | # On command line, do: cat targets |parallel ./scan.sh -r {} 15 | 16 | # For use with a targets file 17 | if [[ "$1" == "-r" ]] 18 | then 19 | args=($2) 20 | TARGET=${args[0]} 21 | if [[ "$TARGET" == "#" ]] 22 | then 23 | echo "ignoring comment" 24 | exit 0 25 | fi 26 | EMAIL=${args[1]} 27 | NMAP_OPTIONS=${args[@]:2:99} 28 | else 29 | # For use with command line arguments 30 | TARGET="$1" 31 | EMAIL="$2" 32 | shift 2 33 | NMAP_OPTIONS="$@" 34 | fi 35 | 36 | INITIAL=false 37 | 38 | # Check if we have custom Nmap options 39 | if [ -z "$NMAP_OPTIONS" ] 40 | then 41 | NMAP_OPTIONS="$NMAP_DEFAULT_OPTIONS" 42 | fi 43 | 44 | # Check if the IP address is correct and containing a netmask 45 | echo $TARGET | egrep '^[0-9]{1,3}(\.[0-9]{1,3}){3}\/[0-9]{1,2}$' 46 | if [ $? -gt 0 ] 47 | then 48 | echo "$TARGET is not a valid IP address including a netmask (like 127.0.0.1/32)." 49 | exit 1 50 | fi 51 | 52 | # Check if the email is given 53 | echo $EMAIL | egrep '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}' 54 | if [ $? -gt 0 ] 55 | then 56 | echo "$EMAIL doesn't seem to be a valid email address." 57 | exit 1 58 | fi 59 | 60 | logger -i --id=$$ -t scanner "Scan requested for $TARGET" 61 | 62 | mkdir -p "$BASEDIR/scans/$TARGET/$DIR_NEW" 63 | mkdir -p "$BASEDIR/scans/$TARGET/$DIR_OLD" 64 | mkdir -p "$BASEDIR/scans/$TARGET/$DIR_ARCHIVE" 65 | FILENAME_NEW=$BASEDIR/scans/$TARGET/$DIR_NEW/result.txt 66 | FILENAME_OLD=$BASEDIR/scans/$TARGET/$DIR_OLD/result.txt 67 | FILENAME_DIFF=$FILENAME_NEW.diff 68 | DIRECTORY_ARCHIVE=$BASEDIR/scans/$TARGET/$DIR_ARCHIVE 69 | 70 | # Check if we ran this before 71 | if [ -e $FILENAME_NEW ] 72 | then 73 | if [ -e $FILENAME_OLD ] 74 | then 75 | mv $FILENAME_OLD $DIRECTORY_ARCHIVE/scan-`date "+%Y%m%d-%s"` 76 | fi 77 | mv $FILENAME_NEW $FILENAME_OLD 78 | else 79 | INITIAL=true 80 | fi 81 | 82 | # perform scan 83 | if [ $INITIAL == true ] 84 | then 85 | logger -i --id=$$ -t scanner "Starting initial scan for $TARGET" 86 | sudo $NMAP_BIN $NMAP_OPTIONS $TARGET -oX $FILENAME_NEW -oN $FILENAME_NEW.txt 87 | #cat $FILENAME_NEW.txt | mail -s "$EMAIL_SUBJECT_PREFIX $EMAIL_SUBJECT_INITIAL $TARGET" $EMAIL 88 | logger -i --id=$$ -t scanner "Scan for $TARGET finished" 89 | printf "$EMAIL_HEADER_INITIAL\n$EMAIL_BODY_INITIAL $TARGET:\n`cat $FILENAME_NEW.txt|sed -e 's/Nmap scan/Scan/'| grep -v 'scan initiated' | grep -v 'Starting Nmap'|grep -v 'Nmap done'`\n\n$EMAIL_FOOTER_INITIAL\n$EMAIL_INFO" | \ 90 | mail -s "$EMAIL_SUBJECT_PREFIX $EMAIL_SUBJECT_INITIAL $TARGET" $EMAIL 91 | logger -i --id=$$ -t scanner "Sent mail to $EMAIL: Initial network scan for $TARGET. See file $FILENAME_NEW for details" 92 | rm $FILENAME_NEW.txt 93 | exit 0 94 | else 95 | logger -i --id=$$ -t scanner "Starting successive scan for $TARGET" 96 | sudo $NMAP_BIN $NMAP_OPTIONS $TARGET -oX $FILENAME_NEW 97 | logger -i --id=$$ -t scanner "Scan for $TARGET finished" 98 | fi 99 | 100 | # test if we have two files to compare 101 | if [ -e $FILENAME_NEW ] && [ -e $FILENAME_OLD ] 102 | then 103 | ndiff -v $FILENAME_OLD $FILENAME_NEW > $FILENAME_DIFF 104 | if [ $? -gt 0 ] 105 | then 106 | cat $FILENAME_DIFF | grep PORT -A 999999 > $FILENAME_DIFF.mail 107 | #mail -s "Network change detected for $TARGET" $EMAIL < $FILENAME_DIFF.mail 108 | printf "$EMAIL_HEADER_CHANGE\n$EMAIL_BODY_CHANGE $TARGET:\n`cat $FILENAME_DIFF.mail`\n\n$EMAIL_FOOTER_CHANGE\n$EMAIL_INFO" | \ 109 | mail -s "$EMAIL_SUBJECT_PREFIX $EMAIL_SUBJECT_CHANGE $TARGET" $EMAIL 110 | rm $FILENAME_DIFF.mail 111 | FILENAME_DIFF_ARCHIVE=$DIRECTORY_ARCHIVE/diff-`date "+%Y%m%d-%s"` 112 | mv $FILENAME_DIFF $FILENAME_DIFF_ARCHIVE 113 | logger -i --id=$$ -t scanner "Sent mail to $EMAIL: network change detected for $TARGET. See file $FILENAME_DIFF_ARCHIVE for details" 114 | else 115 | logger -i --id=$$ -t scanner "No change detected for target $TARGET" 116 | fi 117 | fi 118 | logger -i --id=$$ -t scanner "Scan job for $TARGET finished" 119 | exit 0 120 | -------------------------------------------------------------------------------- /targets-example: -------------------------------------------------------------------------------- 1 | # It is necessary to remove old data of the host/network if the scan type changes! 2 | # host full scan TCP/UDP 3 | 127.0.0.1/32 a@b.cd -Pn -sU -sS -T4 -p0-65535 4 | # network quick scan (some TCP ports only) 5 | 127.0.0.0/24 a@b.cd -n -Pn -sS -sU -T4 6 | # host quick scan, show only open ports 7 | 127.0.0.1/32 a@b.cd --open -n -T4 8 | --------------------------------------------------------------------------------