Saturday, July 25, 2015

Making use of Grep, Cut & Sed -- An Anti-Theft Network Recon Script

After watching this video (which, by the way, is hilarious and worth checking out), I decided that I needed to write some kind of anti-theft bash script for my computers. Why bash? No other reason except it's one langauge that I'm confident enough speaking, and like that video, it too, is awesome. The basic scenario that I'd like to prepare for goes something like this:

Your computer gets stolen, and you really want it back. While you know that the computer is running an ssh server, and is listening on 0.0.0.0 for connections, you don't know what it's IP address will be whenever it gets plugged in to the WWW, or what kind of network topology you will have to hack through in order to connect to it. Of course, this logic assumes that the thief is not smart enough to wipe the system before putting it online. It also assumes that he does not have your sudo password, and perhaps even that you have the guest network account enabled, and/or your system boots into single user mode, as to lure the thief into testing out 'his' new computer. None of these assumptions are ideal, but perhaps if the computer that gets stolen exists in a shared computing environment where those conditions must be met, than this script could be helpful.

It's also worth noting that a few things have changed the days when that hacker in the video linked above had his box stolen, most importantly that 99% of all devices connected to the internet these days are behind some kind of firewall. So, there are a lot of variables to consider here...
In any case, let's assume all those conditions have been met, and you are sitting at home pulling you hair out, praying your computer's thief is a total idiot, and waiting for your beloved to phone_HOME()...

So, without spending too much time preparing for a very unlikely scenario, what information would you need in order to get a shell on your box and begin pwning the thief? First and foremost, you need an IP address. Sounds simple enough, but often times computers are not aware of what their public IP address is because they live on a LAN that does NAT to a local IP address. To solve this problem, we need a webserver that uses php to return the visitors IP address to an html page. Than your script can grab that IP with wget or curl, and send it back to you, the owner. This does the trick:

<?PHP
function getUserIP()
{
    $client  = @$_SERVER['HTTP_CLIENT_IP'];
    $forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
    $remote  = $_SERVER['REMOTE_ADDR'];

    if(filter_var($client, FILTER_VALIDATE_IP))
    {
        $ip = $client;
    }
    elseif(filter_var($forward, FILTER_VALIDATE_IP))
    {
        $ip = $forward;
    }
    else
    {
        $ip = $remote;
    }

    return $ip;
}

$user_ip = getUserIP();
echo $user_ip; // Output IP address
?>

This bit of php does nothing other than output the visiting client's IP address to the webpage in plain text, which is exactly what we need, no more and no less. I spun up a webserver and gave it the domain name ipreturn.tk, feel free to use it if you wish.

$ curl ipreturn.tk
 1.2.3.4

Perfect. Now that we've got the public facing IP of our perpetrators internet connection, perhaps it would be helpful to gather some more information about that host. This is where my all time favorite tool, Nmap, comes in to play:

#!/bin/bash

pubIP=$(curl ipreturn.tk)

pi_RESULTS=$(nmap -sV -A ${pubIP})
echo ${pi_RESULTS}


Parameter expansion is good stuff! Running this script will produce something like this:

Nmap scan report for 1.2.3.4
Host is up (0.063s latency).
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
53/tcp open  domain  dnsmasq 2.43rc3
22/tcp open  telnet    an old one


So now you have a little bit more information about your antagonist's internet connection. In this hypothetical example, the assailant has is running some kind of old telnet service, which should not be very difficult to exploit. But, wouldn't it be useful if we knew more about what lies on the other side of the network? To do that, first we need to find a way to grab the IP address from the output of ifconfig and either figure out the netmask as well, or just turn it into a a wildcard address and let nmap handle the rest. Originally, I tried something like this:

WlocIP=$(/sbin/ifconfig wlan0 | grep Mask | cut -d ':' -f2 | cut -d " " -f1)
ElocIP=$(/sbin/ifconfig eth0 | grep Mask | cut -d ':' -f2 | cut -d " " -f1)
ElocSN=$(echo ${ElocIP} | cut -d "." -f -3 | sed 's/$/.*/')
WlocSN=$(echo ${WlocIP} | cut -d "." -f -3 | sed 's/$/.*/')



function wifi_INFO(){
if [[ ${WlocIP} != "" ]]; then

    echo "<h3> Nmap results for wifi IP </h3>"
    echo "<pre>"
    nmap -sV -F ${WlocSN}
    echo "</pre>"
   
else
    echo "Wireless not available."
fi

}

