Find active SSH servers w/ ssh keys on LAN

Hi,

I am trying to complete my bash script in order to find which SSH servers on LAN are still active with the ssh keys, but i am frozen at this step:

#!/bin/bash
 
# LAN SSH KEYS DISCOVERY SCRIPT
 
</etc/passwd \
grep /bin/bash |
cut -d: -f6 |
sudo xargs -i -- sh -c '
     [ -e "$1" ] && cat "$1"
' -- {}/.ssh/known_hosts |
cut -d' ' -f1 |
tr ',' '\n' |
sed '
     /^\[/{
          s/\[\(.*\)\]:\(.*\)/\1 \2/;
          t;
     };
     s/$/ 22/;
' |
sort -u |
xargs -l1 -- sh -c '
    if echo "~" | nc -q1 -w3 "$1" "$2" | grep -q "^SSH"; then
          echo "#### SUCCESS $1 $2";
    else
          echo "#### ERROR $1 $2";
    fi
' --
 
# TIME TO TEST WHICH SSH servers are still active with the SSH keys
# AND THIS IS WHERE I AM FROZEN...
# Would love to have bash script that could
# ssh -l $users_that_have_/bin/bash -i $ssh_keys $ssh_servers
# Would also be very nice if it could save active
# SSH servers with the valid keys in output.txt in the format
# username:local-IP:/path/to/SSH_key

there is also another one simpler to read (but with some temp files getting created)

#!/bin/bash

# LAN SSH KEYS DISCOVERY SCRIPT
# TRYING TO FIND THOSE SSH KEYS NOW

cat /etc/passwd | grep /bin/bash > bash_users
cat bash_users | cut -d ":" -f 6 > cutted.bash_users_home_dir
for bash_users in $(cat cutted.bash_users_home_dir)
do
ls -al $bash_users/.ssh/*id_* >> ssh-keys.txt
done

# DISCOVERING THE KNOWN_HOSTS NOW

for known_hosts in $(cat cutted.bash_users_home_dir)
do
cat $bash_users/.ssh/known_hosts | awk '{print $1}' | sort -u >> 
hosts_known.txt
sleep 2
done
hosts_known=$(wc -l hosts_known.txt)
echo "We have $hosts_known known hosts that could be still active via SSH 
keys"

# TIME TO TEST WHICH SSH servers are still active with the SSH keys
# AND THIS IS WHERE I AM FROZEN...
# Would love to have bash script that could
# ssh -l $users_that_have_/bin/bash -i $ssh_keys $ssh_servers
# Would also be very nice if it could save active
# SSH servers with the valid keys in output.txt in the format
# username:local-IP:/path/to/SSH_key

Please feel very comfortable to edit/modify the bash script above if it can serve better the goals described.

Any help would be very appreciated,

Thanks

Welcome to the forum.

We may want to wait for the answers to your question on unix.stackexchange.com.

1 Like

I've received the following answer:

you know ssh have a return code ? along with -o BatchMode=yes this can help automatize test. (e.g. if ssh ... ; then echo good for ... >> good.txt ; else echo bad for ... >> bad.txt ; fi) - Archemar 18 mins ago

So now I'm trying to figure out how I could make this idea integrate itself into my bash script, something like;

users=$(cat cutted.bash_users)
cat ssh-keys.txt | awk '{print $9}' > cutted.ssh_keys.txt
ssh_keys=$(cat cutted.ssh_keys.txt)

if ssh -l $users -i $ssh_keys $hosts_known -o BatchMode=yes -o ConnectTimeout=5
then echo $users:$hosts_known:$ssh_keys SUCCESS >> results.txt
else
echo $users:$hosts_known:$ssh_keys FAILED >> not-active.txt
fi

------ Post updated 11-02-18 at 01:35 AM ------

If anyone has an idea how to make this bash script working 100% I would be very happy. Again, please feel very comfortable to edit/modify the bash script above if it can serve better the goals described.

Any help would be very appreciated,

Thanks

You could also use nc to poke the port before trying to connect.

nc -z $target_server 22

Return code of zero for a successful contact. That might cut down the number of hosts you try to talk to that never respond.

Why is this part written like this?

:
cat ssh-keys.txt | awk '{print $9}' > cutted.ssh_keys.txt
ssh_keys=$(cat cutted.ssh_keys.txt)
:

Assuming that your file is space separated, you could just have

ssh_keys=$(cut -f9 -d" " ssh-keys.txt)

I hope that these help,
Robin

1 Like

In what way is it not working? What is doing that you don't want it to -- or not doing that you want it to? What, exactly, is your question?

What is not working is this part exactly:

if ssh -l $users -i $ssh_keys $hosts_known -o BatchMode=yes -o ConnectTimeout=5
then echo $users:$hosts_known:$ssh_keys SUCCESS >> results.txt
else
echo $users:$hosts_known:$ssh_keys FAILED >> not-active.txt
fi

You can see what it should do but actually my syntax seems incorrect because nothing gets into the file results.txt & not-active.txt.

------ Post updated at 05:33 PM ------

You can see below the output I am getting when launching the bash script:

root@blackb0x:/home/sirius/TEST# ./TEST3.sh
We have 6 hosts_known.txt known hosts that could be still active via SSH keys
ssh: Could not resolve hostname sirius: Name or service not known
root@blackb0x:/home/sirius/TEST# ls
bash_users  cutted.bash_users  cutted.bash_users_home_dir  cutted.ssh_keys.txt  hosts_known.txt  not-active.txt  ssh-keys.txt  TEST3.sh
root@blackb0x:/home/sirius/TEST# cat not-active.txt
root sirius postgres:6 hosts_known.txt:/root/.ssh/id_rsa /home/sirius/.ssh/id_rsa /var/lib/postgresql/.ssh/id_rsa /var/lib/postgresql/.ssh/id_rsa.pub FAILED

Seems like I have a syntax error in my bash script...

Try echo $users , etc. Maybe these variables aren't what you think they are.

1 Like

For a reason that I ignore, it seems like when doing:
echo $users
echo $ssh_keys
echo $hosts_known

It's giving the following output all on the same line for each echo instead of let's say, 1 user per line which is why I am having issue right now!

See output result:

./temp1.sh
root sirius postgres
/home/sirius/.ssh/id_rsa /var/lib/postgresql/.ssh/id_rsa /var/lib/postgresql/.ssh/id_rsa.pub
192.168.2.37

When it should be something like:

root
sirius
postgres
/home/sirius/.ssh/id_rsa
/var/lib/postgresql/.ssh/id_rsa
/var/lib/postgresql/.ssh/id_rsa.pub
192.168.2.37

Any idea how I could fix this ?

Thanks for your help !

I'm assuming that you have the same code posted earlier:-

users=$(cat cutted.bash_users)
cat ssh-keys.txt | awk '{print $9}' > cutted.ssh_keys.txt
ssh_keys=$(cat cutted.ssh_keys.txt)

if ssh -l $users -i $ssh_keys $hosts_known -o BatchMode=yes -o ConnectTimeout=5
then echo $users:$hosts_known:$ssh_keys SUCCESS >> results.txt
else
echo $users:$hosts_known:$ssh_keys FAILED >> not-active.txt
fi

Your command starting if ssh -l $users ...... will expand to include ALL the values of $users so you would end up with a command line like:-

if ssh -l root sirius postgres -i /home/sirius/.ssh/id_rsa /var/lib/postgresql/.ssh/id_rsa /var/lib/postgresql/.ssh/id_rsa.pub 192.168.2.37 -o BatchMode=yes -o ConnectTimeout=5

....which is an awful mess. This will try to login to server sirius with user account root (no key provided) and run the command postgres -i /home/sirius/.ssh/id_rsa /var/lib/postgresql/.ssh/id_rsa /var/lib/postgresql/.ssh/id_rsa.pub 192.168.2.37 -o BatchMode=yes -o ConnectTimeout=5

Do you actually want to loop round and try all the combinations perhaps? If so, try something like:-

:
:
for one_user in $users
do
   for one_sshkey in $ssh_keys
   do
      for one_host in $known_hosts
      do
         if ssh -l $one_user -i $one_key -o BatchMode=yes -o ConnectTimeout=5 $one_host 
         then
            echo $one_user:$one_key:$one_host >> results.txt
         else
            echo $one_user:$one_key:$one_host FAILED >> not-active.txt
         fi
      done
   done
done

Does that get you any nearer? note that I put the target host at the end so that all the options will be used. There will very likely be lots of failures as you try all the combinations.

As another note, there is no point trying to login with a public key.

I hope that this helps,
Robin

1 Like

Great, I believe this should do the trick very well, I will test it tomorrow morning. I have 2 questions;

1) Why some ':' at the beginning?
2) Doesn't the 'one_user' 'one_host' 'one_sshkey' variables needs to be defined before using them? like one_user = $(...)

Thanks

The loops define them. for x in a b c d e defines the $x variable for example.

Just guessing - some sort of vertical ellipsis?