Page 1 of 1

Determine Remote Server Operating System Rate Topic: -----

#1 no2pencil  Icon User is offline

  • Professor Snuggly Pants
  • member icon

Reputation: 6544
  • View blog
  • Posts: 30,653
  • Joined: 10-May 07

Posted 09 January 2015 - 07:13 AM

In this tutorial I will walk through a script I recently wrote that I needed to determine servers for a client that did not have an up-to-date map of their infrastructure. In short, they have hundreds of servers, some of which are Windows, some of which are Linux. There was a process that I was required to perform on every Linux server, but wasn't about to try to hit hundreds of IP's that were not going to answer.

Worse yet, I didn't even have the full IP list, I only had their internal domain names (dot local).

I put this list into a text file called sites.txt, & ran a loop on every site :

site=sites.txt
for site in ${sites}
do
  echo Checking ${site}
done



Next I need to get the ip of this site, so in that loop I added a dig +short command :

site=sites.txt
for site in ${sites}
do
  ip=`dig +short ${site}`
  echo Checking ${site} at ${ip}
done



In order to validate that I had an ip, I ran a regex. The reason for this, is if dig returned more subdomains, then the loop would fail as I need IP addresses. To do this I made a function that assumes failure (by setting the return code to 1 by default), & then only if proven true by the regex will return zero.

rx='([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])'
function validate() {
  rc=1
  if [[ $1 =~ ^$rx\.$rx\.$rx\.$rx$ ]]; then
   rc=0
  fi
  echo ${rc}
}



So now for some magic. Now that we know we have an ip address, we can try to ssh to it. But rather than let the timeout occur, we simply check for an ssh key with ssh-keyscan. If we get a key, we have Linux. If not, we have something else.

function osify() {
  ssh-keyscan $1 2>&1 | grep -v "^$" > /dev/null
  if [ $? -eq 0 ]; then
    echo Linux!
    echo $1 >> ${linux}
  else
    echo Windows 
  fi
}



To put it all together with some error checking :

#!/bin/sh
#set -x

clear
rx='([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])'
sites=`cat sites.txt`
linux=tossh.txt

if [ -f ${linux} ]; then
  echo Refreshing output file
  rm ${linux}
fi
touch ${linux}
if [ $? -ne 0 ]; then
  echo Can not create output file 
  exit 0
fi

function validate() {
  rc=1
  if [[ $1 =~ ^$rx\.$rx\.$rx\.$rx$ ]]; then
   rc=0
  fi
  echo ${rc}
}

function osify() {
  ssh-keyscan $1 2>&1 | grep -v "^$" > /dev/null
  if [ $? -eq 0 ]; then
    echo Linux!
    echo $1 >> ${linux}
  else
    echo Windows 
  fi
}

for site in ${sites}
do
  ip=`dig +short ${site}`
  if [ $(validate ${ip}) != "0" ]; then
    sub_site=`echo ${ip} | cut -d' ' -f1`
    echo ${sub_site} | grep "\.$"
    if [ $? -eq 0 ]; then
      ip=`dig +short ${sub_site}`
    fi
  fi
  echo Checking ${site}
  if [ $(validate ${ip}) == "0" ]; then
    osify $ip
  fi
done



With this I was able to crunch the entire site list in under five minutes. That's enough time to go get a cup of coffee, check some email, & get ready to get some more work done.

Just to note, please keep in mind that where this solution will not be helpful, or may create inaccurate results, is in a network of which you are unfamiliar with. For example, if you grabbed a bunch of domain names hosted with GoDaddy, & scan them, you are going to get the results of GoDaddy's outside interface. This script is really only useful if you are already inside the network, & in an infrastructure to which you have some understanding.

Feel free to post any questions, or examples of usage!

Is This A Good Question/Topic? 0
  • +

Replies To: Determine Remote Server Operating System

#2 JWHSmith  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 2
  • View blog
  • Posts: 9
  • Joined: 13-November 14

Posted 22 January 2015 - 08:57 AM

These may be typos, or peculiarities of your shell, but unless I'm wrong, a few things need to be modified before this script can be used. Most of them are fixed in the final script, but the first code snippets do not seem to be :unsure:

  • The for loop iterates over an empty string (sites), and I'm guessing the typo is in the first line where site= should be sites=. This seems to be fixed in the final script though.
  • The first loop will only output a list of files, and not a list of sites. This was fixed in the final script as well. By the way, here is another alternative which avoids a useless use of cat and provides better support for spaces and other tricky characters :
    while IFS=$'\n' read site; do
        echo "Checking $site"
    done < sites.txt
    
    
  • The backticks `` syntax is considered deprecated because of issues with encapsulation and metacharacters management. You might want to use ip=$(dig +short $site) instead. It might also be a good idea to pipe to head since dig could print several IPs:
    while IFS=$'\n' read site; do
        ip=$(dig +short $site | head -n1)
    done < sites.txt
    
    
  • The validate function does not handle IPv6. Actually, you could save yourself some code and let the validation to ssh-keyscan. If an invalid host is submitted, you'll just get a Name of service unknown:
    sshscan=$(ssh-keyscan $1 2>&1)
    if grep -qE "Name.*unknown" <<< $sshscan; then
        echo "Unknown host: $1"
    elif grep -q ^$ <<< $sshscan; then
        echo "No key found, probably not Linux"
    else
        echo "Key found, probably Linux"
    fi
    
    

Now as you said, if you're familiar with your network (for instance, you're sure there is no Linux with no SSH server running), these shouldn't be problems. Now it may require a few changes before it can be use to discover a network. For that, you might find nmap, especially the -O (OS detection/fingerprinting) option, rather interesting.

This post has been edited by JWHSmith: 22 January 2015 - 09:01 AM

Was This Post Helpful? 1
  • +
  • -

#3 no2pencil  Icon User is offline

  • Professor Snuggly Pants
  • member icon

Reputation: 6544
  • View blog
  • Posts: 30,653
  • Joined: 10-May 07

Posted 22 January 2015 - 09:02 AM

Thank you for your added contributions! These are amazing.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1