GreySec Forums

Full Version: port scan (+ subnet calculator)
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
The fun part of this was actually getting the subnet calculator code working. While I already knew subnetting it still was extremely helpful to make this and think about addresses solely in terms of a bit string.

I think there's a library function that will convert text ip address to integer and probably do it better, but oh well, I still needed a way to get the cidr, network address, and broadcast address.

A warning, I wrote this on a little-endian machine, it might break on big-endian. I haven't tested and I'm not sure if it will work, I think it won't as I swap the endianness at one point in order to stick it into the struct for use as a socket. The subnet calculator logic should be independent of endianness. It assembles the bit string, your computer can interpret it however.

Otherwise it's just a generic port scanner. Since it does a full TCP connection it is a bit less subtle than the nmap default scan.

https://github.com/shatwofiftysix/host-scan

host-scan.c
Spoiler(Show)
Code:
// host-scan.c
// scan for hosts and maybe ports too
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
 
// local includes
#include "subnet.h"
 
void usage() {
  puts("usage: host-scan <subnet/cidr>");
  puts("ex: host-scan 10.10.0.0/16");
  puts("ex: host-scan 192.168.100.100/32");
}
 
int main(int argc, char ** argv) {
  // hard coded vars; should move to args
  int debug     = 0;
  int startPort = 1;
  int endPort   = 65535;
 
  // parse args
  if (argc < 2) {
    usage();
  }
  int subnet[5];
 
  sscanf(argv[1], "%d.%d.%d.%d/%d",   (int *) &subnet[0],
                                      (int *) &subnet[1],
                                      (int *) &subnet[2],
                                      (int *) &subnet[3],
                                      (int *) &subnet[4]);
 
  if (subnet[4] < 0 || subnet[4] > 32) {
    printf("bad cidr: %d\n", subnet[4]);
    return -1;
  }
 
  unsigned int userIp = ip4AddrArrToBits(subnet);
  unsigned int mask = getIp4MaskFromCidr(subnet[4]);
  unsigned int ntwAddr;
  unsigned int firstAddr;
  unsigned int bcastAddr;
  unsigned int lastAddr;
   
  if (subnet[4] == 32) {
    ntwAddr = userIp;
    firstAddr = userIp;
    bcastAddr = userIp;
    lastAddr = userIp;
  } else if (subnet[4] == 31) {
    // nonsensical cidr, make it work anyway
    ntwAddr = getIp4NtwAddr(userIp, mask); // ip - 1
    firstAddr = ntwAddr;
    bcastAddr = userIp;
    lastAddr = userIp;
  } else {   
    ntwAddr = getIp4NtwAddr(userIp, mask); // if this is 0 user gave nonsensical address/mask
    firstAddr = ntwAddr + 1;
    bcastAddr = getIp4BcastAddr(ntwAddr, subnet[4]);
    lastAddr = bcastAddr - 1;
  }
 
  if (debug) {   
    printIp4(userIp);
    printIp4(mask);
    printIp4(ntwAddr);
    printIp4(firstAddr);
    printIp4(bcastAddr);
    printIp4(lastAddr);
  }
  // done parsing/sanitizing user input
 
  struct sockaddr_in targetSA;
  memset(&targetSA, 0, sizeof targetSA);
  targetSA.sin_family = AF_INET;
  struct in_addr targetAddr;
  memset(&targetAddr, 0, sizeof targetAddr);
  int sockfd;
 
 
  // iterate all addresses
  for (int addr = firstAddr; addr <= lastAddr; addr++) {
    printIp4(addr);  
 
    // TODO: ping establish it's up first; or maybe quit if all <1024 are closed; make it an option
 
    // htonl/ntohl just swap endianess when not used on struct
    // Will break on big endian (!intel) machine?  
    // Or not because both struct and num will be reversed (since it was created bitwise)?
    targetAddr.s_addr = ntohl(addr); // TODO ^^^^^
    targetSA.sin_addr = targetAddr;
 
    // port scan
    for (int port = startPort; port <= endPort; port++) {
      sockfd = socket(AF_INET, SOCK_STREAM, 0);
      if (sockfd < 0) {
        perror("socket error");
      }
 
      targetSA.sin_port = htons(port);
      if (connect(sockfd, (struct sockaddr *)&targetSA, sizeof targetSA) < 0) {
        if (debug) {
          printf("port: %d ; error: %s\n", port, strerror(errno));
        }
      } else {
        printf("port: %d open\n", port);
      }
      fflush(stdout);
      close(sockfd);
    }
    printf("\n");
  }
 
  return 0;
}

