1
0
forked from extern/SSH-Snake

Resolve all IPv4 addresses for domain names (if possible).

Return false in is_ssh_host() if an invalid IP address ([0-9\.]* which is not ^[0-9]+(\.[0-9]+){3}$)
Force lowercase in is_ssh_dest() and add_ssh_dest()
This commit is contained in:
Joshua Rogers 2024-01-11 18:17:21 +07:00
parent 3ff1879d06
commit f9a46b8c86
3 changed files with 61 additions and 40 deletions

View File

@ -147,5 +147,3 @@ I am particually interested in any interesting `[line]` outputs associated with
- `find ... -readable ...` is used in the script in multiple places. The `-readable` flag is not supported on all versions of `find(1)`. - `find ... -readable ...` is used in the script in multiple places. The `-readable` flag is not supported on all versions of `find(1)`.
- The script does not currently look for SSH agent sockets. - The script does not currently look for SSH agent sockets.
- The script does not properly resolve domains with multiple IPv4 addresses.

View File

@ -994,7 +994,7 @@ local ssh_dest
declare -A valid_ssh_dests declare -A valid_ssh_dests
declare -A resolved_hosts declare -A resolved_hosts
local res local res
local mac local use_mac
local to local to
if command -v timeout >/dev/null 2>&1; then if command -v timeout >/dev/null 2>&1; then
to="timeout 5" to="timeout 5"
@ -1003,7 +1003,7 @@ if getent ahostsv4 -- 1.1.1.1 >/dev/null 2>&1; then
res="$to getent ahostsv4 --" res="$to getent ahostsv4 --"
elif dscacheutil -q host -a name 1.1.1.1 >/dev/null 2>&1; then elif dscacheutil -q host -a name 1.1.1.1 >/dev/null 2>&1; then
res="$to dscacheutil -q host -a name" res="$to dscacheutil -q host -a name"
mac="1" use_mac="1"
else else
printf "INTERNAL_MSG: command not found: RESOLVE (%s)\n" "$(uname -a 2>/dev/null)" printf "INTERNAL_MSG: command not found: RESOLVE (%s)\n" "$(uname -a 2>/dev/null)"
fin fin
@ -1027,27 +1027,32 @@ is_ssh_dest "$ssh_dest" || continue
ssh_user="${ssh_dest%%@*}" ssh_user="${ssh_dest%%@*}"
ssh_host="${ssh_dest#*@}" ssh_host="${ssh_dest#*@}"
if [[ -v 'resolved_hosts["$ssh_host"]' || ${#resolved_hosts["$ssh_host"]} -gt 0 ]]; then if [[ -v 'resolved_hosts["$ssh_host"]' || ${#resolved_hosts["$ssh_host"]} -gt 0 ]]; then
resolved_ssh_host="${resolved_hosts["$ssh_host"]}" :
else else
if [[ -n "$mac" ]]; then local resolved_ssh_hosts
resolved_ssh_host="$($res "$ssh_host" 2>/dev/null | grep -F 'ip_address:')" if [[ -n "$use_mac" ]]; then
resolved_ssh_host="${resolved_ssh_host#* }" resolved_ssh_hosts="$($res "$ssh_host" 2>/dev/null | awk '/ip_address:/{print $NF}')"
else else
resolved_ssh_host="$($res "$ssh_host" 2>/dev/null)" resolved_ssh_hosts="$($res "$ssh_host" 2>/dev/null | awk '/RAW/{print $1}')"
resolved_ssh_host="${resolved_ssh_host%% *}"
fi fi
for resolved_ssh_host in "${resolved_ssh_hosts[@]}"; do
if [[ "${resolved_ssh_host:0:1}" =~ [12] ]]; then if [[ "${resolved_ssh_host:0:1}" =~ [12] ]]; then
[[ "$resolved_ssh_host" =~ ^127\. ]] && resolved_ssh_host="127.0.0.1" [[ "$resolved_ssh_host" =~ ^127\. ]] && resolved_ssh_host="127.0.0.1"
resolved_hosts["$ssh_host"]="$resolved_ssh_host" [[ -v '_ignored_hosts["$resolved_ssh_host"]' || ${#_ignored_hosts["$resolved_ssh_host"]} -gt 0 ]] && continue
resolved_hosts["$ssh_host"]+="$resolved_ssh_host "
else else
_ignored_hosts["$ssh_host"]=1
[[ -n "$resolved_ssh_host" ]] && _ignored_hosts["$resolved_ssh_host"]=1 [[ -n "$resolved_ssh_host" ]] && _ignored_hosts["$resolved_ssh_host"]=1
fi
done
fi
if [[ "${#resolved_hosts["$ssh_host"]}" -lt 7 ]]; then
_ignored_hosts["$ssh_host"]=1
continue continue
fi fi
fi for resolved_ssh_host in ${resolved_hosts["$ssh_host"]}; do
[[ -v '_ignored_hosts["$resolved_ssh_host"]' || ${#_ignored_hosts["$resolved_ssh_host"]} -gt 0 ]] && _ignored_hosts["$ssh_host"]=1
valid_ssh_dests["$ssh_user@$resolved_ssh_host"]=1 valid_ssh_dests["$ssh_user@$resolved_ssh_host"]=1
done done
done
ssh_dests=() ssh_dests=()
for ssh_dest in "${!valid_ssh_dests[@]}"; do for ssh_dest in "${!valid_ssh_dests[@]}"; do
add_ssh_dest "$ssh_dest" add_ssh_dest "$ssh_dest"
@ -1088,6 +1093,9 @@ ssh_host="$1"
[[ -v 'ssh_hosts["$ssh_host"]' || ${#ssh_hosts["$ssh_host"]} -gt 0 ]] && return 0 [[ -v 'ssh_hosts["$ssh_host"]' || ${#ssh_hosts["$ssh_host"]} -gt 0 ]] && return 0
[[ "$ssh_host" =~ ^$allowed_host_chars+$ ]] || return 1 [[ "$ssh_host" =~ ^$allowed_host_chars+$ ]] || return 1
[[ "${ssh_host:0:1}" == "-" || "${ssh_host:0-1}" == "-" || "${ssh_host:0:1}" == "." || "${ssh_host:0-1}" == "." || "$ssh_host" == *"-."* || "$ssh_host" == *"--"* ]] && return 1 [[ "${ssh_host:0:1}" == "-" || "${ssh_host:0-1}" == "-" || "${ssh_host:0:1}" == "." || "${ssh_host:0-1}" == "." || "$ssh_host" == *"-."* || "$ssh_host" == *"--"* ]] && return 1
if [[ "$ssh_host" =~ ^[0-9.]+$ ]]; then
[[ "$ssh_host" =~ ^[0-9]+(\.[0-9]+){3}$ ]] || return 1
fi
return 0 return 0
} }
is_ssh_dest() { is_ssh_dest() {
@ -1096,6 +1104,7 @@ local ssh_host
local ssh_dest local ssh_dest
ssh_dest="$1" ssh_dest="$1"
[[ -z "$ssh_dest" ]] && return 1 [[ -z "$ssh_dest" ]] && return 1
ssh_dest="${ssh_dest,,}"
[[ -v '_ignored_dests["$ssh_dest"]' || ${#_ignored_dests["$ssh_dest"]} -gt 0 ]] && return 1 [[ -v '_ignored_dests["$ssh_dest"]' || ${#_ignored_dests["$ssh_dest"]} -gt 0 ]] && return 1
ssh_user="${ssh_dest%%@*}" ssh_user="${ssh_dest%%@*}"
ssh_host="${ssh_dest#*@}" ssh_host="${ssh_dest#*@}"
@ -1119,6 +1128,7 @@ local ssh_dest
local ssh_host local ssh_host
local ssh_user local ssh_user
ssh_dest="$1" ssh_dest="$1"
ssh_dest="${ssh_dest,,}"
ssh_user="${ssh_dest%%@*}" ssh_user="${ssh_dest%%@*}"
ssh_host="${ssh_dest#*@}" ssh_host="${ssh_dest#*@}"
is_ssh_dest "$ssh_dest" && ssh_dests["$ssh_dest"]=1 && ssh_hosts["$ssh_host"]=1 && ssh_users["$ssh_user"]=1 && return 0 is_ssh_dest "$ssh_dest" && ssh_dests["$ssh_dest"]=1 && ssh_hosts["$ssh_host"]=1 && ssh_users["$ssh_user"]=1 && return 0

View File

@ -1672,13 +1672,12 @@ combinate_interesting_users_hosts() {
} }
# Deduplicate ssh_dests by resolving the hosts for each ssh_dest, checking whether the user, host, or resolved dest is ignored, then adding the destinations back to the original ssh_dests array. # Deduplicate ssh_dests by resolving the hosts for each ssh_dest, checking whether the user, host, or resolved dest is ignored, then adding the destinations back to the original ssh_dests array.
# TODO: doesn't support hosts with multiple hosts (4 ips for 1 domain), and in fact may even break that.
deduplicate_resolved_hosts_keys() { deduplicate_resolved_hosts_keys() {
local ssh_dest local ssh_dest
declare -A valid_ssh_dests declare -A valid_ssh_dests
declare -A resolved_hosts declare -A resolved_hosts
local res local res
local mac local use_mac
local to local to
# DNS timeout of 5 seconds per address (bleh, hack). # DNS timeout of 5 seconds per address (bleh, hack).
@ -1692,7 +1691,7 @@ deduplicate_resolved_hosts_keys() {
# Otherwise dscacheutils for mac. # Otherwise dscacheutils for mac.
elif dscacheutil -q host -a name 1.1.1.1 >/dev/null 2>&1; then elif dscacheutil -q host -a name 1.1.1.1 >/dev/null 2>&1; then
res="$to dscacheutil -q host -a name" res="$to dscacheutil -q host -a name"
mac="1" use_mac="1"
else else
# If we can't use getent or dscacheutil, we're on an unknown type of system (with bash?!) # If we can't use getent or dscacheutil, we're on an unknown type of system (with bash?!)
# Use printf instead of chained_print() to be consistent. # Use printf instead of chained_print() to be consistent.
@ -1724,45 +1723,52 @@ deduplicate_resolved_hosts_keys() {
# Make everything lower case. # Make everything lower case.
ssh_dest="${ssh_dest,,}" ssh_dest="${ssh_dest,,}"
is_ssh_dest "$ssh_dest" || continue is_ssh_dest "$ssh_dest" || continue # Checks if the host has been ignored in this loop
ssh_user="${ssh_dest%%@*}" ssh_user="${ssh_dest%%@*}"
ssh_host="${ssh_dest#*@}" ssh_host="${ssh_dest#*@}"
# Check if the host has already been resolved. If it has, use the internally cached answer. # Check if the host has already been resolved. If it has, use the internally cached answer.
if [[ -v 'resolved_hosts["$ssh_host"]' || ${#resolved_hosts["$ssh_host"]} -gt 0 ]]; then if [[ -v 'resolved_hosts["$ssh_host"]' || ${#resolved_hosts["$ssh_host"]} -gt 0 ]]; then
resolved_ssh_host="${resolved_hosts["$ssh_host"]}" :
else else
# If the host has not already been resolved, resolve it. # If the host has not already been resolved, resolve it.
# If resolution of ${resolved_hosts["$ssh_host"]} failed before, we won't hit this code path because the host will be added to _ignored_hosts (and will be skipped using is_ssh_dest().
# macos # macos
if [[ -n "$mac" ]]; then local resolved_ssh_hosts # list of ipv4 addresses for a host
resolved_ssh_host="$($res "$ssh_host" 2>/dev/null | grep -F 'ip_address:')" if [[ -n "$use_mac" ]]; then
resolved_ssh_host="${resolved_ssh_host#* }" # format is 'ip_address: ip' resolved_ssh_hosts="$($res "$ssh_host" 2>/dev/null | awk '/ip_address:/{print $NF}')"
else else
resolved_ssh_host="$($res "$ssh_host" 2>/dev/null)" # linux
resolved_ssh_host="${resolved_ssh_host%% *}" # format is 'ip\t[junk] resolved_ssh_hosts="$($res "$ssh_host" 2>/dev/null | awk '/RAW/{print $1}')"
fi fi
for resolved_ssh_host in "${resolved_ssh_hosts[@]}"; do
# Answer must begin with 1 or 2 ($res 0.1.2.3 will respond with 0.1.2.3). # Answer must begin with 1 or 2 ($res 0.1.2.3 will respond with 0.1.2.3).
if [[ "${resolved_ssh_host:0:1}" =~ [12] ]]; then if [[ "${resolved_ssh_host:0:1}" =~ [12] ]]; then
[[ "$resolved_ssh_host" =~ ^127\. ]] && resolved_ssh_host="127.0.0.1" # If it's loopback, always use 127.0.0.1 [[ "$resolved_ssh_host" =~ ^127\. ]] && resolved_ssh_host="127.0.0.1" # If it's loopback, always use 127.0.0.1
[[ -v '_ignored_hosts["$resolved_ssh_host"]' || ${#_ignored_hosts["$resolved_ssh_host"]} -gt 0 ]] && continue
# Cache the host # Cache the host
resolved_hosts["$ssh_host"]="$resolved_ssh_host" resolved_hosts["$ssh_host"]+="$resolved_ssh_host "
else else
# Ignore this host # Ignore this RESOLVED host (might save us a few cycles).
_ignored_hosts["$ssh_host"]=1 # Don't add the ssh_host to _ignored_hosts become it may have non-ignored hosts, too.
# Also ignore the resolved host (which may not necessarily be the same as the host).
[[ -n "$resolved_ssh_host" ]] && _ignored_hosts["$resolved_ssh_host"]=1 [[ -n "$resolved_ssh_host" ]] && _ignored_hosts["$resolved_ssh_host"]=1
fi
done
fi
# No IPs resolved for the host, add the host to _ignored_host.
if [[ "${#resolved_hosts["$ssh_host"]}" -lt 7 ]]; then
_ignored_hosts["$ssh_host"]=1
continue continue
fi fi
fi
# Check whether the resolved host is ignored. If so, also add the unresolved host to _ignored_hosts.
[[ -v '_ignored_hosts["$resolved_ssh_host"]' || ${#_ignored_hosts["$resolved_ssh_host"]} -gt 0 ]] && _ignored_hosts["$ssh_host"]=1
# add_ssh_dest will check whether the $ssh_user@$resolved_ssh_host is ignored.
# Loop through each host (which are space-separated now), so no quotation marks.
for resolved_ssh_host in ${resolved_hosts["$ssh_host"]}; do
valid_ssh_dests["$ssh_user@$resolved_ssh_host"]=1 valid_ssh_dests["$ssh_user@$resolved_ssh_host"]=1
done done
done
ssh_dests=() ssh_dests=()
@ -1834,6 +1840,10 @@ is_ssh_host() {
[[ "${ssh_host:0:1}" == "-" || "${ssh_host:0-1}" == "-" || "${ssh_host:0:1}" == "." || "${ssh_host:0-1}" == "." || "$ssh_host" == *"-."* || "$ssh_host" == *"--"* ]] && return 1 [[ "${ssh_host:0:1}" == "-" || "${ssh_host:0-1}" == "-" || "${ssh_host:0:1}" == "." || "${ssh_host:0-1}" == "." || "$ssh_host" == *"-."* || "$ssh_host" == *"--"* ]] && return 1
if [[ "$ssh_host" =~ ^[0-9.]+$ ]]; then
[[ "$ssh_host" =~ ^[0-9]+(\.[0-9]+){3}$ ]] || return 1
fi
return 0 return 0
} }
@ -1847,6 +1857,8 @@ is_ssh_dest() {
[[ -z "$ssh_dest" ]] && return 1 [[ -z "$ssh_dest" ]] && return 1
ssh_dest="${ssh_dest,,}"
# XXX: The below line is intrinsically flawed because even if $ssh_dest is already in ssh_dests, this does not mean $ssh_host has not been added to $_ignored_hosts. We keep it here to remember not to add it again. # XXX: The below line is intrinsically flawed because even if $ssh_dest is already in ssh_dests, this does not mean $ssh_host has not been added to $_ignored_hosts. We keep it here to remember not to add it again.
# [[ -v 'ssh_dests["$ssh_dest"]' || ${#ssh_dests["$ssh_dest"]} -gt 0 ]] && return 0 # [[ -v 'ssh_dests["$ssh_dest"]' || ${#ssh_dests["$ssh_dest"]} -gt 0 ]] && return 0
@ -1888,6 +1900,7 @@ add_ssh_dest() {
local ssh_user local ssh_user
ssh_dest="$1" ssh_dest="$1"
ssh_dest="${ssh_dest,,}"
ssh_user="${ssh_dest%%@*}" ssh_user="${ssh_dest%%@*}"
ssh_host="${ssh_dest#*@}" ssh_host="${ssh_dest#*@}"