function eth_INFO()}{
if [[ ${ElocIP} != "" ]]; then

    echo "<h3> Nmap results for wifi IP </h3>"
    echo "<pre>"
    nmap -sV -F ${WlocSN}
    echo "</pre>"
   
else
    echo "Ethernet not available."
fi

}

But, there a couple problems with that approach. First of all, it's unlikely that the thief will be connected to both wireless and ethernet at the same time, so that will throw some sort of error. We also can't be sure that the name of the interface will be 'wlan0' or 'eth0', what is he is using his own wireless card or something? To get around that, we need to figure out exactly which NIC devices are online, and than grab the IP's and subnet's from there. For this, we need the help of for-loop magic:

INTFACES=$(/sbin/ifconfig -a | sed 's/[ \t].*//;/^\(lo\|\)$/d')
intIPS=$(for i in ${INTFACES}; do /sbin/ifconfig $i | grep Mask | cut -d ':' -f2 | cut -d " " -f1; done)


intSNS=$(for i in ${intIPS}; do echo $i | cut -d "." -f -3 | sed 's/$/.*/'; done)
sn_RESULTS=$(for i in ${intSNS}; do nmap -sV -F $i; done) 


echo ${sn_RESULTS}
192.168.1.*
10.0.0.*

This is much better. First, it grabs a list of all of the network interfaces that are up on the system (excluding the localhost), and stores it as a variable. Than it feeds that variable into the intIPS line, which utilizes some more grep & sed magic to print a list of each interface IP address. Finally, I had figure out a way to turn each IP address into a wildcard mask to feed to nmap (for example, turn 192.168.1.1 into 192.168.1.*). To do that, I had to study the sed manual for a while to figure out how to remove specific unknown characters from a regular expression and than replace them with something else:

for i in ${intIPS};
do echo $i | cut -d "." -f -3 | sed 's/$/.*/' 
done 

And wala, it works! Finally, we feed the list of subnets to scan to nmap, which gives us a lot of useful information about our nemisis's network enviroment:

