Extending Network Reconnaissance Tools
We always come across situations when our beloved tools like Nmap, Nessus etc. cannot continue because of the limited functionality provided by them. The nature of pen testing is such that it requires these type of tools to be be extended and customized. That’s where the add-ons for these type of tools come in handy.
Add-ons can be written for most of the famous security tools out there like Nmap, Nessus, BurpSuite and Metasploit. We will be covering some of them in this article.
Writing Nmap Scripts
Nmap supports scripting. It has a powerful scripting engine. It allows users to write (and share) simple scripts to automate a wide variety of networking tasks. Nmap scripts are written in LUA language. LUA is a strongly typed scripting language. It is a simple language to learn.
On Linux, scripts are placed in “/usr/share/nmap/scripts” directory .
Let’s start by understanding a simple NSE script: http-headers.nse
[plain]
local http = require "http"
local nmap = require "nmap"
local shortport = require "shortport"
local stdnse = require "stdnse"
local table = require "table"
description = [[
Performs a HEAD request for the root folder ("/") of a web server and displays the HTTP headers returned.
]]
—
— @output
— PORT STATE SERVICE
— 80/tcp open http
— | http-headers:
— | Date: Fri, 25 Jan 2013 17:39:08 GMT
— | Server: Apache/2.2.14 (Ubuntu)
— | Accept-Ranges: bytes
— | Vary: Accept-Encoding
— | Connection: close
— | Content-Type: text/html
— |
— |_ (Request type: HEAD)
—
–@args path The path to request, such as <code>/index.php</code>. Default <code>/</code>.
–@args useget Set to force GET requests instead of HEAD.
author = "Ron Bowes"
license = "Same as Nmap–See http://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
portrule = shortport.http
action = function(host, port)
local path = stdnse.get_script_args(SCRIPT_NAME..".path") or "/"
local useget = stdnse.get_script_args(SCRIPT_NAME..".useget")
local request_type = "HEAD"
local status = false
local result
— Check if the user didn’t want HEAD to be used
if(useget == nil) then
— Try using HEAD first
status, result = http.can_use_head(host, port, nil, path)
end
— If head failed, try using GET
if(status == false) then
stdnse.print_debug(1, "http-headers.nse: HEAD request failed, falling back to GET")
result = http.get(host, port, path)
request_type = "GET"
end
if(result == nil) then
if(nmap.debugging() > 0) then
return "ERROR: Header request failed"
else
return nil
end
end
if(result.rawheader == nil) then
if(nmap.debugging() > 0) then
return "ERROR: Header request didn’t return a proper header"
else
return nil
end
end
table.insert(result.rawheader, "(Request type: " .. request_type .. ")")
return stdnse.format_output(true, result.rawheader)
end
[/plain]
As you can see here: status, result = http.can_use_head(host, port, nil, path)
This script uses the head parameter to get the info from a server.
To run this scan on Google:
nmap –script http-headers.nse google.com -p80 -n
If the scan is successful, we get the following:
[plain]
Host is up (0.095s latency).
Other addresses for google.com (not scanned): 173.194.36.14 173.194.36.3 173.194.36.2 173.194.36.6 173.194.36.1 173.194.36.0 173.194.36.7 173.194.36.4 173.194.36.5 173.194.36.8
PORT STATE SERVICE
80/tcp open http
| http-headers:
| Cache-Control: private
| Content-Type: text/html; charset=UTF-8
| Location: http://www.google.co.in/?gfe_rd=cr&ei=wFO5U7SjGMrV8geqkYDgBA
| Content-Length: 261
| Date: Sun, 06 Jul 2014 13:48:48 GMT
| Server: GFE/2.0
| Alternate-Protocol: 80:quic
| Connection: close
|
|_ (Request type: GET)
Nmap done: 1 IP address (1 host up) scanned in 0.50 seconds
[/plain]
Packet Manipulation Using Libpcap
Libpcap is a raw packet library available for Linux and Windows. It can be used to generate and craft raw packets. It can also be used to capture packets and parse them. Libpcap is usually installed as a device driver so that it can sniff data.
Libpcap can be installed from tcpdump.org. There are Ruby and Python bindings available too.
The common library files included with the libpcap package are pcap.h, Pcap-buf.h, and pcap-namedb.h.
When compiling a program, we need to include ilpcap.a with the compiler.
Let’s write a simple packet sender in libpcap:
[c]
#include <pcap.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv)
{
unsigned char err[0x100];
char *dev = "lo";
pcap_t *handle;
handle = pcap_open(dev,
100,
1,
1000,
NULL,
err);
if (handle)
{
printf("Error : %s", err);
return -1;
}
pcap_sendpacket(handle, "hello", strlen("hello")) ;
pcap_close(handle);
}
[/c]
Sending an ARP Request Using Pcap
We will begin with a concrete example by building a legitimate ARP packet. This time we will open eth0 interface.
[c]
#include <pcap.h>
#include <stdlib.h>
#include <stdio.h>
unsigned char ARP_PACKET[] = "xf8xdfxa8x10x17x9bx60x36xddx81x07x77x08x06x00x01x08x00x06x04x00x02x60x36xddx81x07x77xc0xa8x00x65xf8xdfxa8x10x17x9bxc0xa8x00x01";
int main(int argc, char **argv)
{
unsigned char err[0x100];
char *dev = "eth0";
pcap_t *handle;
handle = pcap_open(dev,
100,
1,
1000,
NULL,
err);
if (handle)
{
printf("Error : %s", err);
return -1;
}
pcap_sendpacket(handle, APR_PACKET, sizeof(ARP_PACKET)) ;
pcap_close(handle);
}
[/c]
Capturing Packets Using Libpcap
We can also capture packets using pcap. For that purpose we can set up a live capture using provided API functions. The following sample code shows how to capture packets and display the number of captured packets.
[c]
#include <pcap.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv)
{
unsigned char err[0x100];
char *dev = "eth0";
unsigned char Header[0x100] = {0};
const u_char *pkt_data;
unsigned int counter = 0;
pcap_t *handle;
handle = pcap_open(dev,
100,
1,
1000,
NULL,
err);
if (handle)
{
printf("Error : %s", err);
return -1;
}
while((res = pcap_next_ex( handle, &header, &pkt_data)) >= 0){
if(res == 0)
continue;
printf("Packets Recieved = %d" , counter++);
}
pcap_close(handle);
}
[/c]