Created
November 6, 2024 18:42
-
-
Save VSharapov/d47d84aafe1ad663bce42a53a1111478 to your computer and use it in GitHub Desktop.
Try a set of credentials on all machines in a set of subnets
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| ### recommended usage is something like: | |
| ### export PARAM_SUBNETS="10.69.0.0/16 192.168.1.0/24"; export PARAM_USERNAME=ubuntu; [ -z "$PARAM_PASSWORD" ] && { read -s ; export PARAM_PASSWORD="$REPLY" ; } ; ./listAccessibleMachines.sh | |
| set -Eeuo pipefail | |
| trap cleanup SIGINT SIGTERM ERR EXIT | |
| script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P) | |
| setup_colors() { | |
| if [[ -t 2 ]] && [[ -z "${NO_COLOR-}" ]] && [[ "${TERM-}" != "dumb" ]]; then | |
| NOFORMAT='\033[0m' RED='\033[0;31m' GREEN='\033[0;32m' ORANGE='\033[0;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' YELLOW='\033[1;33m' | |
| else | |
| NOFORMAT='' RED='' GREEN='' ORANGE='' BLUE='' PURPLE='' CYAN='' YELLOW='' | |
| fi | |
| } | |
| setup_colors | |
| msg() { | |
| echo >&2 -e "${1-}" | |
| } | |
| die() { | |
| local msg=$1 | |
| local code=${2-1} # default exit status 1 | |
| msg "$msg" | |
| exit "$code" | |
| } | |
| cleanup() { | |
| trap - SIGINT SIGTERM ERR EXIT | |
| rm -rf "$tmpdir" | |
| } | |
| for cmd in nmap expect nc; do | |
| which "$cmd" > /dev/null || { msg "$cmd not found"; exit 1; } | |
| done | |
| tmpdir=$(mktemp -d) | |
| # Parameters | |
| if [ -z "${PARAM_SUBNETS-}" ]; then | |
| msg "You can make this noninteractive by setting PARAM_SUBNETS" | |
| msg "... e.g. export PARAM_SUBNETS=\"10.0.0.0/8 192.168.1.0/24\" ; $0" | |
| subnets_to_scan=$(ip route | awk '/proto kernel/ {print $1}' | paste -sd " ") | |
| while true; do | |
| echo "Going to scan these subnets:" | |
| echo "${subnets_to_scan}" | |
| read -p "Press Enter to continue, or provide a subnet: " | |
| if [ -z "$REPLY" ]; then | |
| break | |
| fi | |
| # If the reply is already in the string, remove it | |
| if [[ " ${subnets_to_scan} " =~ " $REPLY " ]]; then | |
| subnets_to_scan=$(echo "$subnets_to_scan" | sed "s/ $REPLY / /g") | |
| else | |
| subnets_to_scan="$subnets_to_scan $REPLY" | |
| fi | |
| done | |
| else | |
| subnets_to_scan="${PARAM_SUBNETS}" | |
| fi | |
| if [ -z "${PARAM_USERNAME-}" ]; then | |
| msg "You can make this noninteractive by setting PARAM_USERNAME" | |
| msg "... e.g. export PARAM_USERNAME=ubuntu ; $0" | |
| read -p "Username [$USER]: " username | |
| if [ -z "$username" ]; then | |
| username="$USER" | |
| fi | |
| else | |
| username="${PARAM_USERNAME}" | |
| fi | |
| if [ -z "${PARAM_PASSWORD-}" ]; then | |
| msg "You can make this noninteractive by setting PARAM_PASSWORD" | |
| msg "... e.g. read -s ; export PARAM_PASSWORD=\"$REPLY\" ; $0" | |
| read -p "Password: " -s password | |
| else | |
| password="${PARAM_PASSWORD}" | |
| fi | |
| # Setup | |
| for subnet in $subnets_to_scan; do | |
| nmap -n -sL "$subnet" | awk '/Nmap scan report/{print $NF}' | |
| done > "$tmpdir/all_ips" | |
| touch "$tmpdir/all_ips" | |
| touch "$tmpdir/password_failures" | |
| touch "$tmpdir/ssh_key_failures" | |
| touch "$tmpdir/accessible_machines" | |
| touch "$tmpdir/passwordless_sudo_machines" | |
| touch "$tmpdir/port_22_failures" | |
| # Functions | |
| function check_sudo() { | |
| trap - SIGINT SIGTERM ERR EXIT | |
| ip="$1" | |
| ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o BatchMode=yes -o UserKnownHostsFile=/dev/null "$username@$ip" sudo -n true || return 1 | |
| echo "$ip" >> "$tmpdir/passwordless_sudo_machines" | |
| } | |
| function test_ip() { | |
| trap - SIGINT SIGTERM ERR EXIT | |
| ip="$1" | |
| # Fastest thing to check is port 22 | |
| timeout=1 | |
| nc -z -w $timeout "$ip" 22 || { echo "$ip" >> "$tmpdir/port_22_failures"; return 1; } | |
| # Some machines may already have our ssh key | |
| no_key_args="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" | |
| no_tty_args="-o PasswordAuthentication=no -o BatchMode=yes" | |
| ssh $no_key_args $no_tty_args "$username@$ip" true && \ | |
| { echo "$ip" >> "$tmpdir/accessible_machines"; check_sudo "$ip"; return 0; } | |
| expect -c " | |
| set timeout 10 | |
| spawn ssh-copy-id $no_key_args $username@$ip | |
| expect { | |
| \"password:\" { | |
| send \"$password\r\" | |
| expect { | |
| \"Permission denied\" { | |
| exit 1 | |
| } | |
| \"Number of key(s) added:\" { | |
| exit 0 | |
| } | |
| eof { | |
| exit 1 | |
| } | |
| } | |
| } | |
| \"Number of key(s) added:\" { | |
| exit 0 | |
| } | |
| \"Permission denied\" { | |
| exit 1 | |
| } | |
| \"usage:\" { | |
| exit 2 | |
| } | |
| timeout { | |
| exit 4 | |
| } | |
| eof { | |
| exit 3 | |
| } | |
| } | |
| " || exit_status=$? | |
| msg "${RED}$ip ssh-copy-id exit status: $exit_status${NOFORMAT}" | |
| case $exit_status in | |
| 0) | |
| msg "Successfully copied SSH key to $ip" | |
| ;; | |
| 1) | |
| echo "$ip" >> "$tmpdir/password_failures" | |
| return 1 | |
| ;; | |
| 2) | |
| msg "$ip - Invalid usage of ssh-copy-id" >> "$tmpdir/errors" | |
| return 1 | |
| ;; | |
| 3) | |
| msg "$ip - Unexpected EOF or error" >> "$tmpdir/errors" | |
| return 1 | |
| ;; | |
| 4) | |
| msg "$ip - Connection timed out" >> "$tmpdir/errors" | |
| return 1 | |
| ;; | |
| esac | |
| # Now check if we can log in with our ssh keys | |
| ssh $no_key_args $no_tty_args "$username@$ip" true && \ | |
| { echo "$ip" >> "$tmpdir/accessible_machines"; check_sudo "$ip"; return 0; } ||\ | |
| { echo "$ip" >> "$tmpdir/ssh_key_failures"; check_sudo "$ip"; return 1; } | |
| } | |
| # Let's go! | |
| for ip in $(cat "$tmpdir/all_ips" | tr '\n' ' '); do | |
| # Spawn a background function for each ip | |
| ( | |
| msg "Checking $ip" | |
| mkdir -p "$tmpdir/individual_logs/$ip" | |
| test_ip "$ip" > "$tmpdir/individual_logs/$ip/stdout" 2> "$tmpdir/individual_logs/$ip/stderr" | |
| ) & | |
| msg "Spawned $ip" | |
| done | |
| sleep 1 | |
| msg "Waiting for all background functions to finish" | |
| wait | |
| msg "IPs tested: $(cat "$tmpdir/all_ips" | tr ' ' '\n' | wc -l)" | |
| msg "Failed port 22: $(cat "$tmpdir/port_22_failures" | wc -l)" | |
| msg "Failed passwords: $(cat "$tmpdir/password_failures" | wc -l)" | |
| msg "Failed ssh keys: $(cat "$tmpdir/ssh_key_failures" | wc -l)" | |
| msg "Accessible machines: $(cat "$tmpdir/accessible_machines" | wc -l)" | |
| msg "Passwordless sudo machines: $(cat "$tmpdir/passwordless_sudo_machines" | wc -l)" | |
| msg "This temporary directory will be deleted when you exit the shell, so stash what you need." | |
| pushd "$tmpdir" | |
| bash || msg "Bye." | |
| popd | |
| exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment