Nmap Announce mailing list archives

Nmap stub v1


From: "rain.forest.puppy" <rfpuppy () iname com>
Date: Tue, 29 Dec 1998 21:57:45 -0600

Hello all,

I was thinking about the whole "nmap's only a scanner/make it an exploit
scanner" issue, and think I may have come up with a good solution.

Personally, I stradle the fence...while I think nmap should be left
alone to do only scanning, it does provide good info to use right then
and there to check for exploits.

So, I whipped up the nmap stub.  It's simple.  It will read in
human-readable output from nmap (for reasons I'll get to), reconstruct a
simple port list, and then run whatever code you want.  So, basically,
you get all the same info (list of TCP & UDP ports, IP, hostname & OS
name when available).

I like this approach, as I can first see what nmap spits out, edit it to
my heart's content, and then feed it to the stub.  That way you can also
paste together outputs from multiple machines into one big text file,
and then run the stub on that.

The reason why I did the human output rather than the machine output is
because I found it easier to parse.  :)  Also because I tend to forget
to specify an output file (but I can always look at the session log to
catch the output).  If someone wants to code the parser for the machine
output, let me know.  I personally plan to include support for nlog's db
format next (and then you can just run nlog's machine to nlog db
converter on it, then feed the nlog db into the stub).

I've only tested this code on Intel RedHat 5.2.  If it doesn't work on
other platforms, sorry.  If you can make it work on other platforms,
even better.  And if you can improve my lousy coding
('bucket-load-o-sscanfs'), great.

Also, I don't currently have a place to stick the newest versions of the
stub for public download.  Anyone want to volunteer approx. 10K of space
on a FTP/web server? :)

Lastly, I'm going to play around porting Ajax's vulnerability database
to use the stub...if anyone's interested.

Cheers,
.rain.forest.puppy
rfpuppy () iname com

------ begin sloppy code --------


/*************************************************************** 
nmap stub / v1.0

This file reads in nmap (v2.x human) output, puts it into port and host
structures, and then can call whatever routines you want (per host) to
check for exploits, etc.

If you have any suggestions, fixes, etc, let me know
rfpuppy () iname com    .rain.forest.puppy.     

----------------------------------------------------------------
global information the stub provides:

----In INDEX mode:----

int tcp_ports[65535]
int udp_ports[65535]

These two structures contain the port information (that actual state of
the port).  Initially set to 0 (port not found), changed to 1 (open).

So, to check if port 80 (http) is open:
if(tcp_ports[80]){ //port is open..// }

---In LIST mode:----

struct portnode{
unsigned int port;
unsigned int state;}
portnode tcp_ports[2048]
portnode udp_ports[2048]

Use in conjunction with tpnum/upnum (total number of ports).  Example:

for(int x=0; x < tpnum; x++){
        // do something with tcp_ports[x] // }

Perl equivalent:  foreach $found_port (@port_list) { // do whatever // }

----In all modes:----

char name[1024]
char ip[1024]
char os[1024] 
unsigned int tpnum
unsigned int upnum
int return_value

Resolved name of host (NULL string if not known), IP address in string
format, and OS guess (if available...NULL string if not known).  Tpnum
is
the number of tcp ports in list; upnum is the number of udp ports in
list.
Return_value is what's given when the program exits.

----------------------------------------------------------------

Todo: read in actual state and adjust port value (tcp_ports[x] in
INDEX, tcp_ports[x].state in LIST).  Figure 1 for open, 2 for
filtered, 3 for firewalled, etc.

****************************************************************/

#include <stdio.h>

/* define INDEX for index of ports, undefine INDEX for list of ports */
#define INDEX

/* define STATIC_FILE to specify a specific file to always open. 
Undefine
   it to take it from ARGV                      */
#undef STATIC_FILE

/* V---- remove the const if you want to change the debug value inline
*/
const int debug=0;  /* set to 1 just to see what's going on */

#ifdef STATIC_FILE
#define STATIC_FILE_NAME "nmap.out"
#endif

#ifdef INDEX
        int tcp_ports[65535];
        int udp_ports[65535];
#define MAX 65535
#else
        struct portnode {
        unsigned int port;
        unsigned int state;
        } portnode;
        struct portnode tcp_ports[2048];
        struct portnode udp_ports[2048];
#define MAX 2048
#endif

char name[1024];
char ip[1024], os[1024];
unsigned int tpnum=0;
unsigned int upnum=0;
int return_value=0;

int y;

