Guest User

Untitled

a guest
Mar 27th, 2018
366
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.35 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. __author__ = 'Imam Omar Mochtar <iomarmochtar@gmail.com>'
  4.  
  5. """
  6. Parse zimbra audit file for blocking any massive failed authentication which indicating brute force attempt
  7.  
  8. this script assume zimbra proxy and mailbox service in same server with original ip (oip) is logged
  9. the attempted IP will listed in AUDITWATCH chain. for applying block combine run this command for add it in INPUT filter
  10.  
  11. # iptables -t filter -I INPUT -j AUDITWATCH
  12. """
  13.  
  14. import re
  15. import sys
  16. import subprocess
  17. import smtplib
  18. from email.mime.multipart import MIMEMultipart
  19. from email.mime.text import MIMEText
  20. from email.utils import COMMASPACE, formatdate
  21. from pprint import pprint
  22.  
  23. ### VARIABLES BEGIN
  24. AUDIT_FILE = '/opt/zimbra/log/audit.log'
  25. CHAIN = 'AUDITWATCH'
  26. MAX_ATTEMPT = 20
  27.  
  28. # define white list here
  29. WHITELIST = re.compile( '(%s)' % '|'.join( map(lambda x: x.replace('.', '\.'), [
  30. '192.100'
  31. ])))
  32.  
  33. # list of blocked IP
  34. BLOCKED = set()
  35.  
  36. # this var will hold parsing result
  37. FAILED_IP = {}
  38.  
  39. ## SMTP
  40. REPORT_FROM = 'admin@mail.com'
  41. REPORT_TO = ['iomarmochtar@gmail.com']
  42. REPORT_SUBJECT = 'Authentication Attempt Report'
  43. REPORT_SMTP = '127.0.0.1'
  44.  
  45. ### VARIABLES END
  46.  
  47.  
  48. def run_cmd(command):
  49. return subprocess.Popen(
  50. command, universal_newlines=True, shell=True,
  51. stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
  52.  
  53. # make sure chain are exists
  54. run_cmd("/sbin/iptables -nL {0} || /sbin/iptables -N {0}".format(CHAIN))
  55.  
  56. # grab listed of blocked IP
  57. output, err = run_cmd("/sbin/iptables -nL {0}".format(CHAIN))
  58. for txt in output.splitlines():
  59.  
  60. if txt.startswith('DROP'):
  61. brk = txt.split()
  62. if len(brk) != 5:
  63. continue
  64. BLOCKED.add(brk[3])
  65. continue
  66.  
  67. oip_parser = re.compile(r'oip=(?P<oip>.*?);.*?for\s+\[(?P<username>.*?)\],\s+invalid password;$')
  68.  
  69. # loop trough audit file to parse any failed authentication, capture OIP params
  70. for line in open(AUDIT_FILE, 'r').readlines():
  71. oip = oip_parser.search(line)
  72. if not oip:
  73. continue
  74.  
  75. data = oip.groupdict()
  76. ip = data['oip']
  77.  
  78. # if the IP was listed in existing block and ignore list then skip it
  79. if ip in BLOCKED or WHITELIST.search(ip):
  80. continue
  81.  
  82. if not FAILED_IP.has_key(ip):
  83. FAILED_IP[ip] = {'users': set(), 'attempt': 0}
  84.  
  85. FAILED_IP[ip]['users'].add(data['username'])
  86. FAILED_IP[ip]['attempt'] += 1
  87.  
  88. # input IP in CHAIN if has reach maximum var
  89. is_report = False
  90. text = "<h3><b>List of auth attempt</b></h3> <br/><br/><br/>"
  91. f_cmd = "/sbin/iptables -I {0} -p tcp -s {1} -j DROP"
  92. for ip, data in FAILED_IP.items():
  93. if data['attempt'] <= MAX_ATTEMPT:
  94. continue
  95. is_report = True
  96. cmd = f_cmd.format(CHAIN, ip)
  97. print("IP {0} has reach max attempt {1} ({2})".format(ip, MAX_ATTEMPT, data['attempt']))
  98. run_cmd(cmd)
  99. text += "<b><u>{0} for {1} times</u></b> <br/><ul>".format(ip, data['attempt'])
  100. for user in data['users']:
  101. text += "<li>{0}</li>".format(user)
  102. text += "</ul>"
  103.  
  104.  
  105. if not is_report:
  106. sys.exit(0)
  107.  
  108. print("sending report")
  109. msg = MIMEMultipart()
  110. msg['From'] = REPORT_FROM
  111. msg['To'] = COMMASPACE.join(REPORT_TO)
  112. msg['Date'] = formatdate(localtime=True)
  113. msg['Subject'] = REPORT_SUBJECT
  114.  
  115. msg.attach(MIMEText(text, 'html'))
  116. msg.attach(MIMEText("Please see this email as HTML", 'plain'))
  117.  
  118. smtp = smtplib.SMTP(REPORT_SMTP)
  119. smtp.sendmail(REPORT_FROM, REPORT_TO, msg.as_string())
  120. smtp.close()
Add Comment
Please, Sign In to add comment