#!/usr/bin/env python # -*- coding: cp1251 -*- """ todo for v.0.3: - ��������� proxy/socks """ import os import sys import time import signal import getopt import httplib import logging import fileinput import threading from urlparse import urlparse def usage(mess=''): print \ u"""wscan v.0.2 usage: wscan.py http[s]://site.com[:port] [-s] [-t] [-g] [-p "pattern1|pattern2|...|patternN"] [-f list.txt|...|listN.txt] [-l log.txt] [-h headers.txt] [-n 50] [-i 5] [-b "403|XXX"] �����: -t ����� ������������ -s ����� ������ ���������� -g ������������ GET-������� -f ����� � ������������/������� ��� ����������� �� ��������� list.txt ��� subdomains.txt -l ���-���� (scanlog.txt �� ���������) -n ����� ������� (50 �� ���������) -h ���� � ����������� ����������� -p ������� ��� ���������� �������� ������� ������� -i ����� ���������� ������������ ���������� ������� �������� ����� ��������� �������� ������� -b ������ ������� ������� ������� ������������ ������ � 404 """ sys.exit(mess) def head_scan(thrnum): while True: if interval<>0: time.sleep(interval) lock.acquire() try: path = listFH.readline().rstrip() except: print "[!] cant read from list" path = '' lock.release() if not len(path): return if path[0:1] == "/": path = path[1:] tryes = tryes_to_reconn while tryes: try: conn = Connect(url.netloc) conn.request(method, mypath+path, headers=headers) resp = conn.getresponse() print "[~] %s%s\t\t\t\r" % (mypath, path), break except: tryes-=1 time.sleep(sleep_reconn_time) conn.close() continue if not tryes: say("[!] Can't get response from "+url.netloc+mypath+path) conn.close() continue if str(resp.status) not in bad_status: if len(patterns): hdr = get_headers_str(resp.getheaders()) if method == "GET": html = resp.read(get_len) hdr += html try: for pattern in patterns: if not hdr.find(pattern)==-1: conn.close() raise except: continue if test_mode: hdr = get_headers_str(resp.getheaders()) say("[~] Test request: %s%s\n%s %s\n\n%s\n" \ % (url.netloc, mypath+path, resp.status, resp.reason, hdr)) if not len(patterns) and method=="GET": html = resp.read(get_len) say(html+"\n") say("[+] %s\t\t[%i] %s" % (mypath+path, resp.status, resp.reason)) conn.close() def subdomain_scan(thrnum): while True: if interval<>0: time.sleep(interval) lock.acquire() try: sd = listFH.readline().rstrip() except: print "[!] cant read from list" sd = '' lock.release() if not len(sd): return sd += "." try: conn = Connect(sd+url.netloc) print "[~] "+sd+url.netloc+"\t\t\t\r", except: continue try: conn.request(method, "/", headers=headers) resp = conn.getresponse() if str(resp.status) in bad_status: raise error except: conn.close() continue if len(patterns): hdr = get_headers_str(resp.getheaders()) if method == "GET": html = resp.read(get_len) hdr += html try: for pattern in patterns: if not hdr.find(pattern)==-1: conn.close() raise except: continue if test_mode: hdr = get_headers_str(resp.getheaders()) say("\n[~] Test request: %s%s\n%s %s\n\n%s\n" \ % (sd, url.netloc, resp.status, resp.reason, hdr)) if not len(pattern) and method=="GET": html = resp.read(get_len) say(html+"\n") say("[+] %s%s\t\t[%i] %s" % (sd, url.netloc, resp.status, resp.reason)) conn.close() def get_headers_str(data): hdr = "" for header, param in data: hdr += header+": "+param+"\n" return hdr def stop_signal(self, signum): say("[!] wscan was stoped\t\t\t\t\t\t") sys.exit(1) signal.signal(signal.SIGTERM, stop_signal) signal.signal(signal.SIGINT, stop_signal) # Defaults: list_files = ("list.txt", ) log_file = "scanlog.txt" threads_num = 50 bad_status = ('404',) tryes_to_reconn = 2 sleep_reconn_time = 2 get_len = 512 test_mode_bads = ("/", "sdfgsfgsd9834592/", "adsfsasf54343.php") test_mode_bads_sd = ("www", "sdfghdt9834592") patterns = () get_pattern = "" headers_file = "" headers = {} method = "HEAD" thread_func = head_scan test_mode = False interval = 0 try: url = urlparse(sys.argv[1]) if url.scheme == "http": Connect = httplib.HTTPConnection elif url.scheme == "https": Connect = httplib.HTTPSConnection else: raise error mypath = url.path if len(url.path) else "/" except: usage("[!] Error: wrong URL") try: opts, args = getopt.getopt(sys.argv[2:], "stf:l:n:h:p:gi:b:") except getopt.GetoptError, err: usage("[!] Error: "+str(err)) for opt, arg in opts: if opt == '-s': list_files = ("subdomains.txt", ) thread_func = subdomain_scan test_mode_bads = test_mode_bads_sd elif opt == '-f': list_files = arg.split('|') elif opt == '-l': log_file = arg elif opt == '-n': threads_num = int(arg) elif opt == '-t': test_mode = True threads_num = 1 elif opt == '-h': headers_file = arg elif opt == '-p': patterns = arg.split('|') elif opt == '-g': method = "GET" elif opt == '-i': interval = int(arg) threads_num = 1 elif opt == '-b': bad_status = bad_status + tuple(arg.split('|')) else: usage("[!] Error: wrong params") for file in list_files: try: FH = open(file).close() except: sys.exit("[!] Error: can't open "+file) listFH = fileinput.FileInput(list_files) if len(headers_file): try: headers = dict([line.rstrip().split(": ", 1) for line in open(headers_file) if len(line)>3]) except: sys.exit("[!] Error: can't work with "+headers_file) logging.basicConfig(level=logging.INFO, format='%(message)s', filename=log_file, filemode='w') console = logging.StreamHandler() console.setLevel(logging.INFO) logging.getLogger('').addHandler(console) say = logging.info if test_mode: listFH.close() try: listFH = open("test_mode_list.txt", 'w') except: sys.exit("[!] Error: can't open test_mode_list.txt") [listFH.write(bads+"\n") for bads in test_mode_bads] listFH.close() listFH = open("test_mode_list.txt", 'r') threads = [] lock = threading.Lock() for thrnum in xrange(threads_num): thread = threading.Thread(target=thread_func, name="thread %i" % thrnum, args=[thrnum]) thread.start() threads.append(thread) while threading.active_count()>1: time.sleep(5) print ' ' * 50, if test_mode: say("\n[~] End of test") # by cr0w # http://cr0w.wsec.ru