ARP Monitoring script with notification and speech synthesis

A little bash script for GNU/Linux to monitor the system ARP table and detect duplicate entries leaved by ARP poisoning attacks.

See above in action :

Screenshot 1
Screenshot 2

  • State:

    This is a Proof of Concept...
    You can install 'notify-send' to be alerted by notifications and 'espeak' for the speech synthesis.

  • License:

    MIT License
    MIT License

  • Code from my Github Gist:

    #!/bin/bash
    # arp_monitor.sh
    # Check if each IP address has a unique MAC address in the ARP table
    # Julien Deudon (initbrain)
    # Known duplicate MAC address
    # ("aa:bb:cc:dd:ee:ff" "aa:bb:cc:dd:ee:ff" "aa:bb:cc:dd:ee:ff")
    bypass_macaddr=()
    # Waiting time between each check
    wait=5
    # Select the ARP information source
    # 0: 'cat /proc/net/arp' (without dns resolving, faster)
    # 1: 'arp -a' (attempt to determine hostnames)
    source=1
    function colorize {
    echo -e "$(echo "$3" | sed -e "s/${2}/\\${1}${2}\\${endColor}/g")"
    }
    boldWhite='\e[1;37m'
    green='\e[1;32m'
    red='\e[1;31m'
    endColor='\e[0m'
    espeakBin=$(which espeak)
    if [ -z "$espeakBin" ]
    then
    echo "[!] Warning, 'espeak' need to be installed if you want voice alerting"
    fi
    notifyBin=$(which notify-send)
    if [ -z "$notifyBin" ]
    then
    echo "[!] Warning, 'libnotify-bin' need to be installed if you want notify alerting"
    fi
    echo "Launch in 3 seconds, please wait..."
    sleep 3
    threatHistory=""
    for (( ; ; ))
    do
    # ARP table
    if [ ! $source ]; then
    arp_table=$(tail -n +2 /proc/net/arp | awk '{print $4,$1}')
    else
    arp_table=$(arp -a | awk '{print $4,$2,$1}' | sed 's/[\(\)]//g')
    fi
    # Formated ARP table string
    if [ ! $source ]; then
    formated=$(echo "$arp_table" | awk 'BEGIN{printf("%-22s%-20s\n","HW address","IP address")}{printf("%-22s%-20s\n",$1,$2)}')
    else
    formated=$(echo "$arp_table" | awk 'BEGIN{printf("%-22s%-20s%-30s\n","HW address","IP address","Hostname")}{printf("%-22s%-20s%-30s\n",$1,$2,$3)}')
    fi
    # Duplicate MAC address with the number of occurrences in parentheses
    if [ ! $source ]; then
    duplicate_occurrences=$(echo "$arp_table" | awk '{print $1}' | sort | uniq -c | grep -v '1 ' | awk '{print $2" ("$1")"}')
    else
    duplicate_occurrences=$(echo "$arp_table" | awk '{print $1}' | sort | uniq -c | grep -v '1 ' | awk '{print $2" ("$1")"}')
    fi
    # Duplicate MAC address
    duplicate=$(echo "$duplicate_occurrences" | awk '{print $1}')
    # Known duplicate MAC addresses colorized in green
    for macaddr in "${bypass_macaddr[@]}"
    do
    formated=$(colorize "$green" "$macaddr" "$formated")
    duplicate_occurrences=$(colorize "$green" "$macaddr" "$duplicate_occurrences")
    duplicate=$(echo -e "$duplicate" | grep -v "$macaddr")
    done
    # Unknown duplicate MAC addresses colorized in red
    for threat in "$duplicate"
    do
    if [ ! -z "$threat" ]
    then
    if [[ ! "$threatHistory" =~ "$threat" ]]
    then
    threatLines=$(echo -e "$arp_table" | grep "$threat")
    threatHistory="$threatHistory\n$(date)\n$threatLines"
    if [ ! -z "$espeakBin" ]
    then
    espeak -v en -s 120 'Warning, ARP poisoning detected !' &
    fi
    if [ ! -z "$notifyBin" ]
    then
    threatLinesSplited=(${threatLines//\\\t/ })
    formatedThreat="$(date)\n---"
    if [ ! $source ]; then
    formatedThreat="$formatedThreat\nHW address: ${threatLinesSplited[0]}"
    formatedThreat="$formatedThreat\nIP address: ${threatLinesSplited[1]}"
    formatedThreat="$formatedThreat\n---"
    formatedThreat="$formatedThreat\nHW address: ${threatLinesSplited[2]}"
    formatedThreat="$formatedThreat\nIP address: ${threatLinesSplited[3]}"
    else
    formatedThreat="$formatedThreat\nHW address: ${threatLinesSplited[0]}"
    formatedThreat="$formatedThreat\nIP address: ${threatLinesSplited[1]}"
    formatedThreat="$formatedThreat\nHostname: ${threatLinesSplited[2]}"
    formatedThreat="$formatedThreat\n---"
    formatedThreat="$formatedThreat\nHW address: ${threatLinesSplited[3]}"
    formatedThreat="$formatedThreat\nIP address: ${threatLinesSplited[4]}"
    formatedThreat="$formatedThreat\nHostname: ${threatLinesSplited[5]}"
    fi
    notify-send -u critical -c network.error -i security-high-symbolic "ARP Poisoning Detected" "$formatedThreat" &
    fi
    fi
    formated=$(colorize "$red" "$threat" "$formated")
    duplicate_occurrences=$(colorize "$red" "$threat" "$duplicate_occurrences")
    fi
    done
    clear
    echo -e "${boldWhite}ARP table - $(date):${endColor}\n"
    echo -e "$formated"
    if [ ! -z "$duplicate_occurrences" ]
    then
    echo -e "\n${boldWhite}Suspicious MAC address (duplicate):${endColor}\n"
    echo -e "$duplicate_occurrences"
    fi
    if [ ! -z "$threatHistory" ]
    then
    echo -e "\n${boldWhite}History (threats) :${endColor}"
    echo -e "$threatHistory"
    fi
    sleep $wait
    done
    view raw arp_monitor.sh hosted with ❤ by GitHub