Agile Hacking - A Homegrown Telnet-based Portscanner
So here is the scenario: the attacker has limited access to a box and he/she needs to perform a portscan from it. However, he/she does not want to download any tools to the target system. There might be various reasons for not wanting to upload a portscanner to the box. Perhaps, the attacker wants to minimize the footprint.
In my case, the reason why I had to come up with a solution to this problem is because I had to simulate an attack in which the attacker had gained access to a Internet-visible web server. In this case, I needed to perform a portscan of the backend database server and make sure that only required ports are visible (a customized mssql port in this case). For reasons that are irrelevant to this post, the customer could only give me restricted access (NOT root) to the web server via SSH.
I really didn't want to download a tool such as nmap and then compile it. In theory, I wouldn't be able to cause serious damage to the system since I was using a restricted user account. Even then, I always try to be as polite as possible with customers' environments during security assessments, especially when it's a production system.
Anyway, my solution to this problem was to write a simple TCP portscanner in bash which glues around the telnet command which is present on most Unix/Linux distributions. Literally, all I'm doing is looking for Connected to responses generated by telnet which tells us that a successful TCP connection was established (open port). Very vanilla and trivial stuff as you can see! Nevertheless, I accomplished what I wanted, which is to perform a portscan without having to download any tools and without requiring root privileges.
The following is the short version of our agile hacking TCP portscanner which you can literally copy and paste on your shell (just change the value of the HOST
variable to the IP address of the system you want to scan):
HOST=127.0.0.1;for((port=1;port<=65535;++port));do echo -en "$port ";if echo -en "open $HOST $port\nlogout\quit" | telnet 2>/dev/null | grep 'Connected to' > /dev/null;then echo -en "\n\nport $port/tcp is open\n\n";fi;done
The following is a more elaborate version of our portscanner which supports scanning for either common or all ports. The list of common ports is read from the /etc/services
file which is present on most Unix/Linux systems:
# telnet-based TCP portscanner
# By Adrian 'pagvac' Pastor | www.gnucitizen.org
# delay in seconds
DELAY=0.001
if [[ $# -ne 2 ]]
then
echo "usage: $0 <mode> <host>"
echo -e "modes:\t1 - common TCP ports only"
echo -e "\t2 - all TCP ports"
exit
fi
if [[ $1 -eq 1 ]]
then
echo "scanning for the following common TCP ports on $2 ..."
for port in `grep '/tcp' /etc/services | cut -d '/' -f 1 | cut -d ' ' -f 2 | grep -v '#' | awk '{print $2}' | sort | uniq`
do
echo -en "$port "
if echo -en "open $2 $port\nlogout\quit" | telnet 2>/dev/null | grep 'Connected to' > /dev/null
then
echo -en "\n\nport $port/tcp is open\n\n"
fi
sleep $DELAY
done
echo -en "\n"
elif [[ $1 -eq 2 ]]
then
echo "scanning for all TCP ports on $2 ..."
for((port=1;port<=65535;++port))
do
echo -en "$port "
if echo -en "open $2 $port\nlogout\quit" | telnet 2>/dev/null | grep 'Connected to' > /dev/null
then
echo -en "\n\nport $port/tcp is open\n\n"
fi
sleep $DELAY
done
echo -en "\n"
fi
Syntax follows:
gnucitizen $ ./telnetps.sh
usage: ./telnetps.sh <mode> <host>
modes:
1 - common TCP ports only
2 - all TCP ports
I realize this is not a very elegant tool, but I hope you can see how it can be useful in certain scenarios!
Archived Comments
nc -z host.example.com 20-30
use strict;
use IO::Socket;
my ($target,$remote,$results,$port,@ports);
unless (@ARGV > 0) { die "usage: $0 [ip]" }
$target = shift(@ARGV);
for ($port = 0; $port<65536; $port++)
{
$remote = IO::Socket::INET->new(
Proto => "tcp",
PeerAddr => $target,
PeerPort => $port,
);
if ($remote) {print "$port is open\n" };
}
HOST=127.0.0.1;for((port=1;port<=65535;++port));do echo -en "$port ";if exec 5<>/dev/tcp/$HOST/$port 2>/dev/null;then echo -en "\n\nport $port/tcp is open\n\n";fi;done
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 5242 100 5242 0 0 15489 0 --:--:-- --:--:-- --:--:-- 0
close ports look like this:
scanning port 122...
curl: (7) couldn't connect to host
----------script-----------
## portscanner implimented with curl
#!/bin/bash
if [ $# -ne 1 ]; then
echo 1>&2 "usage: $0 "
echo 1>&2 "mode 1 = well known ports 1-1024"
echo 1>&2 "mode 2 = all ports"
exit 127
fi
case "$1" in
1)
LIMIT=1024
for ((a=1; a /dev/null > out
cat out | grep -v "curl: (7) couldn't connect to host"
done;
;;
2)
LIMIT=65535
for ((a=1; a /dev/null > out
cat out | grep -v "curl: (7) couldn't connect to host"
done;
;;
esac
HOST=192.168.178.88;for((port=1;port<=65535;++port));do echo -en "$port ";if wget -F -S -t 1 -T 1 -v -O banner.txt $HOST:$port 2>&1 | grep connected;then echo -en "\n\nport $port/tcp is open\n\n";cat banner.txt;fi;done
wget should also be available on most of the systems. And - the coolest - it does a "banner grabbing" as well. Nice, isn't it?@ECHO OFF & ECHO start & (FOR /L %p IN (1,1,65535) DO (FOR /F "tokens=*" %a IN ('netsh diag connect iphost 127.0.0.1 %p ^| find /C /I "[NONE]"') DO ( IF %a == 0 echo %p))) & ECHO stop & @ECHO ON
It's rather slow since netsh seems to take quite a while to load, so you might want to narrow down the port range a bit ;>.
What I found interesting is the message the "netsh diag connect iphost" command outputs: "Server appears to be running on port(s) [NONE]" which seems to suggest you could enter more than one port to connect to, but I could'nt find out how to do so.#!/usr/bin/perl
use IO::Socket;
@ARGV||die'usage: perl scanner.pl host [number of threads]';
($|,$h,$t)=(1,@ARGV,20);$p=65535/$t;
for$n(1..$t){
pipe($r[$n],$w[$n]);next if fork;
print IO::Socket::INET->new(PeerAddr=>$h,PeerPort=>$_)?"Port $_ open\n":''for($p*($n-1)...$p*$n-1);
print{$w[$n]}'x';exit;
}
read($r[$_],$x,1)for(1..$t);
import socket
import getpass
import sys
import telnetlib
#Edit these
HOSTA = "78.32.236.185"
PasswordA = "Sch5636$\n"
HOSTB = "82.111.251.241"
PasswordB = "LLUcpe99\n"
HOSTC = "82.108.105.177"
PasswordC = "LLUcpe99\n"
PORT = "23"
#RAS Commands
jmp1 = "ip telnet "+HOSTB+" "+PORT+"\n"
jmp2 = "ip telnet "+HOSTC+" "+PORT+"\n"
#Connect to 1st router.
tn = telnetlib.Telnet(HOSTA)
print tn.read_until("Password: ")
tn.write(PasswordA)
print tn.read_until("ras>")
tn.write(jmp1)
#Connect to second router.
print tn.read_until("Password: ")
tn.write(PasswordB)
print tn.read_until("ras>")
tn.write(jmp2)
#Connect to target system.
print tn.read_until("Password: ")
tn.write(PasswordC)
print tn.read_until("ras>")
tn.write(jmp3)
print tn.read_until("Password: ")
tn.write(PasswordC)
print tn.read_until("ras>")
HOST=127.0.0.1;for p in {0..65535};do((bash -c "(>/dev/tcp/$HOST/$p)" 2> /dev/null && echo open: $p)&read -t0.1;kill $! 2>/dev/null)2>/dev/null;done
echo -en "open $HOST $PORT\nlogout\quit" | telnet 2>/dev/null | grep 'Connected to' > /dev/null
CONNECT_ERROR=$?
if[$CONNECT_ERROR]; then echo"no good"