• Div0 Blog Editor

Port Scanning & Banner Grabbing Using Python

My Network Setup

  • My Machine: Ubuntu 14.04 LTS with Python 2.7.6, IP address: 192.168.209.128

  • Another Machine: “Damn Vulnerable Linux” (DVL), IP address: 192.168.209.129

Port Scanning

import optparse 
from socket import * 
 
def conn(targetHost, targetPort): 
  try: 
    conn = socket(AF_INET, SOCK_STREAM)
    conn.connect((targetHost, targetPort)) 
    print '[+] Connection to ' + targetHost + ' port ' + str(targetPort) + ' succeeded!' 
 
  except Exception, e: 
    print '[-] Connection to ' + targetHost + ' port ' + str(targetPort) + ' failed: ' + str(e) 
 
  finally: 
    conn.close() 
 
def main(): 
  parser = optparse.OptionParser("%prog -t <target host(s)> -p <target port(s)>") 
  parser.add_option('-t', dest='targetHosts', type='string', help='Specify the target host(s); Separate them by commas') 
  parser.add_option('-p', dest='targetPorts', type='string', help='Specify the target port(s); Separate them by commas') 
 
  (options, args) = parser.parse_args() 
 
  if (options.targetHosts == None) | (options.targetPorts == None): 
    print parser.usage 
    exit(0) 
 
  targetHosts = str(options.targetHosts).split(',') 
  targetPorts = str(options.targetPorts).split(',') 
 
  setdefaulttimeout(5) 
 
  for targetHost in targetHosts: 
    for targetPort in targetPorts: 
      conn(targetHost, int(targetPort)) 
      print '' 
 
if __name__ == '__main__': 
  main()

Taking in 2 arguments (-t for target hosts/nodes, and -p for target ports), it informs the user if the port is open or close by attempting to create a socket connection to the respective host-port combination. The port is considered as open if the attempt succeeds, and close otherwise.

An example of my script’s output:

python PortScanner .py –t 192.168.98.128,192.168.98.129,edgis –p 21,22,80,3306

My Ubuntu machine has SSH and Apache2 service running. And my DVL has an additional MySQL service running. Host “edgis” does not exist on my network.

Port Scanning using Python-Nmap Library

My Python script allows user to scan multiple hosts and ports by listing them (separated by commas). But what about notations such as a range of hosts/ports (using the character ‘-‘) like what Nmap allows? We can certainly expand the existing script to fit such needs, but why rebuild the wheel Nmap has provided? Here’s how you can utilise the Python-Nmap library.

import optparse  
import nmap 
 
def nmapScan(targetHosts, targetPorts): 
  try: 
    scanner = nmap.PortScanner() 
    scanner.scan(targetHosts, targetPorts) 
 
  for targetHost in scanner.all_hosts(): 
    if scanner[targetHost].state() == 'up': 
      print targetHost + ' is up' 
  for targetPort in scanner[targetHost]['tcp']: 
    print 'Port ' + str(targetPort) + '/tcp ' + scanner[targetHost]['tcp'][int(targetPort)]['name'] + ' is ' + scanner[targetHost]['tcp'][int(targetPort)]['state'] 
    print '' 
  except Exception, e: 
    print '[-] Something bad happened during the scan: ' + str(e) 
 
def main(): 
  ... 
  targetHosts = str(options.targetHosts) 
  targetPorts = str(options.targetPorts) 
  nmapScan(targetHosts, targetPorts)
python NmapScanner.py -t 192.168.98.125-130 -p 20,21,80,3306
python NmapScanner.py –t 192.168.98.125-130 –p 1-1024

Banner Grabbing

Port scanning identifies a list of open ports of a target host. Sometimes it’s necessary to find out more about the services running on these ports. Banner grabbing is one of the easiest methods to do so.

This can be easily done by adding an additional function grab(), and editing the existing conn() function to the first script mentioned above.

def conn(targetHost, targetPort): 
  try: 
    conn = socket(AF_INET, SOCK_STREAM) 
    conn.connect((targetHost, targetPort)) 
    print '[+] Connection to ' + targetHost + ' port ' + str(targetPort) + ' succeeded!' grab(conn) 
  ... 
 
def grab(conn): 
  try: 
    conn.send('Hello, is it me you\'re looking for? \r\n') 
    ret = conn.recv(1024) 
    print '[+]' + str(ret) 
    return 
  except Exception, e: 
    print '[-] Unable to grab any information: ' + str(e) 
    return

We are able to grab the banner from the Apache service running on my DVL machine, but not the Apache2 service running on my Ubuntu machine. That’s because the more up-to-date HTTP services require specific input for it to return its banner.

So here’s a little tweak – introduce grabHTTP() and edit the existing conn() function.

def conn(targetHost, targetPort): 
  try: 
    ... 
    if targetPort == 80: 
      grabHTTP(conn) 
    else: 
      grab(conn) 
  ... 
 
def grabHTTP(conn): 
  try: 
    conn.send('GET HTTP/1.1 \r\n') 
    ret = conn.recv(1024) 
    print '[+]' + str(ret) 
    return 
  except Exception, e: 
    print '[-] Unable to grab any information: ' + str(e) 
    return

What Now? Why Do This?

By the end of this, you may be feeling a little excited that you've coded your own port scanner. But an afterthought might follow – “why do this when there are so many freely available port scanning tools out there?” – “Why write a Python script that uses Nmap when it’s easier to use Nmap itself?”

First, because coding is fun. Second, this can be just the beginning of writing your own automated exploit script. You can make your script fires up tools such as Metasploit and exploit hosts based on your reconnaissance results, etc. – all using one simple script, and not yourself scrambling through all your tools that are scattered all over your system.

Reference

T.J. O’Connor’s very well written book – Violent Python, 1st ed., Syngress, Novber 2008.

Author

Emil Tan, Skipper & Co-Founder of Div0.

 
  • Facebook
  • Twitter
  • YouTube

Contact Us

Terms of Use | Code of Conduct

All rights reserved.

Division Zero (Div0) © 2017-2020.

Edgis © 2011-2017.