Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
edaacdf
a little refactoring on the way to making a pluggable architecture.
j105rob Nov 18, 2014
3b6a081
moved bot out into its own class; starting to add dynamic capabilitie…
j105rob Nov 19, 2014
c0a0f06
first cut at stats for the dumpmon database
j105rob Nov 19, 2014
24c4ec0
added twitterror import in stats class
j105rob Nov 19, 2014
a802c8c
added TwitterBot protocol
j105rob Nov 20, 2014
74d4c48
added custom regex & persistance into DB
j105rob Nov 20, 2014
0271988
added check user submitted url via DM to twitterbot
j105rob Nov 21, 2014
16ce124
changed out to curl for pulling raw data, resets were preventing data…
j105rob Nov 21, 2014
2d58c1e
added HaveIBeenPwned site
j105rob Nov 24, 2014
b26fdb8
error handling update
j105rob Nov 30, 2014
93265df
error handling update
j105rob Nov 30, 2014
3b073ec
adding tools
j105rob Dec 2, 2014
eeb2f17
adding tools
j105rob Dec 2, 2014
93f71d9
adding tools
j105rob Dec 2, 2014
128498f
adding tools
j105rob Dec 2, 2014
75f56fe
rotating logs
j105rob Dec 2, 2014
96c4179
add log rotation
j105rob Dec 3, 2014
edee974
add log rotation
j105rob Dec 3, 2014
d5b7923
add log rotation
j105rob Dec 3, 2014
be39c39
add log rotation
j105rob Dec 3, 2014
e20af2f
add log rotation
j105rob Dec 3, 2014
7a80350
add log rotation
j105rob Dec 3, 2014
748b8d0
wokring on delay for 403 issues
j105rob Dec 4, 2014
a81e965
wokring on delay for 403 issues
j105rob Dec 4, 2014
d47d09e
wokring on delay for 403 issues
j105rob Dec 4, 2014
96b0102
wokring on delay for 403 issues
j105rob Dec 4, 2014
961bc8e
wokring on delay for 403 issues
j105rob Dec 4, 2014
ca67fdf
wokring on delay for 403 issues
j105rob Dec 4, 2014
8b0e3a5
wokring on delay for 403 issues
j105rob Dec 4, 2014
4f1f606
wokring on delay for 403 issues
j105rob Dec 4, 2014
edc65c0
wokring on delay for 403 issues
j105rob Dec 4, 2014
46d7f48
wokring on delay for 403 issues
j105rob Dec 4, 2014
fc01084
wokring on delay for 403 issues
j105rob Dec 4, 2014
24aaed4
wokring on delay for 403 issues
j105rob Dec 4, 2014
824353e
wokring on delay for 403 issues
j105rob Dec 4, 2014
de901bf
wokring on delay for 403 issues
j105rob Dec 4, 2014
dfce5a8
added pwn3d DM
j105rob Dec 4, 2014
021a875
random fixes
j105rob Dec 5, 2014
a995f72
adding handler for empty paste
j105rob Dec 10, 2014
053a6ce
fixed the None return from the curl"
j105rob Dec 29, 2014
e37b5a2
changed logging msgs to debug where applicable
j105rob Dec 31, 2014
8af3fe9
changed logging msgs to debug where applicable
j105rob Dec 31, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# project
settings.py
output.log
.project
.pydevproject

# python specific
*.pyc
Expand Down
17 changes: 17 additions & 0 deletions .project
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>dumpmon</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>
5 changes: 5 additions & 0 deletions .pydevproject
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?><pydev_project>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
</pydev_project>
Empty file added __init__.py
Empty file.
66 changes: 45 additions & 21 deletions dumpmon.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,17 @@
from lib.Pastebin import Pastebin, PastebinPaste
from lib.Slexy import Slexy, SlexyPaste
from lib.Pastie import Pastie, PastiePaste
from lib.helper import log
from lib.HaveIBeen import HaveIBeen, HaveIBeenPaste

from lib.helper import log, createThread
from lib.TwitterBot import TwitterBot
from lib.RegexMgr import RegexMgr
from lib.Stats import Stats
from time import sleep
from twitter import Twitter, OAuth
from settings import CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET, log_file
from settings import log_file
import threading
import logging
from logging.handlers import RotatingFileHandler


def monitor():
Expand All @@ -30,36 +35,55 @@ def monitor():
parser.add_argument(
"-v", "--verbose", help="more verbose", action="store_true")
args = parser.parse_args()