subnet.c
Spoiler(Show)
Code:
// subnet.c
// handle human readable ip as computer usable bit string
// creates big endian bit string (ignoring system architecture)
 
// example:
// int subnet[] = {192, 168, 100, 99, 24};
// unsigned int userIp = ip4AddrArrToBits(subnet);
// unsigned int mask = getIp4MaskFromCidr(subnet[4]);
// unsigned int ntwAddr = getIp4NtwAddr(userIp, mask);
// unsigned int firstAddr = ntwAddr + 1;
// unsigned int bcastAddr = getIp4BcastAddr(ntwAddr, subnet[4]);
// unsigned int lastAddr = bcastAddr - 1;
 
// for debugging endianess:
// struct sockaddr_in myaddr;
// myaddr.sin_family = AF_INET;
// myaddr.sin_port = htons(55);
// inet_aton("127.0.0.1", &myaddr.sin_addr.s_addr);
 
// printf("struct localhost: %d\n", myaddr.sin_addr.s_addr);
// printf("ntohl(struct) localhost: %d\n", ntohl(myaddr.sin_addr.s_addr));
// printf("calc localhost: %d\n", addr);
// printf("htonl(calc) localhost: %d\n", htonl(addr));
// printf("big localhost: %d\n", 0x7f000001);
// printf("little localhost: %d\n", 0x100007f);
 
// struct localhost: 16777343
// ntohl(struct) localhost: 2130706433
// calc localhost: 2130706433
// htonl(calc) localhost: 16777343
// big localhost: 2130706433
// little localhost: 16777343
 
 
#include <stdio.h>
#include <math.h>
 
unsigned int ip4AddrArrToBits(int * ipArr) {
  unsigned int ip =    (ipArr[0] << 24 |
                        ipArr[1] << 16 |
                        ipArr[2] << 8  |
                        ipArr[3]);
 
  return ip;
}
 
int bitsToIp4AddrArr(unsigned int ipInt, int * ipArr) {
  ipArr[0] = (ipInt & 0xff000000) >> 24;
  ipArr[1] = (ipInt & 0x00ff0000) >> 16;
  ipArr[2] = (ipInt & 0x0000ff00) >> 8;
  ipArr[3] = (ipInt & 0x000000ff);
   
  return 0;
}
 
int printIp4(int ip) {
  printf("%d.%d.%d.%d\n", (ip & 0xff000000) >> 24,
                          (ip & 0x00ff0000) >> 16,
                          (ip & 0x0000ff00) >> 8,
                          (ip & 0x000000ff));
  return 0;
}
 
unsigned int getIp4MaskFromCidr(int cidr) {
  // use shift because pow trick only works with big endian: 2^cidr - 1
  return 4294967295 << (32-cidr);
}
 
unsigned int getIp4NtwAddr(unsigned int ip, unsigned int mask) {
  // eg. 10.10.10.10 & 255.255.0.0 = 10.10.0.0
  return ip & mask;
}
 
unsigned int getIp4BcastAddr (unsigned int ntwAddr, int cidr) {
  // eg. 0.0.0.255 | 10.10.10 = 10.10.10.255
  return (4294967295 >> cidr) | ntwAddr;
}

subnet.h
Spoiler(Show)
Code:
// subnet.h
// handle human readable ip as computer usable bit string
// creates big endian bit string (ignoring system architecture)
 
unsigned int ip4AddrArrToBits(int * ipArr);
int bitsToIp4AddrArr(unsigned int ipInt, int * ipArr);
int printIp4(int ip);
unsigned int getIp4MaskFromCidr(int cidr);
unsigned int getIp4NtwAddr(unsigned int ip, unsigned int mask);
unsigned int getIp4BcastAddr (unsigned int ntwAddr, int cidr);
I really like the way you write C. I have no comment beyond that other than, what was the first programming language you learned?
My first language was c++ though I don't know how much it really affected my style. More so lately I'm trying to make a concentrated effort at writing cleaner code, which is mostly to make variable names and function names speak for themselves. Single letter and nondescript variables make me REEEEEE!
(02-16-2017, 02:53 AM)StickFigure Wrote: [ -> ]My first language was c++ though I don't know how much it really affected my style. More so lately I'm trying to make a concentrated effort at writing cleaner code, which is mostly to make variable names and function names speak for themselves. Single letter and nondescript variables make me REEEEEE!

