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