|
@@ -1,21 +1,21 @@
|
|
|
-
|
|
|
+
|
|
|
|
|
|
"""
|
|
|
-PyDog4Apache - 2015 - by psy (epsylon@riseup.net)
|
|
|
+PyDog4Apache - 2016/2020 - by psy (epsylon@riseup.net)
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
|
with PyDog4Apache; if not, write to the Free Software Foundation, Inc., 51
|
|
|
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
"""
|
|
|
-from options import PyDog4ApacheOptions
|
|
|
-from update import Updater
|
|
|
import os, traceback, sys, re, gzip, datetime, string, stat
|
|
|
+from .options import PyDog4ApacheOptions
|
|
|
+from .update import Updater
|
|
|
|
|
|
try:
|
|
|
from ipwhois import IPWhois
|
|
|
except:
|
|
|
- print "\n[Warning] - Error importing: ipwhois lib. \n\n On Debian based systems:\n\n $ sudo apt-get install python-pip && sudo pip install ipwhois\n"
|
|
|
- print "[Source] - Pypi-ipwhois: https://pypi.python.org/pypi/ipwhois/\n"
|
|
|
+ print("\n[Warning] - Error importing: ipwhois lib. \n\n On Debian based systems:\n\n $ sudo apt-get install python3-pip && sudo pip3 install ipwhois\n")
|
|
|
+ print("[Source] - Pypi-ipwhois: https://pypi.python.org/pypi/ipwhois/\n")
|
|
|
sys.exit(2)
|
|
|
|
|
|
DEBUG = 0
|
|
@@ -36,15 +36,15 @@ class PyDog4Apache(object):
|
|
|
return self.options
|
|
|
|
|
|
def banner(self):
|
|
|
- print '='*75, "\n"
|
|
|
- print " ____ ____ _ _ _ _ "
|
|
|
- print "| _ \ _ _| _ \ ___ __ _| || | / \ _ __ __ _ ___| |__ ___ "
|
|
|
- print "| |_) | | | | | | |/ _ \ / _` | || |_ / _ \ | '_ \ / _` |/ __| '_ \ / _ |"
|
|
|
- print "| __/| |_| | |_| | (_) | (_| |__ _/ ___ \| |_) | (_| | (__| | | | __/"
|
|
|
- print "|_| \__, |____/ \___/ \__, | |_|/_/ \_\ .__/ \__,_|\___|_| |_|\___|"
|
|
|
- print " |___/ |___/ |_| "
|
|
|
- print self.optionParser.description, "\n"
|
|
|
- print '='*75
|
|
|
+ print('='*75, "\n")
|
|
|
+ print(" ____ ____ _ _ _ _ ")
|
|
|
+ print("| _ \ _ _| _ \ ___ __ _| || | / \ _ __ __ _ ___| |__ ___ ")
|
|
|
+ print("| |_) | | | | | | |/ _ \ / _` | || |_ / _ \ | '_ \ / _` |/ __| '_ \ / _ |")
|
|
|
+ print("| __/| |_| | |_| | (_) | (_| |__ _/ ___ \| |_) | (_| | (__| | | | __/")
|
|
|
+ print("|_| \__, |____/ \___/ \__, | |_|/_/ \_\ .__/ \__,_|\___|_| |_|\___|")
|
|
|
+ print(" |___/ |___/ |_| ")
|
|
|
+ print(self.optionParser.description, "\n")
|
|
|
+ print('='*75)
|
|
|
|
|
|
def try_running(self, func, error, args=None):
|
|
|
options = self.options
|
|
@@ -52,14 +52,13 @@ class PyDog4Apache(object):
|
|
|
try:
|
|
|
return func(*args)
|
|
|
except Exception as e:
|
|
|
- print(error, "error")
|
|
|
- if DEBUG:
|
|
|
+ print((error, "error"))
|
|
|
+ if DEBUG != 0:
|
|
|
traceback.print_exc()
|
|
|
|
|
|
def check_root(self):
|
|
|
if not os.geteuid()==0:
|
|
|
- print "[Error] - Some of your 'sources' need more rights to be accessed."
|
|
|
- sys.exit("\n[Info] - Try to launch it as root (ex: 'sudo ./pydog4apache')\n")
|
|
|
+ sys.exit("[Info] You need to launch it as root (ex: 'sudo python3 pydog4apache')...\n")
|
|
|
|
|
|
def is_readable(self, folder):
|
|
|
try:
|
|
@@ -73,9 +72,9 @@ class PyDog4Apache(object):
|
|
|
for folder in logs:
|
|
|
root = self.is_readable(folder)
|
|
|
if root == None:
|
|
|
- print "[Error] - This source:", folder, "is not valid!. Passing..."
|
|
|
+ print("\n[Error] This source: [", folder, "] is not valid... [Passing!]")
|
|
|
if root is 0:
|
|
|
- check_perms = self.try_running(self.check_root, "\nInternal error checking root permissions.")
|
|
|
+ check_perms = self.try_running(self.check_root, "\n[Error] Internal error checking root permissions.")
|
|
|
|
|
|
def extract_logs(self):
|
|
|
try:
|
|
@@ -84,26 +83,24 @@ class PyDog4Apache(object):
|
|
|
logs = [ log.replace('\n','') for log in logs ]
|
|
|
f.close()
|
|
|
if not logs:
|
|
|
- print "\n[Error] - Imposible to retrieve 'sources' from file.\n"
|
|
|
+ print("\n[Error] Imposible to retrieve 'sources' from file... [Aborting!]\n")
|
|
|
return
|
|
|
else:
|
|
|
return logs
|
|
|
except:
|
|
|
if os.path.exists('sources.txt') == True:
|
|
|
- print '\n[Error] - Cannot open:', 'sources.txt', "\n"
|
|
|
+ print('\n[Error] Cannot open:', 'sources.txt', "[Aborting!]\n")
|
|
|
sys.exit(2)
|
|
|
else:
|
|
|
- print '\n[Error] - Cannot found:', 'sources.txt', "\n"
|
|
|
+ print('\n[Error] Cannot found:', 'sources.txt', "[Aborting!]\n")
|
|
|
sys.exit(2)
|
|
|
|
|
|
def extract_whois(self, ip):
|
|
|
try:
|
|
|
if re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', ip):
|
|
|
w = IPWhois(ip, timeout=5)
|
|
|
- res = w.lookup_whois(retry_count=2)
|
|
|
+ res = w.lookup(retry_count=2)
|
|
|
descr = res["nets"][0]['description']
|
|
|
- if self.options.verbose:
|
|
|
- print"[Verbose] - Resolving:", ip
|
|
|
else:
|
|
|
descr = None
|
|
|
except:
|
|
@@ -121,6 +118,7 @@ class PyDog4Apache(object):
|
|
|
def check_visitants(self, descr):
|
|
|
try:
|
|
|
for v in self.keys:
|
|
|
+ v = v.rstrip()
|
|
|
if v.lower() in descr.lower():
|
|
|
key = v.lower()
|
|
|
return key
|
|
@@ -130,7 +128,7 @@ class PyDog4Apache(object):
|
|
|
if os.path.exists('keywords.txt') == True:
|
|
|
return
|
|
|
else:
|
|
|
- print '\n[Error] - Cannot found:', 'keywords.txt', "\n"
|
|
|
+ print('\n[Error] Cannot found:', 'keywords.txt', "[Aborting!]\n")
|
|
|
return
|
|
|
|
|
|
def run(self, opts=None):
|
|
@@ -139,24 +137,20 @@ class PyDog4Apache(object):
|
|
|
self.set_options(options)
|
|
|
options = self.options
|
|
|
self.banner()
|
|
|
- if options.update:
|
|
|
- try:
|
|
|
- print("\n[Info] - Trying to update automatically to the latest stable version.\n")
|
|
|
- Updater()
|
|
|
- except:
|
|
|
- print("\nSomething was wrong!. You should clone PyDog2Apache manually with:\n")
|
|
|
- print("$ git clone https://github.com/epsylon/pydog2apache\n")
|
|
|
- sys.exit(2)
|
|
|
- print "\n[Info] - Sending dogs to sniff logs... Please wait!\n"
|
|
|
- print "-"*22
|
|
|
+ if options.update:
|
|
|
+ print("\n[Info] Trying to update automatically to the latest stable version...\n")
|
|
|
+ Updater()
|
|
|
+ sys.exit()
|
|
|
+ print("\n[Info] Sending 'dogs' to sniff 'logs'... [Waiting!]")
|
|
|
+ if self.options.verbose:
|
|
|
+ print("\n"+"="*40+"\n")
|
|
|
logs = self.try_running(self.extract_logs, "\nInternal error extracting logs.")
|
|
|
access = self.check_access(logs)
|
|
|
f = open('keywords.txt')
|
|
|
self.keys = f.readlines()
|
|
|
- self.keys = [ self.key.replace('\n','') for self.key in self.keys ]
|
|
|
f.close()
|
|
|
if not self.keys:
|
|
|
- print "\n[Error] - Imposible to retrieve 'visitants' from file.\n"
|
|
|
+ print("\n[Error] Imposible to retrieve 'visitants' from file... [Aborting!]\n")
|
|
|
return
|
|
|
for folder in logs:
|
|
|
if not folder.endswith('/'):
|
|
@@ -165,69 +159,82 @@ class PyDog4Apache(object):
|
|
|
listing = os.listdir(folder)
|
|
|
for log in listing:
|
|
|
if self.options.verbose:
|
|
|
- print "[Verbose] - Analyzing:", folder+log
|
|
|
+ print("[Info] Analyzing:", folder+log)
|
|
|
if log.endswith('.gz'):
|
|
|
- with gzip.open(folder+log, 'rb') as f:
|
|
|
+ with gzip.open(folder+log, 'r') as f:
|
|
|
dog_sniff = f.readlines()
|
|
|
+ dog_sniff = [ dog_sniff[0].decode() for sniff in dog_sniff ]
|
|
|
else:
|
|
|
try:
|
|
|
f = open(folder+log)
|
|
|
+ dog_sniff = f.readlines()
|
|
|
except:
|
|
|
return
|
|
|
- dog_sniff = f.readlines()
|
|
|
- sep = '-'
|
|
|
- sep2= '['
|
|
|
- for record in dog_sniff:
|
|
|
- ip = record.split(sep, 1)[0]
|
|
|
- ip = ''.join(ip.split())
|
|
|
- ip_found = self.is_valid_ip(ip)
|
|
|
- if ip_found is True:
|
|
|
- date = [record.split(']')[0] for p in record.split('[') if ']' in p]
|
|
|
- for d in date:
|
|
|
- date_visit = d.split(sep2, 1)[1]
|
|
|
- descr = self.extract_whois(ip)
|
|
|
- if descr is not None:
|
|
|
- key = self.check_visitants(descr)
|
|
|
- if key:
|
|
|
- self.visitants[str(ip)] = "[" + str(key.upper()) + "]" + "|" + str(str(descr) + "|" + str(date_visit) + "|" + str(folder+log))
|
|
|
+ if dog_sniff:
|
|
|
+ sep = '-'
|
|
|
+ sep2= '['
|
|
|
+ for record in dog_sniff:
|
|
|
+ ip = record.split(sep, 1)[0]
|
|
|
+ ip = ''.join(ip.split())
|
|
|
+ ip_found = self.is_valid_ip(ip)
|
|
|
+ if ip_found is True:
|
|
|
+ if self.options.verbose:
|
|
|
+ print(" |-> IP Found:", ip)
|
|
|
+ date = [record.split(']')[0] for p in record.split('[') if ']' in p]
|
|
|
+ for d in date:
|
|
|
+ date_visit = d.split(sep2, 1)[1]
|
|
|
+ descr = self.extract_whois(ip)
|
|
|
+ if descr is not None:
|
|
|
+ key = self.check_visitants(descr)
|
|
|
+ if key:
|
|
|
+ self.visitants[str(ip)] = "[ " + str(key.upper()) + " ]" + " | " + str(str(descr) + " | " + str(date_visit) + " | " + str(folder+log))
|
|
|
f.close()
|
|
|
except:
|
|
|
pass
|
|
|
- if self.options.verbose:
|
|
|
- print "-"*22
|
|
|
+ print("\n"+"="*40+"\n")
|
|
|
if self.options.file:
|
|
|
namefile = str(self.options.file)
|
|
|
self.report = open(namefile, 'w')
|
|
|
- self.report.write("# Apache web logs sneaker - GPLv3 - by psy\n")
|
|
|
- self.report.write("# Project: https://github.com/epsylon/pydog4apache - 03c8.net\n")
|
|
|
+ self.report.write("# Apache web logs sneaker - 2016/2020 - by psy (https://03c8.net)\n")
|
|
|
+ self.report.write("# Project: https://code.03c8.net/epsylon/pydog4apache\n")
|
|
|
self.report.write("# Reported at: " + str(datetime.datetime.now()) + "\n\n")
|
|
|
- for key,val in self.visitants.items():
|
|
|
- print("{} -> {}".format(key, val))
|
|
|
- print "-"*12
|
|
|
- if self.options.file:
|
|
|
+ for key,val in list(self.visitants.items()):
|
|
|
+ print(("{} -> {}".format(key, val))+"\n")
|
|
|
+ if self.options.file:
|
|
|
+ self.report.write("Logs Analyzed:\n\n")
|
|
|
+ for log in listing:
|
|
|
+ self.report.write(" -"+log+"\n")
|
|
|
+ self.report.write("\nResults:\n\n")
|
|
|
self.report.write(key + " -> " + val + "\n")
|
|
|
- self.report.write("-"*12 + "\n")
|
|
|
- if not self.visitants.items():
|
|
|
- print "[Info] - Not any 'keyword' found on your 'visitants'.\n"
|
|
|
+ if not list(self.visitants.items()):
|
|
|
+ print("[Info] Not any 'keyword' found on your 'visitants'... [Exiting!]\n")
|
|
|
if self.options.file:
|
|
|
- self.report.write("Not any 'keyword' found on your 'visitants'.\n")
|
|
|
+ self.report.write("Logs Analyzed:\n\n")
|
|
|
+ for log in listing:
|
|
|
+ self.report.write(" -"+log+"\n")
|
|
|
+ self.report.write("\nResults:\n\n")
|
|
|
+ self.report.write(" -Not any 'keyword' found on your 'visitants'...\n")
|
|
|
if self.options.file:
|
|
|
self.report.close()
|
|
|
if self.options.emails:
|
|
|
+ print("-"*22+"\n")
|
|
|
import smtplib, socket
|
|
|
from email.mime.text import MIMEText
|
|
|
self.notify = open('tempmail', 'w')
|
|
|
- self.notify.write("# Apache web logs sneaker - GPLv3 - by psy\n")
|
|
|
- self.notify.write("# Project: https://github.com/epsylon/pydog4apache - 03c8.net\n")
|
|
|
+ self.notify.write("# Apache web logs sneaker - 2016/2020 - by psy (https://03c8.net)\n")
|
|
|
+ self.notify.write("# Project: https://code.03c8.net/epsylon/pydog4apache\n")
|
|
|
self.notify.write("# Reported at: " + str(datetime.datetime.now()) + "\n\n")
|
|
|
- for key,val in self.visitants.items():
|
|
|
+ self.notify.write("Logs Analyzed:\n\n")
|
|
|
+ for log in listing:
|
|
|
+ self.notify.write(" -"+log+"\n")
|
|
|
+ self.notify.write("\nResults:\n\n")
|
|
|
+ for key,val in list(self.visitants.items()):
|
|
|
self.notify.write(key + " -> " + val + "\n")
|
|
|
- self.notify.write("-"*12 + "\n")
|
|
|
- if not self.visitants.items():
|
|
|
- self.notify.write("Not any 'keyword' found on your 'visitants'.\n")
|
|
|
+ if not list(self.visitants.items()):
|
|
|
+ self.notify.write("Not any 'keyword' found on your 'visitants'...\n")
|
|
|
self.notify.close()
|
|
|
self.notify = open('tempmail', 'rb')
|
|
|
- msg = MIMEText(self.notify.read())
|
|
|
+ msg = MIMEText(self.notify.read().decode('utf-8'))
|
|
|
self.notify.close()
|
|
|
doggy = 'pydog4apache@'+str(socket.gethostname())
|
|
|
herd = self.options.emails
|
|
@@ -241,7 +248,7 @@ class PyDog4Apache(object):
|
|
|
s.sendmail(doggy, herd, msg.as_string())
|
|
|
s.quit()
|
|
|
except:
|
|
|
- print "[Error] - Not any SMTP server running on: '"+str(socket.gethostname())+"'. Aborting email report...\n"
|
|
|
+ print("[Error] Not any SMTP (email) server running on: '"+str(socket.gethostname())+"'... [Passing!]\n")
|
|
|
os.remove('tempmail')
|
|
|
|
|
|
if __name__ == "__main__":
|