Lol same. In any event good job. You get bonus points for readability.
(02-09-2017, 04:56 AM)StickFigure Wrote: [ -> ]The fun part of this was actually getting the subnet calculator code working. While I already knew subnetting it still was extremely helpful to make this and think about addresses solely in terms of a bit string.

I think there's a library function that will convert text ip address to integer and probably do it better, but oh well, I still needed a way to get the cidr, network address, and broadcast address.

A warning, I wrote this on a little-endian machine, it might break on big-endian. I haven't tested and I'm not sure if it will work, I think it won't as I swap the endianness at one point in order to stick it into the struct for use as a socket. The subnet calculator logic should be independent of endianness. It assembles the bit string, your computer can interpret it however.

Otherwise it's just a generic port scanner. Since it does a full TCP connection it is a bit less subtle than the nmap default scan.

https://github.com/shatwofiftysix/host-scan

host-scan.c
Spoiler(Show)
Code:
// host-scan.c
// scan for hosts and maybe ports too
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
 
// local includes
#include "subnet.h"
 
void usage() {
  puts("usage: host-scan <subnet/cidr>");
  puts("ex: host-scan 10.10.0.0/16");
  puts("ex: host-scan 192.168.100.100/32");
}
 
int main(int argc, char ** argv) {
  // hard coded vars; should move to args
  int debug     = 0;
  int startPort = 1;
  int endPort   = 65535;
 
  // parse args
  if (argc < 2) {
    usage();
  }
  int subnet[5];
 
  sscanf(argv[1], "%d.%d.%d.%d/%d",   (int *) &subnet[0],
                                      (int *) &subnet[1],
                                      (int *) &subnet[2],
                                      (int *) &subnet[3],
                                      (int *) &subnet[4]);
 
  if (subnet[4] < 0 || subnet[4] > 32) {
    printf("bad cidr: %d\n", subnet[4]);
    return -1;
  }
 
  unsigned int userIp = ip4AddrArrToBits(subnet);
  unsigned int mask = getIp4MaskFromCidr(subnet[4]);
  unsigned int ntwAddr;
  unsigned int firstAddr;
  unsigned int bcastAddr;
  unsigned int lastAddr;
   
  if (subnet[4] == 32) {
    ntwAddr = userIp;
    firstAddr = userIp;
    bcastAddr = userIp;
    lastAddr = userIp;
  } else if (subnet[4] == 31) {
    // nonsensical cidr, make it work anyway
    ntwAddr = getIp4NtwAddr(userIp, mask); // ip - 1
    firstAddr = ntwAddr;
    bcastAddr = userIp;
    lastAddr = userIp;
  } else {   
    ntwAddr = getIp4NtwAddr(userIp, mask); // if this is 0 user gave nonsensical address/mask
    firstAddr = ntwAddr + 1;
    bcastAddr = getIp4BcastAddr(ntwAddr, subnet[4]);
    lastAddr = bcastAddr - 1;
  }
 
  if (debug) {   
    printIp4(userIp);
    printIp4(mask);
    printIp4(ntwAddr);
    printIp4(firstAddr);
    printIp4(bcastAddr);
    printIp4(lastAddr);
  }
  // done parsing/sanitizing user input
 
  struct sockaddr_in targetSA;
  memset(&targetSA, 0, sizeof targetSA);
  targetSA.sin_family = AF_INET;
  struct in_addr targetAddr;
  memset(&targetAddr, 0, sizeof targetAddr);
  int sockfd;
 
 
  // iterate all addresses
  for (int addr = firstAddr; addr <= lastAddr; addr++) {
    printIp4(addr);  
 
    // TODO: ping establish it's up first; or maybe quit if all <1024 are closed; make it an option
 
    // htonl/ntohl just swap endianess when not used on struct
    // Will break on big endian (!intel) machine?  
    // Or not because both struct and num will be reversed (since it was created bitwise)?
    targetAddr.s_addr = ntohl(addr); // TODO ^^^^^
    targetSA.sin_addr = targetAddr;
 
    // port scan
    for (int port = startPort; port <= endPort; port++) {
      sockfd = socket(AF_INET, SOCK_STREAM, 0);
      if (sockfd < 0) {
        perror("socket error");
      }
 
      targetSA.sin_port = htons(port);
      if (connect(sockfd, (struct sockaddr *)&targetSA, sizeof targetSA) < 0) {
        if (debug) {
          printf("port: %d ; error: %s\n", port, strerror(errno));
        }
      } else {
        printf("port: %d open\n", port);
      }
      fflush(stdout);
      close(sockfd);
    }
    printf("\n");
  }
 
  return 0;
}

