#!/usr/bin/python import sys,commands,time,getopt,string import twitter, os from optparse import OptionParser username='' password='' ssh_attacks=dict() ftp_attacks=dict() params = dict() def parseCmdline(argv): parser = OptionParser() parser.add_option("-s", "--ssh", action="store", type="string", dest="ssh_logfile", default="/var/log/auth.log", help="Report attacks on ssh. default path /var/log/auth.log is used of no path provided as FILE", metavar="FILE") parser.add_option("-f", "--ftp", action="store", type="string", dest="ftp_logfile", default="/var/log/vsftpd.log",help="Report attacks on FTP. default path /var/log/vsftpd.log is used of no path provided as FILE", metavar="FILE") options, args = parser.parse_args() return options.ssh_logfile, options.ftp_logfile def postTweet(message): print "u: " + username + " p: " + password api = twitter.Api(username=username, password=password, input_encoding="utf-8") try: status = api.PostUpdate(message) except: print "Possibly encoding error\n" sys.exit(2) return status def parseLog(log_name): global params cmd = "grep '" + params[log_name][0] + "' " + params[log_name][1] attacks = params[log_name][6] #attacks is a in memory dictionary that stores the map in the form of IP:[[count],[set of usernames tried]] with IP as a key line_count_cmd = cmd + " | wc -l" cmdstatus, response = commands.getstatusoutput(line_count_cmd) current_log_length = int(response) lines_to_fetch = current_log_length - params[log_name][4] if lines_to_fetch <= 0: return current_log_length fetch_lines_cmd = cmd + " | tail -" + str(lines_to_fetch) cmdstatus, response = commands.getstatusoutput(fetch_lines_cmd) log_lines = response.split('\n') #split logs into individual log lines lines = len(log_lines) attackers = set([]) #a set of fresh attackers seen in this time slot for line in log_lines: ip = line.split()[int(params[log_name][3])] #ip address is fourth last field in the log line user = line.split()[int(params[log_name][2])] #username tried is sixth last field in the log list if ip in attacks: if attacks[ip][0] < params[log_name][5]: #add username if the different usernames tried are less than 5 attacks[ip][1].append(user) attackers.add(ip) attacks[ip][0] = attacks[ip][0] + 1 #increment the number of attacks else: #new attacker IP, log it as a key and save the username tried username_set = [] username_set.append(user) users = [1, username_set] attacks[ip] = users attackers.add(ip) # now that the IP:[username] dictionaries have been updated, go through the # fresh attackers in this time slot and tweet them for ip in attackers: if attacks[ip][0] >= params[log_name][5]: tweet = log_name + " attack from " + str(ip) + " with " + str(attacks[ip][0]) + " usernames {" + ", ".join(attacks[ip][1]) + " ...}" #print tweet status = postTweet(tweet) print "%s posted: %s" %(status.user.name, status.text) return current_log_length def main(argv): ssh_log_length = 0 ftp_log_length = 0 global username global password global params global ssh_attacks global ftp_attacks ssh_logfile, ftp_logfile = parseCmdline(argv) params['SSH'] = ["invalid", ssh_logfile, 10, 12, 0, 5, ssh_attacks] # [log_keyword, log_filename, user_column, ip_column, threshold, log_lenght_parsed] params['FTP'] = ["FAIL LOGIN", ftp_logfile, 7, 11, 0, 3, ftp_attacks] while 1: try: print "tried... " username = os.environ.get("TWEETUSERNAME", None) password = os.environ.get("TWEETPASSWORD", None) if not username or not password: print "Could not get twitter account details.\n" sys.exit(1) params['SSH'][4] = parseLog("SSH") params['FTP'][4] = parseLog("FTP") except: sys.exit(2) #repeat every 1 hour time.sleep(3600) if __name__ == "__main__": main(sys.argv[1:])