level = logging.INFO
if args.verbose:
level = logging.DEBUG

logging.basicConfig(
format='%(asctime)s [%(levelname)s] %(message)s', filename=log_file, level=level)
format='%(asctime)s [%(levelname)s][%(module)s][%(funcName)s] %(message)s', filename=log_file, level=level)

handler = RotatingFileHandler(log_file, maxBytes=20*1000,
backupCount=5)
#logging.addHandler(handler)

logging.info('Monitoring...')
bot = Twitter(
auth=OAuth(ACCESS_TOKEN, ACCESS_TOKEN_SECRET,
CONSUMER_KEY, CONSUMER_SECRET)
)
# Create lock for both output log and tweet action

regexMgr = RegexMgr()
bot = TwitterBot(regexMgr)
# Create lock for output log
log_lock = threading.Lock()
tweet_lock = threading.Lock()

pastebin_thread = threading.Thread(
target=Pastebin().monitor, args=[bot, tweet_lock])
slexy_thread = threading.Thread(
target=Slexy().monitor, args=[bot, tweet_lock])
pastie_thead = threading.Thread(
target=Pastie().monitor, args=[bot, tweet_lock])

for thread in (pastebin_thread, slexy_thread, pastie_thead):
thread.daemon = True
thread.start()

#create an event to tell threads to keep running
isRunning = threading.Event()
isRunning.set()

#array to keep a handle on threads
workers = []

#these next 2 workers don't need to be joined when termd
createThread(bot.monitor)
createThread(Stats().monitor,bot)

#these workers need to be shut down gracefully
workers.append(createThread(HaveIBeen().monitor,bot,isRunning))
workers.append(createThread(Pastebin().monitor,bot,isRunning))
workers.append(createThread(Slexy().monitor,bot,isRunning))
workers.append(createThread(Pastie().monitor,bot,isRunning))

# Let threads run
try:
while(1):
sleep(5)
except KeyboardInterrupt:
#signal threads to shutdown
isRunning.clear()
print 'stopping'
#wait for threads to join
for t in workers:
t.join()
print 'stopped'
logging.warn('Stopped.')


Expand Down
60 changes: 60 additions & 0 deletions lib/HaveIBeen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"""
Troy Hunt's RSS Feed for the last 50 pastes

http://feeds.feedburner.com/HaveIBeenPwnedLatestPastes

"""
import feedparser

from .Site import Site
from .Paste import Paste
from bs4 import BeautifulSoup
from . import helper
from time import sleep
from settings import SLEEP_HAVEIBEEN
from twitter import TwitterError
import logging

class HaveIBeenPaste(Paste):
def __init__(self, id):
super(HaveIBeenPaste, self).__init__(id)
self.headers = None
self.url = 'http://pastebin.com/raw.php?i=' + self.id

def get(self):
self.text = helper.curl(self.url)

class HaveIBeen(Site):
def __init__(self):
super(HaveIBeen, self).__init__()
self.sleep = SLEEP_HAVEIBEEN
logging.info('[+] Started HaveIBeen')
self.feedURL = 'http://feeds.feedburner.com/HaveIBeenPwnedLatestPastes'

def _parse(self):
try:
d = feedparser.parse(self.feedURL)
return d['entries']
except Exception as e:
logging.error('[!] Feed Parser Error: %s'%(str(e)))
return None

def update(self):
logging.debug('Retrieving HaveIBeenPwned ID\'s')
i=0

for entry in self._parse():
l = entry['links'][0]['href']
link = l.split(r'/')
paste = HaveIBeenPaste(link[3])
if not self.hasSeen(paste):
i+=1
self.put(paste)
logging.debug('HaveIBeenPwned Added URLs: ' + str(i))




if __name__ == '__main__':
c = HaveIBeen()
c.update()
126 changes: 91 additions & 35 deletions lib/Paste.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,47 @@
import settings
import logging
import re
import time

class Paste(object):
def __init__(self):
def __init__(self,id):
'''
class Paste: Generic "Paste" object to contain attributes of a standard paste

'''
self.emails = 0
self.hashes = 0
self.id = id
self.emails = []
self.emails2 = []
self.hashes = []
self.num_emails = 0
self.num_hashes = 0
self.text = None
self.type = None
self.sites = None
self.db_keywords = 0.0


