/* NST Simple HTTP Scanner v0.4 ChangeLog: v0.1 - Initial realease v0.2 - Security bugs fixed - Add some error handling - New feature: HTML report at the end of the scan - New feature: detection of directory listing - Default requests.txt improved v0.3 - Security bugs fixed - New feature: options handling - New feature: added some headers detection - New feature: support for proxy servers (HTTP Tunneling) - Default requests.txt improved v0.4 - Security bugs fixed - HTML Report improved - New feature: subdomains scanning - New feature: option -u for updates check - New feature: use of POSIX threads (the scanner is much more faster) - Default requests.txt improved Author: Paisterist Date: 2006-09-16 [N]eo [S]ecurity [T]eam - http://www.neosecurityteam.net [root@home shttpscanner]# gcc 0.4.c -o 0.4 -lpthread [root@home shttpscanner]# ./0.4 [!] NST Simple HTTP Scanner v0.4 by Paisterist - 2006/07/30 [!] [N]eo [S]ecurity [T]eam - http://www.neosecurityteam.net [+] Usage: ./0.4 -h host -d path -p port [+] Example: ./0.4 -h www.google.com -d / -p 80 -P 216.155.15.57:3128 -e [+] Options: ------------ -h: hostname. Example: www.google.com -p: port number to connect by (80 by default). -d: path ("/ by default"). Example: /web/ -e: use it for evading the responses used for not found errors. -P: proxy server and port. Example: 216.155.15.57:3128 -r: requests file (requests.txt by default) -m: scanning mode. O (by default) for get requests, 1 for scanning subdomains and 2 for both of them -s: subdomains file (subdomains.txt by default) -t: number of threads (64 by default). Must be between 0 and 1000 -u: use this option alone to check for updates. [root@home shttpscanner]# */ #include #include #include #include #include #ifdef WIN32 #pragma comment(lib, "ws2_32") #include #else #include #include #include #include #include #endif #define CURRENT_VERSION 0.4 #define HTML_CODE_SIZE 999999 #define RECEIVE_SIZE 9999 #define REQUEST_SIZE 1000 #define REQUESTS_FILE "requests.txt" #define SUBDOMAINS_FILE "subdomains.txt" #define MAX_REQUESTS 10000 #define URL_SIZE 100 #define THREADS 64 int Usage(char *argv[]); void Rights(void); char* GetBanner(char *hostname, int port, char *c_host, int c_port, struct sockaddr_in *host, int opt); char* Get404(char *hostname, int port, char *c_host, int c_port, struct sockaddr_in *host, char *dir); char* Get404Subdomain(char *hostname, int port, struct sockaddr_in host, struct hostent *h); int CheckPort(char *hostname, int port, struct sockaddr_in *host); int DirectoryListing(char *dir, char *rec, char *hostname, char *banner); void CRLF(char *string); char* stripSlash(char *string); char* stripWWW(char *string); char* time_format(time_t *begin, time_t *end); char* formatProxy(char *string, int ret); int invalidData(char *string, int limit); void Report_Header(char *host, char *html); int Report_Save(char *host, char *html); int Report_Add(char *dir, char *response, char *html, char *extra, int type, int s_type); int Report_Add_Details(int type, char *extra, char *html); void Report_Start(char *html, int type); void FATAL_ERROR(char *message); void *ThreadGETRoutine(void* r_data); void *ThreadSubdomainRoutine(void* r_data); int CheckUpdate(); int COLOR=0; int n_requests=0, n_subdomains=0; int n_total, n_total1; int n, n1; int rounds = 0; char *html; struct OPTIONS { char O_C_HOST[50]; int O_C_PORT; char O_PROXY_HOST[50]; int O_PROXY_PORT; char O_HOST[50]; char O_PATH[50]; char O_REQUESTS[50]; char O_HTML[50]; int O_PORT; int O_CHECK_UPDATE; int O_EVADING; int O_THREADS; int S_MODE; char O_SUBDOMAINS[50]; }; struct request_data { struct sockaddr_in host; char* request; char* subdomain; char* error_response; char* banner; }; struct OPTIONS o_handler; struct request_data *r_data; pthread_t *threads; int main(int argc, char *argv[]) { #ifdef WIN32 WSADATA ws; SOCKET sock; #else int sock; #endif time_t begin, begin1, begin2, end, end1, end2; char *requests[MAX_REQUESTS], *p; char *subdomains[MAX_REQUESTS]; char *banner; char *error_response; char *serror_response; char *nulo = NULL; int n_threads = 0; int error=0, count=0, i, lapso=0, arg_i; int pos; double div; struct sockaddr_in host; struct sockaddr_in remote; struct hostent *h; FILE *fp; #ifdef WIN32 WSAStartup(MAKEWORD(2, 2), &ws); #endif html = (char *) malloc(sizeof(char) * 999999); error_response = (char *) malloc(sizeof(char) * 4); serror_response = (char *) malloc(sizeof(char) * 4); time(&begin); if (argc<2) { Usage(argv); return 0; } o_handler.O_PORT = 80; o_handler.O_EVADING = 0; o_handler.O_CHECK_UPDATE = 0; for (arg_i = 1; arg_i < argc; arg_i++) { switch (argv[arg_i][0]) { case '-': { if (((int) argv[arg_i][1] >= 97 && (int) argv[arg_i][1] <= 122) || ((int) argv[arg_i][1] >= 65 && (int) argv[arg_i][1] <= 90)) { switch (argv[arg_i][1]) { case 'h': { if (strlen(o_handler.O_HOST)>0) { Usage(argv); return 0; } if (argv[arg_i + 1][0] == '-') { Usage(argv); return 0; } else { strncpy(o_handler.O_HOST, argv[arg_i + 1], sizeof(o_handler.O_HOST)); } } break; case 'p': { if (atoi(argv[arg_i + 1]) <=0 || atoi(argv[arg_i + 1]) >65535) FATAL_ERROR("[+] Invalid port number: it must be between 0 and 65535. Quiting...\n"); else { o_handler.O_PORT = atoi(argv[arg_i + 1]); } } break; case 'd': { if (strlen(o_handler.O_PATH) > 0) { Usage(argv); return 0; } if (strstr(argv[arg_i + 1], "/") != argv[arg_i + 1] || argv[arg_i + 1][strlen(argv[arg_i + 1])-1] != '/') { printf("[!] Invalid directory path: it must contain slashes. Quiting...\n"); return 0; } else strncpy(o_handler.O_PATH, argv[arg_i + 1], sizeof(o_handler.O_PATH)); } break; case 'r': { if (strlen(o_handler.O_REQUESTS) > 0 || argv[arg_i + 1][0] == '-') { Usage(argv); return 0; } strncpy(o_handler.O_REQUESTS, argv[arg_i + 1], sizeof(o_handler.O_REQUESTS)); } break; case 'e': { if (o_handler.O_EVADING != 0) { Usage(argv); return 0; } o_handler.O_EVADING = 1; } break; case 'P': { if (strlen(o_handler.O_PROXY_HOST) > 0 || !strstr(argv[arg_i + 1], ":") || strlen(argv[arg_i + 1]) < 10) { Usage(argv); return 0; } if (formatProxy(argv[arg_i + 1], 0) != NULL && formatProxy(argv[arg_i + 1], 1) != NULL) { strncpy(o_handler.O_PROXY_HOST, formatProxy(argv[arg_i + 1], 0), sizeof(o_handler.O_PROXY_HOST)); o_handler.O_PROXY_PORT = atoi(formatProxy(argv[arg_i + 1], 1)); } else { Usage(argv); return 0; } } break; case 'm': { if (atoi(argv[arg_i +1]) >= 0 && atoi(argv[arg_i + 1]) <= 2 && argv[arg_i + 1] && !o_handler.S_MODE) { o_handler.S_MODE = atoi(argv[arg_i + 1]); } else { Usage(argv); return 0; } } break; case 's': { if (strlen(o_handler.O_SUBDOMAINS) > 0 || argv[arg_i + 1][0] == '-') { Usage(argv); return 0; } strncpy(o_handler.O_SUBDOMAINS, argv[arg_i + 1], sizeof(o_handler.O_SUBDOMAINS)); } break; case 't': { if (atoi(argv[arg_i + 1]) <= 0 || atoi(argv[arg_i + 1]) > 1000 || o_handler.O_THREADS) { Usage(argv); return 0; } o_handler.O_THREADS = atoi(argv[arg_i + 1]); } break; case 'u': { if (o_handler.O_CHECK_UPDATE == 1) { Usage(argv); return 0; } o_handler.O_CHECK_UPDATE = 1; } break; default: { Usage(argv); return 0; } } } } } } if (o_handler.O_CHECK_UPDATE == 1) { CheckUpdate(); return 0; } if (!o_handler.O_HOST) Usage(argv); if (strlen(o_handler.O_PATH) <= 0) strcpy(o_handler.O_PATH, "/"); if (strlen(o_handler.O_REQUESTS) <= 0) strcpy(o_handler.O_REQUESTS, REQUESTS_FILE); if (strlen(o_handler.O_SUBDOMAINS) <= 0) strcpy(o_handler.O_SUBDOMAINS, SUBDOMAINS_FILE); if ((h = gethostbyname(o_handler.O_HOST)) == NULL) FATAL_ERROR("[!] Fatal error: unrecognized host. Quiting...\n"); if (!o_handler.S_MODE) o_handler.S_MODE = 0; if (!o_handler.O_THREADS) o_handler.O_THREADS = THREADS; threads = (pthread_t *) malloc(sizeof(pthread_t) * o_handler.O_THREADS); r_data = (struct request_data *) malloc(sizeof(struct request_data) * o_handler.O_THREADS); if (strlen(o_handler.O_PROXY_HOST) > 0 && o_handler.O_PROXY_PORT > 0) { if ((h = gethostbyname(o_handler.O_PROXY_HOST)) == NULL) FATAL_ERROR("[!] Fatal error: unrecognized proxy server. Quiting...\n"); host.sin_family=AF_INET; host.sin_port=htons((short) o_handler.O_PROXY_PORT); host.sin_addr.s_addr=inet_addr(o_handler.O_PROXY_HOST); memcpy(&host.sin_addr.s_addr, h->h_addr_list[0], h->h_length); strcpy(o_handler.O_C_HOST, o_handler.O_PROXY_HOST); o_handler.O_C_PORT = o_handler.O_PROXY_PORT; } else { strcpy(o_handler.O_C_HOST, o_handler.O_HOST); o_handler.O_C_PORT = o_handler.O_PORT; } host.sin_family=AF_INET; host.sin_port=htons((short) o_handler.O_C_PORT); host.sin_addr.s_addr=inet_addr(o_handler.O_C_HOST); memcpy(&host.sin_addr.s_addr, h->h_addr_list[0], h->h_length); CheckPort(o_handler.O_C_HOST, o_handler.O_C_PORT, &host); Report_Header(o_handler.O_HOST, html); Report_Add_Details(0, o_handler.O_HOST, html); banner = GetBanner(o_handler.O_HOST, o_handler.O_PORT, o_handler.O_C_HOST, o_handler.O_C_PORT, &host, 0); GetBanner(o_handler.O_HOST, o_handler.O_PORT, o_handler.O_C_HOST, o_handler.O_C_PORT, &host, 1); if (banner) Report_Add_Details(1, banner, html); error_response = Get404(o_handler.O_HOST, o_handler.O_PORT, o_handler.O_C_HOST, o_handler.O_C_PORT, &host, o_handler.O_PATH); serror_response = Get404Subdomain(o_handler.O_HOST, o_handler.O_PORT, host, h); Report_Add_Details(-1, error_response, html); Report_Add_Details(5, serror_response, html); printf("\n"); if (o_handler.S_MODE == 0 || o_handler.S_MODE == 2) { time(&begin1); fp=fopen(o_handler.O_REQUESTS, "r"); if (!fp) { printf("[!] Can't open %s for reading requests. Quiting...\n", o_handler.O_REQUESTS); return 0; } while (!feof(fp) && count0 && *requests[count] == '/') count++; else requests[count] = (char *) NULL; } if (count == 0) { printf("[!] No requests found at %s. Quiting...\n", o_handler.O_REQUESTS); return 0; } n = n_total = count; printf("[+] Starting GET scaning with %d requests...\n\n", count); count = 0; n_threads = 0; Report_Start(html, 0); while (requests[count]) { if (n_threads == o_handler.O_THREADS) { rounds++; n_threads = 0; pthread_join(threads[n_threads], NULL); } r_data[n_threads].request = requests[count]; r_data[n_threads].host = host; r_data[n_threads].error_response = error_response; r_data[n_threads].banner = banner; r_data[n_threads].subdomain = NULL; if (n_threads > 0 && rounds > 0) pthread_join(threads[n_threads], NULL); if (pthread_create(&threads[n_threads], NULL, &ThreadGETRoutine, (void *) &r_data[n_threads]) == -1) FATAL_ERROR("[!] Can't create thread. Quiting...\n"); count++; n_threads++; } count = 0; n_threads--; if (rounds == 0) n_threads = 0; while (n_threads < o_handler.O_THREADS) { pthread_join(threads[n_threads], NULL); n_threads++; } rounds = 0; n_threads = 0; n_requests = 0; time(&end1); } if (o_handler.S_MODE == 1 || o_handler.S_MODE == 2) { time(&begin2); count=0; strcpy(o_handler.O_HOST, stripWWW(o_handler.O_HOST)); fp=fopen(o_handler.O_SUBDOMAINS, "r"); if (!fp) { printf("[!] Can't open %s for reading subdomains. Quiting...\n", o_handler.O_SUBDOMAINS); return 0; } while (!feof(fp) && count0) count++; else subdomains[count] = (char *) NULL; } if (count == 0) { printf("[!] No subdomains found at %s. Quiting...\n", o_handler.O_SUBDOMAINS); return 0; } n1 = n_total1 = count; if (o_handler.S_MODE == 2) printf("\n"); printf("[+] Starting subdomain scaning with %d entries...\n\n", count); count = 0; Report_Start(html, 1); while (subdomains[count]) { if (n_threads == o_handler.O_THREADS) { rounds++; n_threads = 0; pthread_join(threads[n_threads], NULL); } if (n_threads > 0 && rounds > 0) pthread_join(threads[n_threads], NULL); r_data[n_threads].request = NULL; r_data[n_threads].host = host; r_data[n_threads].error_response = serror_response; r_data[n_threads].banner = banner; r_data[n_threads].subdomain = subdomains[count]; if (pthread_create(&threads[n_threads], NULL, &ThreadSubdomainRoutine, (void *) &r_data[n_threads]) == -1) { FATAL_ERROR("[!] Can't create thread. Quiting...\n"); } n_threads++; count++; } count = 0; n_threads--; if (rounds == 0) n_threads = 0; while (n_threads < n_total1) { pthread_join(threads[n_threads],NULL); n_threads++; } time(&end2); } time(&end); printf("\n"); if (o_handler.S_MODE == 0 || o_handler.S_MODE == 2) printf("[+] %d GET requests done, %d were successfull on %s. Leaving...\n", n_total, n, time_format(&begin1, &end1)); if (o_handler.S_MODE == 1 || o_handler.S_MODE ==2) printf("[+] %d subdomain requests done, %d were successfull on %s. Leaving...\n", n_total1, n1, time_format(&begin2, &end2)); printf("[+] Scan took %s.\n", time_format(&begin, &end)); #ifdef WIN32 WSACleanup(); #endif Report_Save(o_handler.O_HOST, html); return 0; } int Usage(char *argv[]) { Rights(); printf("[+] Usage: %s -h host -d path -p port\n" "[+] Example: %s -h www.google.com -d / -p 80 -P 216.155.15.57:3128 -e\n\n" "[+] Options:\n" "------------\n" "\t-h: hostname. Example: www.google.com\n" "\t-p: port number to connect by (80 by default).\n" "\t-d: path (\"/ by default\"). Example: /web/\n" "\t-e: use it for evading the responses used for not found errors.\n" "\t-P: proxy server and port. Example: 216.155.15.57:3128\n" "\t-r: requests file (%s by default)\n" "\t-m: scanning mode. O (by default) for get requests, 1 for scanning subdomains and 2 for both of them\n" "\t-s: subdomains file (%s by default)\n" "\t-t: number of threads (%d by default). Must be between 0 and 1000\n" "\t-u: use this option alone to check for updates.\n", argv[0], argv[0], REQUESTS_FILE, SUBDOMAINS_FILE, THREADS); return 0; } void Rights(void) { printf("[!] NST Simple HTTP Scanner v0.4 by Paisterist - 2006/07/30\n" "[!] [N]eo [S]ecurity [T]eam - http://www.neosecurityteam.net\n\n"); } char* GetBanner(char *hostname, int port, char *c_host, int c_port, struct sockaddr_in *host, int opt) { #ifdef WIN32 SOCKET sock; #else int sock; #endif char buffer[300]; char rec[RECEIVE_SIZE]; char *server; char powered[100]; char *p; int i, error; server = (char *) malloc(sizeof(char) * 200); sock = socket(AF_INET, SOCK_STREAM, 0); if (!sock) { printf("[!] Fatal error: failed to create the socket\n"); return NULL; } error=connect(sock, (const struct sockaddr*) host, sizeof(*host)); if (error != 0) { printf("[!] Fatal error: Can't connect to %s by port %d\n", c_host, c_port); return (char *) NULL; } if (opt != 0) { sprintf(buffer, "OPTIONS http://%s:%d/ HTTP/1.0\r\n" "User-agent: NST Bot Scanner\r\n" "Host: %s\r\n\r\n", hostname, port, hostname); send(sock, buffer, strlen(buffer), 0); recv(sock, rec, sizeof(rec), 0); if (!(p = strstr(rec, "Allow: " ))) return (char *) NULL; p += 7; i = 0; while ((int) *p != 13 && i<200) { server[i] = *p; i++; p++; } server[i] = '\0'; printf("[+] HTTP allowed methods: %s.\n", server); Report_Add_Details(4, server, html); #ifdef WIN32 closesocket(sock); #else shutdown(sock, SHUT_WR); close(sock); #endif return (char *) NULL; } sprintf(buffer,"GET http://%s:%d/ HTTP/1.1\r\n" "Connection: close\r\n" "User-agent: NST Bot Scanner\r\n" "Host: %s\r\n\r\n", hostname, port, c_host); send(sock, buffer, strlen(buffer), 0); recv(sock, rec, sizeof(rec), 0); if (!(p = strstr(rec, "Server: "))) { return (char *) NULL; } p += 8; i = 0; while ((int) *p != 13 && i<200) { server[i] = *p; i++; p++; } server[i] = '\0'; i = 0; printf("[+] Server header: %s. This header can be modified manually.\n", server); // ERROR EN WINDOWS CON ARGENTINA.COM if (p = strstr(rec, "X-Powered-By: ")) { p += 14; while ((int) *p != 13 && i<100) { powered[i] = *p; i++; p++; } powered[i] = '\0'; printf("[+] X-Powered-By header found: %s\n", powered); Report_Add_Details(2, powered, html); memset(powered, 0x00, strlen(powered)); i = 0; } if (p = strstr(rec, "X-AspNet-Version: ")) { p += 18; while ((int) *p != 13 && i<100) { powered[i] = *p; i++; p++; } powered[i] = '\0'; printf("[+] X-AspNet-Version header found: %s\n", powered); Report_Add_Details(3, powered, html); } #ifdef WIN32 closesocket(sock); #else shutdown(sock, SHUT_WR); close(sock); #endif return server; } char* Get404(char *hostname, int port, char *c_host, int c_port, struct sockaddr_in *host, char *dir) { #ifdef WIN32 SOCKET sock; #else int sock; #endif char buffer[150]; char *response; char rec[RECEIVE_SIZE]; int error; response = (char *) malloc(sizeof(char) * 4); sock = socket(AF_INET, SOCK_STREAM, 0); if (!sock) FATAL_ERROR("[!] Fatal error: failed to create the socket\n"); error=connect(sock, (const struct sockaddr*) host, sizeof(*host)); if (error != 0) { printf("[!] Fatal error: Can't connect to %s by port %d", c_host, c_port); exit(-1); } sprintf(buffer, "HEAD http://%s:%d%s404_NotFuND2.ex HTTP/1.1\r\n" "Proxy-Connection: close\r\n" "User-Agent: NST Bot Scanner\r\n" "Host: %s\r\n\r\n", hostname, port, dir, c_host); send(sock, buffer, strlen(buffer), 0); recv(sock, rec, sizeof(rec), 0); sprintf(response, "%c%c%c", rec[9], rec[10], rec[11]); if (strcmp(response, "404") == 0) { printf("[+] Server respond normally with 404 messages for not found errors.\n"); } else printf("[+] Server uses %s messages for not found errors. That can make the scan less precise, use -e for evading.\n", response); #ifdef WIN32 closesocket(sock); #else shutdown(sock, SHUT_WR); close(sock); #endif return response; } char* Get404Subdomain(char *hostname, int port, struct sockaddr_in host, struct hostent *h) { #ifdef WIN32 SOCKET sock; #else int sock; #endif char buffer[150]; char *response; char *subdomain; char rec[RECEIVE_SIZE]; int error; response = (char *) malloc(sizeof(char) * 4); subdomain = (char *) malloc((sizeof(char) * strlen(hostname)) + 20); sock = socket(AF_INET, SOCK_STREAM, 0); sprintf(subdomain, "n0tex4sistant.%s", stripWWW(hostname)); if (!sock) FATAL_ERROR("[!] Fatal error: failed to create the socket\n"); host.sin_addr.s_addr=inet_addr(subdomain); if ((h = gethostbyname(subdomain)) != NULL) memcpy(&host.sin_addr.s_addr, h->h_addr_list[0], h->h_length); error=connect(sock, (const struct sockaddr*) &host, sizeof(host)); if (error != 0) { printf("[+] Server uses normal response for non existant subdomains.\n"); return (char *) NULL; } sprintf(buffer, "HEAD http://%s:%d HTTP/1.1\r\n" "Proxy-Connection: close\r\n" "User-Agent: NST Bot Scanner\r\n" "Host: %s:%d\r\n\r\n", subdomain, port, subdomain, port); send(sock, buffer, strlen(buffer), 0); recv(sock, rec, sizeof(rec), 0); sprintf(response, "%c%c%c", rec[9], rec[10], rec[11]); printf("[+] Server uses %s messages for not found subdomains. That can make the scan less precise.\n", response); #ifdef WIN32 closesocket(sock); #else shutdown(sock, SHUT_WR); close(sock); #endif return response; } int CheckPort(char *hostname, int port, struct sockaddr_in *host) { #ifdef WIN32 SOCKET sock; #else int sock; #endif int error; int FATAL=0; char buffer[200]; char rec[5]; sock = socket(AF_INET, SOCK_STREAM, 0); if (!sock) { printf("[!] Fatal error: failed to create the socket\n"); return 0; } error=connect(sock, (const struct sockaddr*) host, sizeof(*host)); if (error != 0) { printf("[!] Fatal error: Can't connect to %s by port %d. Quiting...\n", hostname, port); FATAL=1; } sprintf(buffer, "GET / HTTP/1.0\r\n" "User-agent: NST Bot Scanner\r\n" "Host: %s\r\n\r\n", hostname); send(sock, buffer, strlen(buffer), 0); recv(sock, rec, sizeof(rec), 0); if (strlen(rec) == 0 || invalidData(rec, sizeof(rec)) == -1) { printf("[!] Fatal error: Can't receive data from %s by port %d. Quiting...\n", hostname, port); FATAL=1; } #ifdef WIN32 closesocket(sock); #else shutdown(sock, SHUT_WR); close(sock); #endif if (FATAL == 1) exit(0); return 0; } void CRLF(char *string) { int i=0; for (i=0; i= 60) { m = lapso / 60; s = lapso % 60; if (s == 0) sprintf(format, "%d minutes", m); else sprintf(format, "%d minutes and %d seconds", m, s); } else sprintf(format, "%d seconds", lapso); return format; } int DirectoryListing(char *dir, char *rec, char *hostname, char *banner) { char *serverAt; serverAt = (char *) malloc (sizeof(char) * (strlen(hostname) + strlen(banner) + 20)); strcpy(serverAt, banner); strcat(serverAt, " Server at "); strcat(serverAt, hostname); if (dir[strlen(dir) - 1] != '/' || banner == NULL) return 0; if (strstr(rec, "Index of") != NULL) return 1; if (strstr(rec, serverAt) != NULL) return 1; return 0; } void Report_Header(char *host, char *html) { sprintf(html, "\n" "\n" "Simple HTTP Scanner - Scan report for %s\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n", host, host); } int Report_Save(char *host, char *html) { FILE *fp; char *filename; filename = (char *) malloc(sizeof(char) * ( strlen(host) + 15 )); sprintf(filename, "report-%s.html", host); strcat(html, "
Scan report for %s
Server details