void yourfunc(void){

/***********************************************************
Insert your function/code here to be called per host
***********************************************************/

/* this is example code */

#ifdef INDEX

/* demo of how to access index of ports */

        printf("Checking %s, ip: %s", name, ip);

        if (os[0] != '\0') printf(" OS: %s\n", os);
         else printf("\n");     

        printf("Found %i TCP ports, %i UDP ports\n", tpnum, upnum);
        
        if (tcp_ports[80]) printf("Seem to be running a web server\n");
        if (tcp_ports[21]) printf("Seem to be running a ftp server\n");
        if (tcp_ports[23]) printf("Seem to be running telnetd\n");

        printf("\n");
#else

/* demo of how to access list of ports */

        printf("Checking %s, ip: %s", name, ip);

        if (os[0] != NULL) printf(" OS: %s\n", os);
         else printf("\n");     

        printf("Found %i TCP ports, %i UDP ports\n", tpnum, upnum);

        printf("Open TCP ports:");
        for (y = 0; y < tpnum; y++)
          printf(" %i", tcp_ports[y].port);

        printf("\n\n"); 
#endif

/* end of example code */

/** End of your code/function *****************************/ 
}

FILE *fp;
char line[1024], copy[1024];
char s1[1024], s2[1024], s3[1024];
int c,tp;
unsigned int x, gothost=0;


int main(int argc, char *argv[]){
char filename[256];

/* shameless plug.  ;-)  */
printf("Nmap stub by .rain.forest.puppy.    rfpuppy () iname com\n");

for (x = 0; x < MAX; x++) 
#ifdef INDEX
  tcp_ports[x] = udp_ports[x] = 0;
#else
 
tcp_ports[x].state=tcp_ports[x].port=udp_ports[x].state=udp_ports[x].port=0;
#endif

#ifdef STATIC_FILE
 filename=STATIC_FILE_NAME;
#else
 if (argc < 2){
        printf("You need to specify the nmap input file on the commandline\n");
        return -1;}
 strncpy(filename,argv[1],255);
#endif

/***********************************************************
If you're going to process commandline switches, here's a
good place to do it.  If you do commandline switches, I
suggest you define STATIC_FILE, and then make a switch to
specify the filename.  Put the input file name into 'filename'.
By defining STATIC_FILE, you'll have a default filename
(defined in STATIC_FILE_NAME)
***********************************************************/

/* your getopts code */

/**********************************************************/

if ((fp=fopen(filename,"r")) == NULL){
        perror("fopen"); return -1;}

fgets(line,sizeof(line)-1,fp);
do {            /* main decoding loop */

  if(c = sscanf(line,"Interesting ports on %1023s (%1023[^)]):",s1,s2)){
    if(gothost){     /* we run function on first host when we
                        start the record for the second host */
      yourfunc();

      for (x=0; x < MAX; x++) 
#ifdef INDEX
  tcp_ports[x]=udp_ports[x]=0;
#else
 
tcp_ports[x].state=tcp_ports[x].port=udp_ports[x].state=udp_ports[x].port=0;
#endif

      strcpy(name,"\0"); /* no need to clear ip, as it */
      strcpy(os,"\0");   /* will be overwritten below  */
      tpnum = upnum = 0;
    } gothost = 1;
    if (c == 2){ 
      strncpy(name, s1, 1024);
      strncpy(ip, s2, 1024);
    } else sscanf(s1, "(%1024[^)])", ip);
    
    if (debug) printf("Setting hostname: %s ip: %s\n", s1, s2);
    fgets(line,sizeof(line)-1,fp);
  }

  if(!strcmp(line,"Port    State       Protocol  Service\n")){
    if (debug) printf("Adding ports:");
    fgets(line, sizeof(line)-1,fp);
    while(strcmp(line, "\n")){
      sscanf(line,"%i%20[ ]%20[^ ]%30[ ]%20[^
]%1024s",&tp,s1,s2,s1,s3,s1); 
      if (debug) printf(" %i/%s (%s)",tp,s3,s2);

      if(!strncmp(s3,"tcp",1023)) {
#ifdef INDEX
        tcp_ports[tp]=1;
#else
        tcp_ports[tpnum].port=tp;
        tcp_ports[tpnum].state=1;
#endif
        tpnum++;
      } else {
#ifdef INDEX
        udp_ports[tp]=1;
#else
        udp_ports[tpnum].port=tp;
        udp_ports[tpnum].state=1;
#endif
        upnum++;}

      fgets(line, sizeof(line)-1, fp);}

    if (debug) printf("\nAdded %i TCP ports, %i UDP
ports\n",tpnum,upnum);
    fgets(line, sizeof(line) - 1, fp);}
    
  if(sscanf(line,"Remote operating system guess: %1024[^\n]", s1)){
    strncpy(os, s1, 1024);
    if (debug) printf("OS: %s\n", s1);
  }

} while(fgets(line, sizeof(line) - 1, fp));

if (gothost) yourfunc(); /* catch the last host */
fclose(fp);

/***********************************************************
Do any cleanup you need to here
***********************************************************/


return return_value;}


Current thread: