[Violent Python] -TCP Full Connect Scan
TCP Full Connect Scan
An attacker routinely performs a port scan in the opening salvo of any successful cyber assault. One type of port scan includes sending a TCP SYN packet to a series of common ports and waiting for a TCP ACK response that will result in signaling an open port. In contrast, a TCP Connect Scan uses the full three-way handshake to determine the availability of the service or port.
So let's begin by writing our own TCP port scanner that utilizes a TCP full connect scan to identify hosts. To begin, we will import the Python implementation of the BSD socket API. The socket API provides us with some functions that will be useful in implementing our TCP port scanner. Let's examine a couple before proceeding.
1、socket.gethostbyname(hostname) - This function takes a hostname such as www.syngress.com and returns an IPv4 address format such as 69.163.177.2
from socket import *
print "The domain of hbfu.edu.cn is " + gethostbyname("hbfu.edu.cn")
2、socket.gethostbyaddr(IP address) - This function takes an IPv4 address and returns a triple containing the hostname, alternative list of hostnames, and a list of IPv4/v6 addresses for the same interface on the host.
IF THE ERROR OCCURS: IT's BECAUSE not every IP address has reverse DNS. Sometimes this is on purpose, sometimes it's because you're looking at an internal address and there's no need for it inside the network so it wasn't worth setting up, sometimes someone just screwed up.
3、socket.socket([family[,type[,proto]]]) - This function creates an instance of a new socket given the family. Options for the socket family are AF_INET, AF_INET6, or AF_UNIX. Additionally, the socket can be specified as SOCK_STREAM for a TCP socket or SOCK_DGRAM for a UDP socket. Finally, the protocol number is usually zero and is omitted in most cases.
4、socket.create_connection(address[,timeout[,source_address]]) - This function takes a 2-tuple (host, port) and returns an instance of a network socket. Additionally, it has the option of taking a timeout and source address.
Process
In order to better understand how our TCP Port Scanner works, we will break our script into five unique steps and write Python code for each of them.
- First, we will input a hostname and a comma-separated list of ports to scan.
- Next, we will translate the hostname into an IPv4 Internet address. For each port in the list, we will also connect to the target address and specific port.
- Finally, to determine the specific service running on the port, we will send garbage data and read the banner results sent back by the specific application.
In our first step, we accept the hostname and port from the user. For this, our program utilizes the optparse library for parsing command-line options. The call to optparse. OptionPaser([usage message]) creates an instance of an option parser. Next, parser.add_option specifies the individual command-line options for our script. The following example shows a quick method for parsing the target hostname and port to scan.
import optparse
parser = optparse.OptionParser('usage %prog -H'+'<target host> -p <target port>')
parser.add_option('-H',dest='tgtHost',type='string',help='specify target host')
parser.add_option('-p',dest='tgtPort',type='int',help='specify target port')
(options,args) = parser.parse_args()
tgtHost = options.tgtHost
tgtPort = options.tgtPort
if (tgtHost == None) | (tgtPort == None):
print parser.usage
exit(0)
Next, we will build two functions connScan and portScan. The portScan function takes the hostname and target ports as arguments. It will first attempt to resolve an IP address to a friendly hostname using the gethostbyname() function. Next, it will print the hostname (or IP address) and enumerate it through each individual port attempting to connect using the connScan function. The connScan function will take two arguments: tgtHost and tgtPort and attempt to create a connection to the target host and port. If it is successful, connScan will print an open port message. If unsuccessful, it will print the closed port message.
from socket import *
def connScan(tgtHost,tgtPort):
try:
connSkt = socket(AF_INET, SOCK_STREAM)
connSkt.connect((tgtHost,tgtPort))
print '[+]%d/tcp open'% tgtPort
connSkt.close()
except:
print '[-]%d/tcp closed'% tgtPort
def portScan(tgtHost,tgtPorts):
try:
tgtIP = gethostbyname(tgtHost)
except:
print "[-] Cannot resolve '%s': Unknown host"%tgtHost
return
try:
tgtName = gethostbyaddr(tgtIP)
print '\n[+] Scan Results for: '+tgtName[0]
except:
print '\n[+] Scan Results for: '+tgtIP
setdefaulttimeout(1)
for tgtPort in tgtPorts:
print 'Scanning port '+tgtPort
connScan(tgtHost, int(tgtPort))
Application Banner Grabbing
In order to grab the application banner from our target host, we must first insert additional code into the connScan function. After discovering an open port, we send a string of data to the port and wait for the response. Gathering this response might give us an indication of the application running on the target host and port.
# coding:utf-8
import optparse
import socket
from socket import *
def connScan(tgtHost,tgtPort):
try:
connSkt = socket(AF_INET, SOCK_STREAM)
connSkt.connect((tgtHost,tgtPort))
print '[+]%d/tcp open'% tgtPort
connSkt.close()
except:
print '[-]%d/tcp closed'% tgtPort
def portScan(tgtHost,tgtPorts):
try:
tgtIP = gethostbyname(tgtHost)
except:
print "[-] Cannot resolve '%s': Unknown host"%tgtHost
return
try:
tgtName = gethostbyaddr(tgtIP)
print '\n[+] Scan Results for: '+tgtName[0]
except:
print '\n[+] Scan Results for: '+tgtIP
setdefaulttimeout(1)
for tgtPort in tgtPorts:
print 'Scanning port '+tgtPort
connScan(tgtHost, int(tgtPort))
def main():
parser = optparse.OptionParser('usage %prog -H'+'<target host> -p <target port>')
parser.add_option('-H',dest='tgtHost',type='string',help='specify target host')
parser.add_option('-p',dest='tgtPort',type='int',help='specify target port[s] separated by comma')
(options,args) = parser.parse_args()
tgtHost = options.tgtHost
tgtPort = str(options.tgtPort).split(',')
if (tgtHost == None) | (tgtPort == None):
print '[-] You must specify a target host and port[s].'
exit(0)
portScan(tgtHost,tgtPort)
if __name__ == '__main__':
main()
For example, scanning a host with a FreeFloat FTP Server installed might reveal the following information in the banner grab:
attacker$ python portscanner.py -H 192.168.1.37 -H 192.168.1.37 -p 21,22,80
[+] Scan Results for: 192.168.1.37
Scanning port 21
[+] 21/tcp open
[+] 220 FreeFloat Ftp Server (Version 1.00).
In knowing that the server runs FreeFloat FTP (Version 1.00) will prove to be useful for targeting our application as seen later.
Threading the Scan
Depending on the timeout variable for a socket, a scan of each socket can take several seconds. While this appears trivial, it quickly adds up if we are scanning multiple hosts or ports. Ideally, we would like to scan sockets simultaneously as opposed to sequentially. Enter Python threading. Threading provides a way to perform these kinds of executions simultaneously. To utilize this in our scan, we will modify the iteration loop in our portScan() function. Notice how we call the connScan function a thread. Each thread created in the iteration will now appear to execute at the same time.
for tgtPort in tgtPorts:
t = Thread(target=connScan, args=(tgtHost,int(tgtPort)))
t.start()
While this provides us with a significant advantage in speed, it does present one disadvantage. Our function connScan() prints output to the screen. If multiple threads print output at the same time, it could appear garbled and out of order. In order to allow a function to have complete control of the screen, we will use a semaphore. A simple semaphore provides us a lock to prevent other threads from processing. Notice that prior to printing an output, we grabbed a hold of the lock using screenLock.acquire(). If open, the semaphore will grant us access to proceed and we will print to the screen. If locked, we will have to wait until the thread holding the semaphore releases the lock. By utilizing this semaphore, we now ensure only one thread can print to the screen at any given point in time. In our exception handling code, the keyword finally executes the following code before terminating the block.
screenLock = Semaphore(value=1)
def connScan(tgtHost,tgtPort):
try:
connSkt = socket(AF_INET,SOCK_STREAM)
connSkt.connect((tgtHost,tgtPort))
connSkt.send('ViolentPython\r\n')
results = connSkt.recv(100)
screenLock.acquire()
print '[+]%d/tcp open'% tgtPort
print '[+] ' + str(results)
except:
screenLock.acquire()
print '[-]%d/tcp closed'%tgtPort
finally:
screenLock.release()
connSkt.close()
Placing all other functions into the same script and adding some option parsing, we produce our final port scanner script.
# coding:utf-8
import optparse
import socket
from socket import *
from threading import *
screenLock = Semaphore(value=1)
def connScan(tgtHost,tgtPort):
try:
connSkt = socket(AF_INET, SOCK_STREAM)
connSkt.connect((tgtHost,tgtPort))
connSkt.send('ViolentPython\r\n')
results = connSkt.recv(100)
screenLock.acquire()
print '[+]%d/tcp open'% tgtPort
print '[+] ' + str(results)
except:
screenLock.release()
print '[-]%d/tcp closed'% tgtPort
finally:
screenLock.release()
connSkt.close()
def portScan(tgtHost,tgtPorts):
try:
tgtIP = gethostbyname(tgtHost)
except:
print "[-] Cannot resolve '%s': Unknown host"%tgtHost
return
try:
tgtName = gethostbyaddr(tgtIP)
print '\n[+] Scan Results for: '+tgtName[0]
except:
print '\n[+] Scan Results for: '+tgtIP
setdefaulttimeout(1)
for tgtPort in tgtPorts:
t = Thread(target=connScan,args=(tgtHost,int(tgtPort)))
t.start()
def main():
parser = optparse.OptionParser('usage %prog -H'+'<target host> -p <target port>')
parser.add_option('-H',dest='tgtHost',type='string',help='specify target host')
parser.add_option('-p',dest='tgtPort',type='string',help='specify target port[s] separated by comma')
(options,args) = parser.parse_args()
tgtHost = options.tgtHost
tgtPort = str(options.tgtPort).split(',')
if (tgtHost == None) | (tgtPort == None):
print parser.usage
exit(0)
portScan(tgtHost,tgtPort)
if __name__ == '__main__':
main()
MORE INFORMATION...
- TCP SYN SCAN - Also known as a half-open scan, this type of scan initiates a TCP connection with an SYN packet and waits for a response. A reset packet indicates the port is closed while an SYN/ACK indicates the port is open.
- TCP NULL SCAN - A null scan sets the TCP flag header to zero. If an RST is received, it indicates the port is closed.
- TCP FIN SCAN - A TCP FIN scan sends the FIN to tear down an active TCP connection and wait for a graceful termination. If an RST is received, it indicates the port is closed.
- TCP XMAS SCAN - An XMAS Scan sets the PSH, FIN, and URG TCP Flags. If an RST is received, it indicates the port is closed.
Copy from book - <