# VirusTotal Proxy v1.0 # Author: Mert SARICA # E-mail: mert [ . ] sarica [ @ ] gmail [ . ] com # URL: http://www.mertsarica.com from twisted.protocols import portforward from twisted.internet import reactor import getopt, sys import re import time import urllib import simplejson from cookielib import CookieJar import threading from threading import * import urlparse import urllib, urllib2 import os from datetime import datetime if sys.platform == 'win32': import winsound # Global Variables lport = 0 dhost = "" dport = 0 debug = False screenLock = Semaphore(value=1) debug = "" domains = [] alarm_level = 1 # Initialization reload(sys) sys.setdefaultencoding('iso-8859-9') opener = urllib2.build_opener(urllib2.HTTPHandler) urllib2.install_opener(opener) def cls(): if sys.platform == 'linux-i386' or sys.platform == 'linux2': os.system("clear") elif sys.platform == 'win32': os.system("cls") else: os.system("cls") def ctime(): if debug: print "--> ctime()" now = datetime.now() right_now = str(now.day) + "-" + str(now.month) + "-" + str(now.year) + " " + str(now.hour) + ":" + str(now.minute) + ":" + str(now.second) if debug: print "right_now", right_now print "<-- ctime()" return right_now def check_url(domain): url = "https://www.virustotal.com/en/url/submission/" token = "" positive = 0 total = 0 anurl = "" time.sleep(15) # We dont want to flood remote server. post_data_dictionary = {"url" : domain} http_headers = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0", "X-CSRFToken":"null", "Referer":"https://www.virustotal.com/en/"} post_data_encoded = urllib.urlencode(post_data_dictionary) request_object = urllib2.Request(url, post_data_encoded, http_headers) if debug: screenLock.acquire() print url, domain screenLock.release() f = opener.open(request_object) response = f.read() if debug: screenLock.acquire() print response screenLock.release() re1='("positives")' # Double Quote String 1 re2='(:)' # Any Single Character 1 re3='(.*?)' # Non-greedy match on filler re4='(,)' # Any Single Character 2 rg = re.compile(re1+re2+re3+re4,re.IGNORECASE|re.DOTALL) m = rg.search(response) if m: string1=m.group(1) c1=m.group(2) c2=m.group(3) c3=m.group(4) positive = c2 if debug: screenLock.acquire() print "Positive: " + positive + "\n" screenLock.release() re1='("last_analysis_date")' # Double Quote String 1 re2='(: ")' # Any Single Character 1 re3='(.*?)' # Non-greedy match on filler re4='(",)' # Any Single Character 2 rg = re.compile(re1+re2+re3+re4,re.IGNORECASE|re.DOTALL) m = rg.search(response) if m: string1=m.group(1) c1=m.group(2) c2=m.group(3) c3=m.group(4) ladate = c2 if debug: screenLock.acquire() print "Last Analysis Date: " + ladate + "\n" screenLock.release() a = datetime.strptime(ladate.split(" ")[0], "%Y-%m-%d") b = "{:%Y-%m-%d}".format(datetime.now()) b = datetime.strptime(b, "%Y-%m-%d") re1='("total")' # Double Quote String 1 re2='(:)' # Any Single Character 1 re3='(.*?)' # Non-greedy match on filler re4='(,)' # Any Single Character 2 rg = re.compile(re1+re2+re3+re4,re.IGNORECASE|re.DOTALL) m = rg.search(response) if m: string1=m.group(1) c1=m.group(2) c2=m.group(3) c3=m.group(4) total = c2 if debug: screenLock.acquire() print "Total: " + total + "\n" screenLock.release() re1='("reanalyse_url")' # Double Quote String 1 re2='(:)' # Any Single Character 1 re3='(.*?)' # Non-greedy match on filler re4='(})' # Any Single Character 2 rg = re.compile(re1+re2+re3+re4,re.IGNORECASE|re.DOTALL) m = rg.search(response) if m: string1=m.group(1) c1=m.group(2) c2=m.group(3) c3=m.group(4) anurl = c2 if a < b: opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0')] aurl = urlparse.urlparse(url).netloc + anurl.replace("\"", "") aurl = aurl.replace(" ", "") aurl = "https://" + aurl f = opener.open(aurl) if debug: screenLock.acquire() print "Submitting outdated URL:", aurl screenLock.release() return 1 if debug: screenLock.acquire() print "Report URL: " + anurl + "\n" print "----------------------" screenLock.release() if anurl: url = urlparse.urlparse(url).netloc + anurl.replace("\"", "") url = url.replace(" ", "") url = "https://" + url if debug: screenLock.acquire() print url screenLock.release() opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0')] f = opener.open(url) response = f.read() if debug: screenLock.acquire() print response screenLock.release() ltime = ctime() if m: screenLock.acquire() print "Date:", ltime, "Domain:", domain, "Detection Ratio:", positive + " / " + total, "Report URL:", url + "\n" screenLock.release() line = ltime + "|" + domain.strip()+"|"+ positive + " / " + total + "|" + url + "\n" if sys.platform == 'win32': if int(positive) >= int(alarm_level): winsound.Beep(700,1500) filename = "vtp.txt" FILE = open(filename,"a+") FILE.writelines(line) FILE.close() if debug: line = response + "\n" filename = "vtp_debug.txt" FILE = open(filename,"a+") FILE.writelines(line) FILE.close() return 0 return 1 def connect_vt(self, data): re1='(CONNECT)' # Word 1 re2='.*?' # Non-greedy match on filler re3='((?:[a-z][a-z\\.\\d\\-]+)\\.(?:[a-z][a-z\\-]+))(?![\\w\\.])' # Fully Qualified Domain Name 1 re4='.*?' # Non-greedy match on filler re5='(\\d+)' # Integer Number 1 re6='.*?' # Non-greedy match on filler re7='(HTTP)' # Word 2 domain="" rg = re.compile(re1+re2+re3+re4+re5+re6+re7,re.IGNORECASE|re.DOTALL) m = rg.search(data) if m: fqdn1=m.group(2) int1=m.group(3) if int1 == "443": domain = "https://" + fqdn1 screenLock.acquire() print "Connecting to:", domain screenLock.release() else: domain = "http://" + fqdn1 screenLock.acquire() print "Connecting to:", domain screenLock.release() else: re1='(GET|POST ) ' # Word 1 re2='((?:http|https)(?::\\/{2}[\\w]+)(?:[\\/|\\.]?)(?:[^\\s"]*))' # HTTP URL 1 re3='( HTTP/)' # Word 2 rg = re.compile(re1+re2+re3,re.IGNORECASE|re.DOTALL) m = rg.search(data) if m: httpurl1=m.group(2) domain = "http://" + urlparse.urlparse(httpurl1).netloc screenLock.acquire() print "Connecting to:", domain screenLock.release() for entry in domains: if entry.find(domain) < 0: if len(domains) >= 50: domains.pop(0) domains.append(domain) screenLock.acquire() print domain screenLock.release() else: return domains.append(domain) i = 1 while (i != 0): i = check_url(domain) def log_data(self, data): server_file = "log.txt" FILE = open(server_file, "a") FILE.write(data) FILE.close() def server_dataReceived(self, data): global debug t = Thread(target=connect_vt, args=(self,data)) t.start() if debug: log_data(self, data) screenLock.acquire() print "Client ------> server" print "%r" % data screenLock.release() portforward.Proxy.dataReceived(self, data) portforward.ProxyServer.dataReceived = server_dataReceived def vtproxy(): reactor.listenTCP(lport, portforward.ProxyFactory(dhost, dport)) reactor.run() def banner(): print "============================================" print u"VirusTotal Proxy [http://www.mertsarica.com]" print "============================================" print "Usage: python vtp.py -l <bind port> -r <proxy ip> -p <proxy port> -a <alarm level>\n" def main(): global debug global lport global dhost global dport global alarm_level try: opts, args = getopt.getopt(sys.argv[1:], "vl:r:p:a:") except getopt.GetoptError: banner() sys.exit(1) try: for o, a in opts: if o == "-l": lport = int(a) if o == "-r": dhost = a if o == "-p": dport = int(a) if o == "-v": debug = True if o == "-a": alarm_level = int(a) except: banner() sys.exit(1) if lport == 0 or dhost == "" or dport == 0: cls() banner() sys.exit(1) else: cls() print "============================================" print u"VirusTotal Proxy [http://www.mertsarica.com]" print "============================================" print "[+] Listening on port", lport vtproxy() if __name__ == "__main__": try: main() except KeyboardInterrupt: print "[+] Bye..." sys.exit(1)