def __eq__(self,comparePaste):
#logging.info('id %s compares to %s'%(self.id, comparePaste.id))
return self.id == comparePaste.id

def row(self):
return {
'pid' : self.id,
'text' : self.text,
'emails' : self.emails,
'hashes' : self.hashes,
'num_emails' : self.num_emails,
'num_hashes' : self.num_hashes,
'type' : self.type,
'db_keywords' : self.db_keywords,
'url' : self.url,
"added":time.strftime("%c")
}

def get(self):
#override this
logging.error('[@] Function Not Implemented in Subclass')
pass

def match(self):
'''
Matches the paste against a series of regular expressions to determine if the paste is 'interesting'
Expand All @@ -32,33 +57,64 @@ def match(self):

'''
# Get the amount of emails
self.emails = list(set(regexes['email'].findall(self.text)))
self.hashes = regexes['hash32'].findall(self.text)
self.num_emails = len(self.emails)
self.num_hashes = len(self.hashes)
if self.num_emails > 0:
self.sites = list(set([re.search('@(.*)$', email).group(1).lower() for email in self.emails]))
for regex in regexes['db_keywords']:
if regex.search(self.text):
logging.debug('\t[+] ' + regex.search(self.text).group(1))
self.db_keywords += round(1/float(
len(regexes['db_keywords'])), 2)
for regex in regexes['blacklist']:
if regex.search(self.text):
logging.debug('\t[-] ' + regex.search(self.text).group(1))
self.db_keywords -= round(1.25 * (
1/float(len(regexes['db_keywords']))), 2)
if (self.num_emails >= settings.EMAIL_THRESHOLD) or (self.num_hashes >= settings.HASH_THRESHOLD) or (self.db_keywords >= settings.DB_KEYWORDS_THRESHOLD):
self.type = 'db_dump'
if regexes['cisco_hash'].search(self.text) or regexes['cisco_pass'].search(self.text):
self.type = 'cisco'
if regexes['honeypot'].search(self.text):
self.type = 'honeypot'
if regexes['google_api'].search(self.text):
self.type = 'google_api'
# if regexes['juniper'].search(self.text): self.type = 'Juniper'
for regex in regexes['banlist']:
if regex.search(self.text):
self.type = None
break
return self.type
try:
r = self.text.splitlines()
logging.debug("[*] Num Lines in text: %i"%(len(r)))

if regexes['email'].search(self.text):
self.emails = regexes['email'].findall(self.text)

if regexes['email2'].search(self.text):
self.emails2 = regexes['email2'].findall(self.text)

self.hashes = regexes['hash32'].findall(self.text)

self.num_emails = len(self.emails)
logging.debug("[*] Num Emails: %i"%(self.num_emails))

self.num_emails = len(self.emails2)
logging.debug("[*] Num Emails2: %i"%(self.num_emails))

self.num_hashes = len(self.hashes)
logging.debug("[*] Num Hashes: %i"%(self.num_hashes))

if self.num_emails > 0:
self.sites = list(set([re.search('@(.*)$', email).group(1).lower() for email in self.emails]))
logging.debug("[*] Num Sites: %i"%(len(self.sites)))

for regex in regexes['db_keywords']:
if regex.search(self.text):
logging.debug('\t[+] ' + regex.search(self.text).group(1))
self.db_keywords += round(1/float(
len(regexes['db_keywords'])), 2)

for regex in regexes['blacklist']:
if regex.search(self.text):
logging.debug('\t[-] ' + regex.search(self.text).group(1))
self.db_keywords -= round(1.25 * (
1/float(len(regexes['db_keywords']))), 2)

if (self.num_emails >= settings.EMAIL_THRESHOLD) or (self.num_hashes >= settings.HASH_THRESHOLD) or (self.db_keywords >= settings.DB_KEYWORDS_THRESHOLD):
self.type = 'db_dump'

if regexes['cisco_hash'].search(self.text) or regexes['cisco_pass'].search(self.text):
self.type = 'cisco'

if regexes['honeypot'].search(self.text):
self.type = 'honeypot'

if regexes['google_api'].search(self.text):
self.type = 'google_api'

# if regexes['juniper'].search(self.text): self.type = 'Juniper'
for regex in regexes['banlist']:
if regex.search(self.text):
self.type = None
break

logging.debug("[*] Type: %s"%(self.type))
return self.type

except Exception as e:
logging.error("[!] Error: %s"%(str(e)))
return None
Loading