subnet.c
Spoiler(Show)
Code:
// subnet.c
// handle human readable ip as computer usable bit string
// creates big endian bit string (ignoring system architecture)
 
// example:
// int subnet[] = {192, 168, 100, 99, 24};
// unsigned int userIp = ip4AddrArrToBits(subnet);
// unsigned int mask = getIp4MaskFromCidr(subnet[4]);
// unsigned int ntwAddr = getIp4NtwAddr(userIp, mask);
// unsigned int firstAddr = ntwAddr + 1;
// unsigned int bcastAddr = getIp4BcastAddr(ntwAddr, subnet[4]);
// unsigned int lastAddr = bcastAddr - 1;
 
// for debugging endianess:
// struct sockaddr_in myaddr;
// myaddr.sin_family = AF_INET;
// myaddr.sin_port = htons(55);
// inet_aton("127.0.0.1", &myaddr.sin_addr.s_addr);
 
// printf("struct localhost: %d\n", myaddr.sin_addr.s_addr);
// printf("ntohl(struct) localhost: %d\n", ntohl(myaddr.sin_addr.s_addr));
// printf("calc localhost: %d\n", addr);
// printf("htonl(calc) localhost: %d\n", htonl(addr));
// printf("big localhost: %d\n", 0x7f000001);
// printf("little localhost: %d\n", 0x100007f);
 
// struct localhost: 16777343
// ntohl(struct) localhost: 2130706433
// calc localhost: 2130706433
// htonl(calc) localhost: 16777343
// big localhost: 2130706433
// little localhost: 16777343
 
 
#include <stdio.h>
#include <math.h>
 
unsigned int ip4AddrArrToBits(int * ipArr) {
  unsigned int ip =    (ipArr[0] << 24 |
                        ipArr[1] << 16 |
                        ipArr[2] << 8  |
                        ipArr[3]);
 
  return ip;
}
 
int bitsToIp4AddrArr(unsigned int ipInt, int * ipArr) {
  ipArr[0] = (ipInt & 0xff000000) >> 24;
  ipArr[1] = (ipInt & 0x00ff0000) >> 16;
  ipArr[2] = (ipInt & 0x0000ff00) >> 8;
  ipArr[3] = (ipInt & 0x000000ff);
   
  return 0;
}
 
int printIp4(int ip) {
  printf("%d.%d.%d.%d\n", (ip & 0xff000000) >> 24,
                          (ip & 0x00ff0000) >> 16,
                          (ip & 0x0000ff00) >> 8,
                          (ip & 0x000000ff));
  return 0;
}
 
unsigned int getIp4MaskFromCidr(int cidr) {
  // use shift because pow trick only works with big endian: 2^cidr - 1
  return 4294967295 << (32-cidr);
}
 
unsigned int getIp4NtwAddr(unsigned int ip, unsigned int mask) {
  // eg. 10.10.10.10 & 255.255.0.0 = 10.10.0.0
  return ip & mask;
}
 
unsigned int getIp4BcastAddr (unsigned int ntwAddr, int cidr) {
  // eg. 0.0.0.255 | 10.10.10 = 10.10.10.255
  return (4294967295 >> cidr) | ntwAddr;
}

subnet.h
Spoiler(Show)
Code:
// subnet.h
// handle human readable ip as computer usable bit string
// creates big endian bit string (ignoring system architecture)
 
unsigned int ip4AddrArrToBits(int * ipArr);
int bitsToIp4AddrArr(unsigned int ipInt, int * ipArr);
int printIp4(int ip);
unsigned int getIp4MaskFromCidr(int cidr);
unsigned int getIp4NtwAddr(unsigned int ip, unsigned int mask);
unsigned int getIp4BcastAddr (unsigned int ntwAddr, int cidr);

It is pretty basic code, and you do some checking but you miss the validation for calls like sscanf(). Things like the CIDR checks should probably exist in some form in your subnet.h/c code too I'm thinking.