\n" "\n" "\n" "\n" "\n" "
Simple HTTP Scanner v0.4 by Paisterist
" "Neo Security Team © 2004 - 2006 || http://www.neosecurityteam.net
\n" "\n" "\n"); fp = fopen(filename, "w"); if (!fp) { printf("[+] Unknown error: the report couldn't be written. Please check the directory permissions.\n"); return 0; } fwrite(html, sizeof(char), strlen(html), fp); fclose(fp); printf("[+] Report saved successfully at %s.\n\n", filename); return 0; } int Report_Add(char *dir, char *response, char *html, char *extra, int type, int s_type) { char message[200]; char cat[1000]; char color[8]; char url[100]; if (COLOR == 0) { COLOR = 1; strcpy(color, "#CCCCCC"); } else { COLOR = 0; strcpy(color, "#FFFFFF"); } switch (type) { case 0: sprintf(message, "Content-Location header was detected. The source has taken from %s.", extra); break; case 1: sprintf(message, "Location header was detected. The web server redirects to %s.", extra); break; case 2: sprintf(message, "The web server allows you to see the content of directories without a index document. Check it out."); break; case 3: sprintf(message, "The requested document requires a web based authentication, there is a restricted area."); break; case 4: sprintf(message, "The requested document is forbidden. Maybe there is some confidential or sensitive information in there."); break; default: sprintf(message, "Normal response received, the document exists. You should take a look."); break; } if (s_type == 0) sprintf(url, "%s%s", o_handler.O_PATH, stripSlash(dir)); else sprintf(url, "http://%s", dir); sprintf(cat, "\n" "%s\n" "%s\n" "%s\n" "\n", color, url, response, message); strncat(html, cat, sizeof(cat)); return 0; } int Report_Add_Details(int type, char *extra, char *html) { char message[200]; char detail[30]; char color[8]; char *ret; if (COLOR == 0) { COLOR = 1; strcpy(color, "#CCCCCC"); } else { COLOR = 0; strcpy(color, "#FFFFFF"); } switch (type) { case 0: { sprintf(detail, "Hostname: "); strcpy(message, extra); } break; case 1: { sprintf(detail, "Server information: "); strcpy(message, extra); } break; case 2: { sprintf(detail, "X-Powered-By: "); strcpy(message, extra); } break; case 3: { sprintf(detail, "X-AspNet-Version: "); strcpy(message, extra); } break; case 4: { sprintf(detail, "HTTP allowed methods: "); strcpy(message, extra); } break; case 5: { sprintf(detail, "Not found subdomain errors: "); if (extra != NULL) sprintf(message, "The web server use %s messages for not found subdomains.", extra); else strcpy(message, "The web servers respond normally to not found subdomains."); } break; default: { sprintf(detail, "Not found errors: "); if (strcmp(extra, "404") != 0) sprintf(message, "The web server use %s messages for not found errors. This can make the scan less precise.", extra); else sprintf(message, "The web server use %s messages for not found errors. This is normal.", extra); } break; } ret = (char *) malloc(sizeof(char) * ((strlen(message) + strlen(detail)) + 100)); sprintf(ret, "\n" "%s\n" "%s\n" "\n", color, detail, message); strcat(html, ret); return 0; } void Report_Start(char *html, int type) { COLOR = 0; char mode[30]; char cat[210]; char request[10]; if (type == 0) { strcpy(mode, "GET scanning"); strcpy(request, "Path"); } else { strcpy(mode, "Subdomain scanning"); strcpy(request, "Domain"); } sprintf(cat, "\n" "%s\n" "\n" "\n" "%s\n" "Response\n" "Comments\n" "\n", mode, request); strcat(html, cat); } void FATAL_ERROR(char *message) { printf("%s", message); fflush(stdout); exit(-1); } char* formatProxy(char *string, int ret) { char *p; char *port = (char *) malloc(sizeof(char) * 6); char *host = (char *) malloc(sizeof(char) * strlen(string)); int pos, count=0; if ((p = strstr(string, ":")) == NULL) return (char *) NULL; for (pos = 0; pos < (p - string); pos++) { host[pos] = string[pos]; } host[pos]='\0'; p++; while (*p != '\0' && count < 5) { port[count] = *p; count++; p++; } port[count] = '\0'; if (atoi(port) <= 0 || atoi(port) >= 65536) { return (char *) NULL; } return ret == 1 ? port : host; } int invalidData(char *string, int limit) { int i, len = strlen(string); for (i = 0; i < limit; i++) if ((int) string[i] < 32) return -1; return 0; } char* stripWWW(char *string) { int i; char *ret = (char *) malloc(sizeof(char) * strlen(string)); if (strstr(string, "www.") == string) { for (i=4; i < strlen(string); i++) { ret[i-4] = string[i]; } ret[i-4]='\0'; return ret; } return string; } void *ThreadGETRoutine(void* r_data) { #ifdef WIN32 SOCKET sock; #else int sock; #endif struct request_data *data; char url[URL_SIZE]; char response[3]; char rec[RECEIVE_SIZE]; char request[REQUEST_SIZE]; char *request_s; char *error_response; char *banner; char *p; int error, size, i; float div, porcentaje; data = (struct request_data *) r_data; request_s = data->request; error_response = data->error_response; banner = data->banner; sock = socket(AF_INET, SOCK_STREAM, 0); if (!sock) { printf("[!] Fatal error: failed to create the socket. Quiting...\n"); n--; return 0; } error = connect(sock, (const struct sockaddr*) &data->host, sizeof(data->host)); if (error != 0) { printf("[!] Unknown error: Can't connect to %s by port %d. Quiting...\n", o_handler.O_C_HOST, o_handler.O_C_PORT); n--; return 0; } sprintf(request, "GET http://%s:%d%s%s HTTP/1.0\r\n" "Connection: Keep-Alive\r\n" "User-Agent: NST Bot Scanner\r\n" "Host: %s\r\n\r\n", o_handler.O_HOST, o_handler.O_PORT, o_handler.O_PATH, stripSlash(request_s), o_handler.O_C_HOST); size=sizeof(struct sockaddr); send(sock, request, sizeof(request), 0); recv(sock, rec, sizeof(rec), 0); n_requests++; div = (float) (n_requests) / n_total; porcentaje = (float) (div * 100); sprintf(response, "%c%c%c", rec[9], rec[10], rec[11]); response[3] = '\0'; if (strcmp(response, error_response) != 0 || (strcmp(response, error_response) == 0 && o_handler.O_EVADING == 0)) { if (strcmp("200", response) == 0) { if (p = strstr(rec, "Content-Location: ")) { p += 18; i = 0; while (*p != (int) 13 && *p != 32 && isubdomain; serror_response = data->error_response; banner = data->banner; strcpy(subdomain, r_subdomain); strcat(subdomain, "."); strcat(subdomain, o_handler.O_HOST); if (serror_response == NULL) { serror_response = (char *) malloc(sizeof(char) * 4); // This way strcmp() don't crash } if (strcmp(o_handler.O_C_HOST, o_handler.O_PROXY_HOST) != 0) { strcpy(o_handler.O_C_HOST, subdomain); data->host.sin_addr.s_addr=inet_addr(o_handler.O_C_HOST); if ((h = gethostbyname(o_handler.O_C_HOST)) != NULL) memcpy(&data->host.sin_addr.s_addr, h->h_addr_list[0], h->h_length); } sock = socket(AF_INET, SOCK_STREAM, 0); if (!sock) { printf("[!] Fatal error: failed to create the socket. Quiting...\n"); n1--; return NULL; } error=connect(sock, (const struct sockaddr*) &data->host, sizeof(data->host)); if (error == 0 && h != NULL) { sprintf(request, "GET http://%s/ HTTP/1.0\r\n" "Connection: Keep-Alive\r\n" "User-Agent: NST Bot Scanner\r\n" "Host: %s\r\n\r\n", subdomain, o_handler.O_C_HOST); size=sizeof(struct sockaddr); send(sock, request, sizeof(request), 0); recv(sock, rec, sizeof(rec), 0); sprintf(response, "%c%c%c", rec[9], rec[10], rec[11]); if (strcmp(response, serror_response) != 0 || (strcmp(response, serror_response) == 0 && o_handler.O_EVADING == 0)) { if (strcmp("200", response) == 0) { if (p = strstr(rec, "Content-Location: ")) { p += 18; i = 0; while (*p != (int) 13 && ih_addr_list[0], h->h_length); error = connect(sock, (const struct sockaddr*) &host, sizeof(struct sockaddr)); if (error != 0) { printf("[!] Can't connect to shttpscanner.sourceforge.net by port 80 for retrieving updates.\n", o_handler.O_C_HOST, o_handler.O_C_PORT); return -1; } strcpy(buffer, "GET /updates.csv HTTP/1.1\r\n" "User-agent: NST Bot Updater\r\n" "Host: shttpscanner.sourceforge.net\r\n\r\n"); send(sock, buffer, strlen(buffer), 0); recv(sock, rec, sizeof(rec), 0); sprintf(response, "%c%c%c", rec[9], rec[10], rec[11]); if (strcmp(response, "200") != 0) { printf("[!] Can't find updates.csv on shttpscanner.sourceforge.net\n"); return -1; } i = strlen(rec); while (i >= 0) { if ((int) rec[i] == 10) { if (t_count == 0) t_count++; else { pos = i + 1; i = 0; } } i--; } update = (char *) malloc(sizeof(char) * (strlen(rec) - pos) + 3); //printf("%d", (strlen(rec) - pos)); for (i = 0; rec[pos + i] != (char) NULL && (int) rec[pos + i] != 10; i++) update[i] = rec[pos + i]; update[i] = '\0'; p = strstr(update, ","); i = 0; version = (char *) malloc((sizeof(char) * (p - update)) + 10); while (i < (p - update)) { version[i] = update[i]; i++; } version[i] = '\0'; p++; i = 0; p1 = strstr(p, ","); date = (char *) malloc((sizeof(char) * (p1 - p)) + 10); while (i < (p1 - p)) { date[i] = update[i + (p - update)]; i++; } date[i] = '\0'; p1++; url = (char *) malloc((sizeof(char) * (strlen(update) - (p1 - update))) + 10); i = 0; while ((int) *p1 != 0 && (int) *p1 != 10) { url[i] = *p1; i++; p1++; } url[i] = '\0'; if (atof(version) > CURRENT_VERSION) printf("[+] The %s version was released on %s. You can download it on %s.\n", version, date, url); else printf("[+] There isn't a new version of NST Simple HTTP Scanner available.\n"); #ifdef WIN32 closesocket(sock); #else shutdown(sock, SHUT_WR); close(sock); #endif return 0; }