Starting Nmap ( http://nmap.org )
Nmap scan report for router (10.0.0.1)
Host is up (0.063s latency).
Not shown: 98 closed ports
PORT   STATE SERVICE VERSION
53/tcp open  domain  dnsmasq 2.73rc4
80/tcp open  http    LuCI Lua http config


Starting Nmap ( http://nmap.org )
Nmap scan report for yourcomputer (10.0.0.101)
All ports on 10.0.0.101 are filtered (cause your smart)
Starting Nmap ( http://nmap.org )
Nmap scan report for felix (10.0.0.100)
(The 1640 ports scanned but not shown below are in state: closed)
PORT     STATE SERVICE    VERSION
21/tcp   open  ftp        WU-FTPD wu-2.6.1-20
22/tcp   open  ssh        OpenSSH 3.1p1 (protocol 1.99)
53/tcp   open  domain     ISC BIND 9.2.1
79/tcp   open  finger     Linux fingerd
111/tcp  open  rpcbind    2 (rpc #100000)
443/tcp  open  ssl/http   Apache httpd 2.0.39 ((Unix) mod_perl/1.99_04-dev)
515/tcp  open  printer
631/tcp  open  ipp        CUPS 1.1
953/tcp  open  rndc?
5000/tcp open  ssl/ftp    WU-FTPD wu-2.6.1-20
5001/tcp open  ssl/ssh    OpenSSH 3.1p1 (protocol 1.99)
5002/tcp open  ssl/domain ISC BIND 9.2.1
5003/tcp open  ssl/finger Linux fingerd
6000/tcp open  X11        (access denied)
8000/tcp open  http-proxy Junkbuster webproxy
8080/tcp open  http       Apache httpd 2.0.39 ((Unix) mod_perl/1.99_04-dev)
8081/tcp open  http       Apache httpd 2.0.39 ((Unix) mod_perl/1.99_04-dev)
Device type: general purpose
Running: Linux 2.4.X|2.5.X
OS details: Linux Kernel 2.4.0 - 2.5.20

Nmap finished: 1 IP address (1 host up) scanned in 42.494 seconds


In this case, the theif has at least one on his network that appears
to be very vulnerable (I borrowed this from nmap.org)
That will come in useful, but now we need a way to send this
information back home. This should also happen silently in the
background, and not leave any leftover files when it's done.
Originally I thought it may be a good idea to send all the gathered
information back home via email, but than I decided against that
because email is very insecure. It's possible to encrypt the message
with GPG before emailing it, but that has it's own issues too, like
you probably don't want your GPG key's password cached in memory
permantly if you can help it. The solution I decicided on was to send
it over SFTP to a server running SFTP in a chrooted enviroment,
protected by an RSA key:

function write_page(){
cat << _EOF_
<html>
<head>
<title>$TITLE</title>
</head>
<body bgcolor="black" text="white">
<h1>$TITLE</h1>
<p>$RIGHT_NOW</p>
<p><b> Local Subnet Scan Results: </b></p>
<pre>
${sn_RESULTS}
${pi_RESULTS}
</pre>
</body>
</html>
_EOF_
}
function phone_HOME(){
cd $workDIR
if [[ ! -f $workDIR/batch ]];then
cat << 'EOF' >> $workDIR/batch
put netenv*.html
EOF
fi
sftp -b batch $sftpUSER@$sftpHOST:/$sftpDIR
}

I figured I may as well have the output be in html format, in case someone did want to use email instead of sftp. To erase evidence of this script, I added the clean_UP function, with will delete the files left in /tmp with secure-delete if it's available, and if not than revert to normal 'rm'. Of course, this should probably also either be ran with the script command, or redirected to /dev/null, as not to leave any telltale error messages in the syslogs, like this:

netrecon > /dev/null 2>&1

So, putting it all together, this is the final script:


#!/bin/bash
#####################################################
# Bash Network Reconnaissance Script * Version 2.0  #                            
# DarkerEgo's Bash Snippets, GPL 2015               #
#####################################################
workDIR="/tmp/netrecon"
sftpUSER="user"
sftpHOST="remoteserver"
sftpDIR="some/directory"
OUTPUT="netenv.$(hostname).$(date +'%d-%m-%y').html"
TITLE="Bash Network Reconnaissance Results"
RIGHT_NOW=$(date +"%x %r %Z")
pubIP=$(curl ipreturn.tk)
#
INTFACES=$(/sbin/ifconfig -a | sed 's/[ \t].*//;/^\(lo\|\)$/d')
intIPS=$(for i in ${INTFACES}; do /sbin/ifconfig $i | grep Mask | cut -d ':' -f2 | cut -d " " -f1; done)
intSNS=$(for i in ${intIPS}; do echo $i | cut -d "." -f -3 | sed 's/$/.*/'; done)
sn_RESULTS=$(for i in ${intSNS}; do nmap -sV -F $i; done)
pi_RESULTS=(nmap -sV -A ${pubIP})
#
function prep_VARS(){
if [[ ! -d $workDIR ]];then
mkdir $workDIR
fi
if [[ -f $workDIR/$OUTPUT ]];then
srm $workDIR/$OUTPUT || rm $workDIR/$OUTPUT
fi
touch $workDIR/$OUTPUT
}
function write_page(){
cat << _EOF_
<html>
<head>
<title>$TITLE</title>
</head>
<body bgcolor="black" text="white">
<h1>$TITLE</h1>
<p>$RIGHT_NOW</p>
<p><b> Local Subnet Scan Results: </b></p>
<pre>
${sn_RESULTS}
${pi_RESULTS}
</pre>
</body>
</html>
_EOF_
}
function phone_HOME(){
cd $workDIR
if [[ ! -f $workDIR/batch ]];then
cat << 'EOF' >> $workDIR/batch
put netenv*.html
EOF
fi
sftp -b batch $sftpUSER@$sftpHOST:/$sftpDIR
}
function clean_UP(){
srm $workDIR/$OUTPUT || rm $workDIR/$OUTPUT
srm $workDIR/batch || rm $workDIR/batch
rmdir $workDIR
}
prep_VARS
write_page > $OUTPUT
phone_HOME
clean_UP
exit


And that is as much effort as I am going to put into that! By the way, I uploaded this to github as well, in case you'd like to pull it from there and avoid all those problems that the nasty windows style formatting can cause.

Edit: It might also be a good idea to also add a function that would ssh into your server for a few minutes upon each run, and do some reverse port forwarding so that you'd have a window to grab a shell that way. Or perhaps make it so that if the ip address changes, than the script would wait until the computer is idle for a few minutes, and than connect to your server over ssh, reverse forwarding back to your ssh port. Maybe I'll look into that and figure it out.

That's all for today.

No comments:

Post a Comment