def create_bitcoin_account(address=None, canarydrop=None): key = KEY_BITCOIN_ACCOUNT + address if db.exists(key): raise KeyError if not canarydrop: from tokens import Canarytoken from canarydrop import Canarydrop ht = Canarytoken() canarydrop = Canarydrop(canarytoken=ht.value()) else: ht = canarydrop.canarytoken canarydrop['bitcoin_account'] = address save_canarydrop(canarydrop=canarydrop) bitcoin_account = { 'canarytoken': ht.value(), 'address': address, 'balance': get_bitcoin_address_balance(address=address) } return save_bitcoin_account(bitcoin_account=bitcoin_account)
def create_linkedin_account(username=None, password=None, canarydrop=None): key = KEY_LINKEDIN_ACCOUNT + username if db.exists(key): raise KeyError if not canarydrop: from tokens import Canarytoken from canarydrop import Canarydrop ht = Canarytoken() canarydrop = Canarydrop(canarytoken=ht.value()) else: ht = canarydrop.canarytoken canarydrop['linkedin_username'] = username save_canarydrop(canarydrop=canarydrop) linkedin_account = { 'username': username.lower(), 'password': password, 'canarytoken': ht.value(), 'count': get_linkedin_viewer_count(username=username, password=password) } return save_linkedin_account(linkedin_account=linkedin_account)
def create_linkedin_account(username=None, password=None, canarydrop=None): key = KEY_LINKEDIN_ACCOUNT+username if db.exists(key): raise KeyError if not canarydrop: from tokens import Canarytoken from canarydrop import Canarydrop ht = Canarytoken() canarydrop = Canarydrop(canarytoken=ht.value()) else: ht = canarydrop.canarytoken canarydrop['linkedin_username'] = username save_canarydrop(canarydrop=canarydrop) linkedin_account = { 'username': username.lower(), 'password': password, 'canarytoken': ht.value(), 'count': get_linkedin_viewer_count( username=username, password=password)} return save_linkedin_account(linkedin_account=linkedin_account)
def create_bitcoin_account(address=None, canarydrop=None): key = KEY_BITCOIN_ACCOUNT+address if db.exists(key): raise KeyError if not canarydrop: from tokens import Canarytoken from canarydrop import Canarydrop ht = Canarytoken() canarydrop = Canarydrop(canarytoken=ht.value()) else: ht = canarydrop.canarytoken canarydrop['bitcoin_account'] = address save_canarydrop(canarydrop=canarydrop) bitcoin_account = { 'canarytoken': ht.value(), 'address': address, 'balance': get_bitcoin_address_balance( address=address)} return save_bitcoin_account(bitcoin_account=bitcoin_account)
def query(self, query, src_ip): """ Check if the query should be answered dynamically, otherwise dispatch to the fallback resolver. """ IS_NX_DOMAIN = True in [ query.name.name.lower().endswith(d) for d in settings.NXDOMAINS ] if (not True in [ query.name.name.lower().endswith(d) for d in self.canary_domains ] and not IS_NX_DOMAIN): return defer.fail(error.DNSQueryRefusedError()) if query.type == dns.NS: return defer.succeed(self._do_ns_response(name=query.name.name)) if query.type == dns.SOA: return defer.succeed(self._do_soa_response(name=query.name.name)) if query.type != dns.A: return defer.succeed(self._do_no_response(query=query)) try: token = Canarytoken(value=query.name.name) canarydrop = Canarydrop(**get_canarydrop( canarytoken=token.value())) src_data = self.look_for_source_data(token=token.value(), value=query.name.name) if canarydrop._drop['type'] == 'my_sql': d = deferLater(reactor, 10, self.dispatch, canarydrop=canarydrop, src_ip=src_ip, src_data=src_data) d.addErrback(self._handleMySqlErr) else: self.dispatch(canarydrop=canarydrop, src_ip=src_ip, src_data=src_data) except (NoCanarytokenPresent, NoCanarytokenFound): # If we dont find a canarytoken, lets just continue. No need to log. pass except Exception as e: log.error(e) if IS_NX_DOMAIN: return defer.fail(error.DomainError()) return defer.succeed(self._do_dynamic_response(name=query.name.name))
def validateTo(self, user): # Only messages directed to the "console" user are accepted. try: token = Canarytoken(value=user.dest.local) self.canarydrop = Canarydrop(**get_canarydrop(canarytoken=token.value())) return lambda: CanaryMessage(esmtp=self) except (NoCanarytokenPresent, NoCanarytokenFound): log.err("No token in recipient address: {address}".format(address=user.dest.local)) except Exception as e: log.err(e) raise smtp.SMTPBadRcpt(user)
def render_GET(self, request): # A GET request to a token URL can trigger one of a few responses: # 1. Check if link has been clicked on (rather than loaded from an # <img>) by looking at the Accept header, then: # 1a. If browser security if enabled, serve that page and stop. # 1b. If fortune in enabled, serve a fortune and stop. # 2. Otherwise we'll serve an image: # 2a. If a custom image is attached to the canarydrop, serve that and stop. # 2b. Serve our default 1x1 gif request.setHeader("Server", "Apache") try: token = Canarytoken(value=request.path) canarydrop = Canarydrop(**get_canarydrop(canarytoken=token.value())) if request.args.get("ts_key", [None])[0]: canarydrop._drop["hit_time"] = request.args.get("ts_key", [None])[0] else: canarydrop._drop["hit_time"] = datetime.datetime.utcnow().strftime("%s.%f") useragent = request.getHeader("User-Agent") src_ip = request.getHeader("x-forwarded-for") # location and refere are for cloned sites location = request.args.get("l", [None])[0] referer = request.args.get("r", [None])[0] self.dispatch(canarydrop=canarydrop, src_ip=src_ip, useragent=useragent, location=location, referer=referer) if "text/html" in request.getHeader("Accept"): if canarydrop["browser_scanner_enabled"]: template = env.get_template("browser_scanner.html") return template.render(key=canarydrop._drop["hit_time"], canarytoken=token.value()).encode("utf8") elif TOKEN_RETURN == "fortune": try: fortune = subprocess.check_output("/usr/games/fortune") template = env.get_template("fortune.html") return template.render(fortune=fortune).encode("utf8") except Exception as e: log.err("Could not get a fortune: {e}".format(e=e)) if canarydrop["web_image_enabled"] and os.path.exists(canarydrop["web_image_path"]): mimetype = "image/" + canarydrop["web_image_path"][-3:] with open(canarydrop["web_image_path"], "r") as f: contents = f.read() request.setHeader("Content-Type", mimetype) return contents except Exception as e: log.err("Error in render GET: {error}".format(error=e)) request.setHeader("Content-Type", "image/gif") return self.GIF
def validateTo(self, user): # Only messages directed to the "console" user are accepted. try: token = Canarytoken(value=user.dest.local) self.canarydrop = Canarydrop(**get_canarydrop( canarytoken=token.value())) return lambda: CanaryMessage(esmtp=self) except (NoCanarytokenPresent, NoCanarytokenFound): log.warn('No token in recipient address: {address}'\ .format(address=user.dest.local)) except Exception as e: log.error(e) raise smtp.SMTPBadRcpt(user)
def render_GET(self, request): try: token = Canarytoken(value=request.path) canarydrop = Canarydrop(**get_canarydrop(canarytoken=token.value())) useragent = request.getHeader('User-Agent') src_ip = request.getHeader('x-forwarded-for') self.dispatch(canarydrop=canarydrop, src_ip=src_ip, useragent=useragent) except: log.err('No canarytoken seen in: {path}'.format(path=request.path)) request.setHeader("Content-Type", "image/gif") request.setHeader("Server", "Apache") return self.GIF
def render_GET(self, request): try: token = Canarytoken(value=request.path) canarydrop = Canarydrop(**get_canarydrop( canarytoken=token.value())) useragent = request.getHeader('User-Agent') src_ip = request.getHeader('x-forwarded-for') self.dispatch(canarydrop=canarydrop, src_ip=src_ip, useragent=useragent) except: log.err('No canarytoken seen in: {path}'.format(path=request.path)) request.setHeader("Content-Type", "image/gif") request.setHeader("Server", "Apache") return self.GIF
def chirp(self, trigger): try: token = Canarytoken(value=trigger['tf']) self.canarydrop = Canarydrop(**get_canarydrop(canarytoken=token.value())) if self.enricher: self.enricher(trigger, self.canarydrop, self.factory.dispatch) else: self.factory.dispatch( canarydrop=self.canarydrop, src_ip=trigger['ip'], useragent=trigger['useragent'], location=trigger['location'] ) except (NoCanarytokenPresent, NoCanarytokenFound): log.warn('No token for {tf} | Cert: {f}'.format(tf=trigger['tf'], f=trigger['f'])) except Exception as e: log.error("Exception in chirp: {}".format(e))
def render_GET(self, request): try: token = Canarytoken(value=request.path) canarydrop = Canarydrop(**get_canarydrop(canarytoken=token.value())) useragent = request.getHeader('User-Agent') src_ip = request.getHeader('x-forwarded-for') #location and refere are for cloned sites location = request.args.get('l', [None])[0] referer = request.args.get('r', [None])[0] self.dispatch(canarydrop=canarydrop, src_ip=src_ip, useragent=useragent, location=location, referer=referer) except: log.err('No canarytoken seen in: {path}'.format(path=request.path)) request.setHeader("Content-Type", "image/gif") request.setHeader("Server", "Apache") return self.GIF
def query(self, query, src_ip): """ Check if the query should be answered dynamically, otherwise dispatch to the fallback resolver. """ self.logfile.write('%r\n' % query) self.logfile.flush() if query.type == dns.NS: return defer.succeed(self._do_ns_response(name=query.name.name)) if query.type != dns.A: return defer.succeed(self._do_no_response(query=query)) #return defer.fail(error.DomainError()) try: token = Canarytoken(value=query.name.name) canarydrop = Canarydrop(**get_canarydrop( canarytoken=token.value())) src_data = self.look_for_source_data(token=token.value(), value=query.name.name) self.dispatch(canarydrop=canarydrop, src_ip=src_ip, src_data=src_data) # return defer.succeed( # self._do_dynamic_response(name=query.name.name, # response=response)) except NoCanarytokenPresent: log.err('No token seen in query: {query}'.format( query=query.name.name)) except Exception as e: log.err(e) if query.name.name in settings.NXDOMAINS: return defer.fail(error.DomainError()) return defer.succeed(self._do_dynamic_response(name=query.name.name))
def query(self, query, src_ip): """ Check if the query should be answered dynamically, otherwise dispatch to the fallback resolver. """ self.logfile.write('%r\n' % query) self.logfile.flush() if not True in [query.name.name.lower().endswith(d) for d in self.canary_domains]: return defer.fail(error.DNSQueryRefusedError()) if query.type == dns.NS: return defer.succeed(self._do_ns_response(name=query.name.name)) if query.type == dns.SOA: return defer.succeed(self._do_soa_response(name=query.name.name)) if query.type != dns.A: return defer.succeed(self._do_no_response(query=query)) try: token = Canarytoken(value=query.name.name) canarydrop = Canarydrop(**get_canarydrop(canarytoken=token.value())) src_data = self.look_for_source_data(token=token.value(), value=query.name.name) self.dispatch(canarydrop=canarydrop, src_ip=src_ip, src_data=src_data) except (NoCanarytokenPresent, NoCanarytokenFound): # If we dont find a canarytoken, lets just continue. No need to log. pass except Exception as e: log.err(e) if query.name.name in settings.NXDOMAINS: return defer.fail(error.DomainError()) return defer.succeed(self._do_dynamic_response(name=query.name.name))
def render_GET(self, request): try: token = Canarytoken(value=request.path) canarydrop = Canarydrop(**get_canarydrop( canarytoken=token.value())) useragent = request.getHeader('User-Agent') src_ip = request.getHeader('x-forwarded-for') #location and refere are for cloned sites location = request.args.get('l', [None])[0] referer = request.args.get('r', [None])[0] self.dispatch(canarydrop=canarydrop, src_ip=src_ip, useragent=useragent, location=location, referer=referer) except: log.err('No canarytoken seen in: {path}'.format(path=request.path)) request.setHeader("Content-Type", "image/gif") request.setHeader("Server", "Apache") return self.GIF
def query(self, query, src_ip): """ Check if the query should be answered dynamically, otherwise dispatch to the fallback resolver. """ self.logfile.write('%r\n' % query) self.logfile.flush() if query.type == dns.NS: return defer.succeed(self._do_ns_response(name=query.name.name)) if query.type != dns.A: return defer.succeed(self._do_no_response(query=query)) #return defer.fail(error.DomainError()) try: token = Canarytoken(value=query.name.name) canarydrop = Canarydrop(**get_canarydrop(canarytoken=token.value())) src_data = self.look_for_source_data(token=token.value(), value=query.name.name) self.dispatch(canarydrop=canarydrop, src_ip=src_ip, src_data=src_data) # return defer.succeed( # self._do_dynamic_response(name=query.name.name, # response=response)) except NoCanarytokenPresent: log.err('No token seen in query: {query}'.format(query=query.name.name)) except Exception as e: log.err(e) if query.name.name in settings.NXDOMAINS: return defer.fail(error.DomainError()) return defer.succeed(self._do_dynamic_response(name=query.name.name))
def render_POST(self, request): request.responseHeaders.addRawHeader(b"content-type", b"application/json") response = { 'Error': None, 'Url': "", 'Token': "", 'Email': "", 'Hostname': "" } try: try: email = request.args.get('email', None)[0] except IndexError: response['Error'] = 1 raise Exception('No email supplied') try: memo = ''.join(request.args.get('memo', None)) except TypeError: response['Error'] = 2 raise Exception('No memo supplied') canarytoken = Canarytoken() canarydrop = Canarydrop(generate=True, alert_email_enabled=True, alert_email_recipient=email, canarytoken=canarytoken.value(), memo=memo) if settings.TWILIO_ENABLED: try: if not request.args['mobile'][0]: raise KeyError canarydrop['alert_sms_recipient'] = request.args['mobile'][ 0] canarydrop['alert_sms_enabled'] = True except KeyError: canarydrop['alert_sms_recipient'] = '' canarydrop['alert_sms_enabled'] = False save_canarydrop(canarydrop) response['Token'] = canarytoken.value() response['Url'] = canarydrop.get_url() response['Hostname'] = canarydrop.get_hostname() response['Email'] = email try: imgur_id = request.args['imgur'][0] if not imgur_id: raise KeyError imgur_token = { 'id': imgur_id, 'canarytoken': canarytoken.value() } canarydrop.imgur_token = save_imgur_token(imgur_token) save_canarydrop(canarydrop) response['imgur_count'] = imgur_token['count'] response['imgur_id'] = imgur_id except (IndexError, KeyError): pass try: linkedin_user = request.args['linkedin_user'][0] linkedin_password = request.args['linkedin_password'][0] if not linkedin_user and not linkedin_password: raise KeyError create_linkedin_account(username=linkedin_user, password=linkedin_password, canarydrop=canarydrop) response['linkedin_account'] = linkedin_user response['linkedin_account_views'] = \ get_linkedin_account(username=linkedin_user)['count'] except (IndexError, KeyError): pass try: bitcoin_address = request.args['bitcoin_address'][0] if not bitcoin_address: raise KeyError create_bitcoin_account(address=bitcoin_address) btc = get_bitcoin_account(address=bitcoin_address) response['bitcoin_address'] = bitcoin_address response['bitcoin_balance'] = btc['balance'] except (IndexError, KeyError): pass except Exception as e: if response['Error'] is None: response['Error'] = 255 log.err('Unexpected error: {err}'.format(err=e)) return simplejson.dumps(response)
def render_POST(self, request): try: key = request.args["key"][0] token = Canarytoken(value=request.path) canarydrop = Canarydrop(**get_canarydrop(canarytoken=token.value())) # if key and token args are present, we are either: # -posting browser info # -getting an aws trigger (key == aws_s3) # store the info and don't re-render if key and token: if key == "aws_s3": try: canarydrop._drop["hit_time"] = datetime.datetime.utcnow().strftime("%s.%f") src_ip = request.args["RemoteIP"][0] additional_info = { "AWS Log Data": {k: v for k, v in request.args.iteritems() if k not in ["key", "src_ip"]} } self.dispatch(canarydrop=canarydrop, src_ip=src_ip, additional_info=additional_info) except Exception as e: log.err("Error in s3 post: {error}".format(error=e)) elif "secretkeeper_photo" in request.args: log.err("Saving secretkeeper_photo") try: fields = cgi.FieldStorage( fp=request.content, headers=request.getAllHeaders(), environ={"REQUEST_METHOD": "POST", "CONTENT_TYPE": request.getAllHeaders()["content-type"]}, ) # hacky way to parse out file contents and filenames filename = fields["secretkeeper_photo"].filename filebody = fields["secretkeeper_photo"].value if len(filebody) > MAX_UPLOAD_SIZE: raise Exception("File too large") r = hashlib.md5(os.urandom(32)).hexdigest() filepath = os.path.join(WEB_IMAGE_UPLOAD_PATH, r[:2], r[2:]) + ".png" if not os.path.exists(os.path.dirname(filepath)): try: os.makedirs(os.path.dirname(filepath)) except OSError as exc: # Guard against race condition if exc.errno != errno.EEXIST: raise with open(filepath, "w") as f: f.write(filebody) canarydrop.add_additional_info_to_hit( hit_time=key, additional_info={"secretkeeper_photo": filepath} ) except Exception as e: log.err("Error in secretkeeper_photo post: {error}".format(error=e)) else: additional_info = { k: v for k, v in request.args.iteritems() if k not in ["key", "canarytoken", "name"] } canarydrop.add_additional_info_to_hit( hit_time=key, additional_info={request.args["name"][0]: additional_info} ) return "success" else: return self.render_GET(request) except Exception as e: return self.render_GET(request)
def render_POST(self, request): try: token = Canarytoken(value=request.path) canarydrop = Canarydrop(**get_canarydrop( canarytoken=token.value())) #if key and token args are present, we are either: # -posting browser info # -getting an aws trigger (key == aws_s3) # otherwise, slack api token data perhaps #store the info and don't re-render if canarydrop._drop['type'] == 'slack_api': canarydrop._drop['hit_time'] = datetime.datetime.utcnow( ).strftime("%s.%f") useragent = request.args.get('user_agent', [None])[0] src_ip = request.args.get('ip', [None])[0] additional_info = { 'Slack Log Data': { k: v for k, v in request.args.iteritems() if k not in ['user_agent', 'ip'] } } self.dispatch(canarydrop=canarydrop, src_ip=src_ip, useragent=useragent, additional_info=additional_info) return self.GIF if canarydrop._drop['type'] == 'aws_keys': canarydrop._drop['hit_time'] = datetime.datetime.utcnow( ).strftime("%s.%f") useragent = request.args.get('user_agent', [None])[0] src_ip = request.args.get('ip', [None])[0] safety_net = request.args.get('safety_net', [None])[0] last_used = request.args.get('last_used', [None])[0] additional_info = { 'AWS Key Log Data': { k: v for k, v in request.args.iteritems() if k not in ['user_agent', 'ip'] } } if safety_net: log.info('AWS Safety Net triggered for {}'.format( token.value())) self.dispatch(canarydrop=canarydrop, src_ip=src_ip, useragent=useragent, additional_info=additional_info) return self.GIF key = request.args['key'][0] if key and token: if key == 'aws_s3': try: canarydrop._drop[ 'hit_time'] = datetime.datetime.utcnow().strftime( "%s.%f") src_ip = request.args['RemoteIP'][0] additional_info = { 'AWS Log Data': { k: v for k, v in request.args.iteritems() if k not in ['key', 'src_ip'] } } self.dispatch(canarydrop=canarydrop, src_ip=src_ip, additional_info=additional_info) except Exception as e: log.error('Error in s3 post: {error}'.format(error=e)) elif 'secretkeeper_photo' in request.args: log.error('Saving secretkeeper_photo') try: fields = cgi.FieldStorage( fp=request.content, headers=request.getAllHeaders(), environ={ 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': request.getAllHeaders()['content-type'], } ) #hacky way to parse out file contents and filenames filename = fields['secretkeeper_photo'].filename filebody = fields['secretkeeper_photo'].value if len(filebody) > MAX_UPLOAD_SIZE: raise Exception('File too large') r = hashlib.md5(os.urandom(32)).hexdigest() filepath = os.path.join(WEB_IMAGE_UPLOAD_PATH, r[:2], r[2:]) + '.png' if not os.path.exists(os.path.dirname(filepath)): try: os.makedirs(os.path.dirname(filepath)) except OSError as exc: # Guard against race condition if exc.errno != errno.EEXIST: raise with open(filepath, "w") as f: f.write(filebody) canarydrop.add_additional_info_to_hit( hit_time=key, additional_info={'secretkeeper_photo': filepath}) except Exception as e: log.error( 'Error in secretkeeper_photo post: {error}'.format( error=e)) else: additional_info = { k: v for k, v in request.args.iteritems() if k not in ['key', 'canarytoken', 'name'] } canarydrop.add_additional_info_to_hit( hit_time=key, additional_info={ request.args['name'][0]: additional_info }) return 'success' else: return self.render_GET(request) except Exception as e: return self.render_GET(request)
def render_GET(self, request): #A GET request to a token URL can trigger one of a few responses: # 1. Check if link has been clicked on (rather than loaded from an # <img>) by looking at the Accept header, then: # 1a. If browser security if enabled, serve that page and stop. # 1b. If fortune in enabled, serve a fortune and stop. # 2. Otherwise we'll serve an image: # 2a. If a custom image is attached to the canarydrop, serve that and stop. # 2b. Serve our default 1x1 gif request.setHeader("Server", "Apache") try: token = Canarytoken(value=request.path) canarydrop = Canarydrop(**get_canarydrop( canarytoken=token.value())) if request.args.get('ts_key', [None])[0]: canarydrop._drop['hit_time'] = request.args.get( 'ts_key', [None])[0] else: canarydrop._drop['hit_time'] = datetime.datetime.utcnow( ).strftime("%s.%f") useragent = request.getHeader('User-Agent') src_ip = request.getHeader('x-forwarded-for') #location and refere are for cloned sites location = request.args.get('l', [None])[0] referer = request.args.get('r', [None])[0] self.dispatch(canarydrop=canarydrop, src_ip=src_ip, useragent=useragent, location=location, referer=referer) if 'redirect_url' in canarydrop._drop and canarydrop._drop[ 'redirect_url']: # if fast redirect if canarydrop._drop['type'] == 'fast_redirect': return redirectTo(canarydrop._drop['redirect_url'], request) #template = env.get_template('browser_scanner.html') #return template.render(key=canarydrop._drop['hit_time'], # canarytoken=token.value()).encode('utf8') elif canarydrop._drop['type'] == 'slow_redirect': template = env.get_template('browser_scanner.html') return template.render( key=canarydrop._drop['hit_time'], canarytoken=token.value(), redirect_url=canarydrop._drop['redirect_url']).encode( 'utf8') if request.getHeader( 'Accept') and "text/html" in request.getHeader('Accept'): if canarydrop['browser_scanner_enabled']: template = env.get_template('browser_scanner.html') return template.render(key=canarydrop._drop['hit_time'], canarytoken=token.value(), redirect_url='').encode('utf8') elif TOKEN_RETURN == 'fortune': try: fortune = subprocess.check_output('/usr/games/fortune') template = env.get_template('fortune.html') return template.render(fortune=fortune).encode('utf8') except Exception as e: log.error('Could not get a fortune: {e}'.format(e=e)) if canarydrop['web_image_enabled'] and os.path.exists( canarydrop['web_image_path']): mimetype = "image/" + canarydrop['web_image_path'][-3:] with open(canarydrop['web_image_path'], "r") as f: contents = f.read() request.setHeader("Content-Type", mimetype) return contents except Exception as e: log.warn('Error in render GET: {error}'.format(error=e)) request.setHeader("Content-Type", "image/gif") return self.GIF
def render_POST(self, request): request.responseHeaders.addRawHeader(b"content-type", b"application/json") response = { 'Error': None, 'Url': "", 'Token': "", 'Email': "", 'Hostname': "", 'Auth': ''} try: try: email = request.args.get('email', None)[0] webhook = request.args.get('webhook', None)[0] if not email and not webhook: response['Error'] = 1 raise Exception('No email/webhook supplied') except IndexError: response['Error'] = 1 raise Exception('No email supplied') try: memo = ''.join(request.args.get('memo', None)) if not memo: response['Error'] = 2 raise Exception('No memo supplied') except TypeError: response['Error'] = 2 raise Exception('No memo supplied') if webhook and not is_webhook_valid(webhook): response['Error'] = 3 raise Exception('Invalid webhook supplied') alert_email_enabled = False if not email else True alert_webhook_enabled = False if not webhook else True canarytoken = Canarytoken() try: browser_scanner = request.args['subtype'][0] == 'browserscanner' except: browser_scanner = False canarydrop = Canarydrop(generate=True, alert_email_enabled=alert_email_enabled, alert_email_recipient=email, alert_webhook_enabled=alert_webhook_enabled, alert_webhook_url=webhook, canarytoken=canarytoken.value(), memo=memo, browser_scanner_enabled=browser_scanner) if settings.TWILIO_ENABLED: try: if not request.args['mobile'][0]: raise KeyError canarydrop['alert_sms_recipient'] = request.args['mobile'][0] canarydrop['alert_sms_enabled'] = True except KeyError: canarydrop['alert_sms_recipient'] = '' canarydrop['alert_sms_enabled'] = False save_canarydrop(canarydrop) response['Token'] = canarytoken.value() response['Url'] = canarydrop.get_url() response['Hostname'] = canarydrop.get_hostname() response['Auth'] = canarydrop['auth'] response['Email'] = email try: clonedsite = request.args['clonedsite'][0] if not clonedsite: raise KeyError cloned_token = {'clonedsite': clonedsite, 'canarytoken': canarytoken.value()} canarydrop.clonedsite_token = save_clonedsite_token(cloned_token) save_canarydrop(canarydrop) response['clonedsite_js'] = CLONED_SITE_JS\ .replace('CLONED_SITE_DOMAIN', clonedsite)\ .replace('CANARYTOKEN_SITE', canarydrop.get_random_site())\ .replace('CANARYTOKEN', response['Token']) response['clonedsite'] = clonedsite except (IndexError, KeyError): pass try: imgur_id = request.args['imgur'][0] if not imgur_id: raise KeyError imgur_token = {'id': imgur_id, 'canarytoken': canarytoken.value()} canarydrop.imgur_token = save_imgur_token(imgur_token) save_canarydrop(canarydrop) response['imgur_count'] = imgur_token['count'] response['imgur_id'] = imgur_id except (IndexError, KeyError): pass try: linkedin_user = request.args['linkedin_user'][0] linkedin_password = request.args['linkedin_password'][0] if not linkedin_user and not linkedin_password: raise KeyError create_linkedin_account(username=linkedin_user, password=linkedin_password, canarydrop=canarydrop) response['linkedin_account'] = linkedin_user response['linkedin_account_views'] = \ get_linkedin_account(username=linkedin_user)['count'] except (IndexError, KeyError): pass try: bitcoin_address = request.args['bitcoin_address'][0] if not bitcoin_address: raise KeyError create_bitcoin_account(address=bitcoin_address) btc = get_bitcoin_account(address=bitcoin_address) response['bitcoin_address'] = bitcoin_address response['bitcoin_balance'] = btc['balance'] except (IndexError, KeyError): pass try: qrcode = pyqrcode.create(canarydrop.get_url()).png_as_base64_str(scale=5) response['qrcode_png'] = "data:image/png;base64,{qrcode}".format(qrcode=qrcode) except: pass except Exception as e: if response['Error'] is None: response['Error'] = 255 log.err('Unexpected error: {err}'.format(err=e)) return simplejson.dumps(response)
def render_POST(self, request): request.responseHeaders.addRawHeader(b"content-type", b"application/json") response = { 'Error': None, 'Url': "", 'Token': "", 'Email': "", 'Hostname': ""} try: try: email = request.args.get('email', None)[0] except IndexError: response['Error'] = 1 raise Exception('No email supplied') try: memo = ''.join(request.args.get('memo', None)) except TypeError: response['Error'] = 2 raise Exception('No memo supplied') canarytoken = Canarytoken() canarydrop = Canarydrop(generate=True, alert_email_enabled=True, alert_email_recipient=email, canarytoken=canarytoken.value(), memo=memo) if settings.TWILIO_ENABLED: try: if not request.args['mobile'][0]: raise KeyError canarydrop['alert_sms_recipient'] = request.args['mobile'][0] canarydrop['alert_sms_enabled'] = True except KeyError: canarydrop['alert_sms_recipient'] = '' canarydrop['alert_sms_enabled'] = False save_canarydrop(canarydrop) response['Token'] = canarytoken.value() response['Url'] = canarydrop.get_url() response['Hostname'] = canarydrop.get_hostname() response['Email'] = email try: clonedsite = request.args['clonedsite'][0] if not clonedsite: raise KeyError cloned_token = {'clonedsite': clonedsite, 'canarytoken': canarytoken.value()} canarydrop.clonedsite_token = save_clonedsite_token(cloned_token) save_canarydrop(canarydrop) response['clonedsite_js'] = CLONED_SITE_JS\ .replace('CLONED_SITE_DOMAIN', clonedsite)\ .replace('CANARYTOKEN_SITE', canarydrop.get_random_site())\ .replace('CANARYTOKEN', response['Token']) response['clonedsite'] = clonedsite except (IndexError, KeyError): pass try: imgur_id = request.args['imgur'][0] if not imgur_id: raise KeyError imgur_token = {'id': imgur_id, 'canarytoken': canarytoken.value()} canarydrop.imgur_token = save_imgur_token(imgur_token) save_canarydrop(canarydrop) response['imgur_count'] = imgur_token['count'] response['imgur_id'] = imgur_id except (IndexError, KeyError): pass try: linkedin_user = request.args['linkedin_user'][0] linkedin_password = request.args['linkedin_password'][0] if not linkedin_user and not linkedin_password: raise KeyError create_linkedin_account(username=linkedin_user, password=linkedin_password, canarydrop=canarydrop) response['linkedin_account'] = linkedin_user response['linkedin_account_views'] = \ get_linkedin_account(username=linkedin_user)['count'] except (IndexError, KeyError): pass try: bitcoin_address = request.args['bitcoin_address'][0] if not bitcoin_address: raise KeyError create_bitcoin_account(address=bitcoin_address) btc = get_bitcoin_account(address=bitcoin_address) response['bitcoin_address'] = bitcoin_address response['bitcoin_balance'] = btc['balance'] except (IndexError, KeyError): pass except Exception as e: if response['Error'] is None: response['Error'] = 255 log.err('Unexpected error: {err}'.format(err=e)) return simplejson.dumps(response)
def dispatch_alert(self, username, src_host, additional_info): token = Canarytoken(value=username) canarydrop = Canarydrop(**get_canarydrop(canarytoken=token.value())) self.dispatch(canarydrop=canarydrop, src_ip=src_host, additional_info=additional_info)
def render_POST(self, request): request.responseHeaders.addRawHeader(b"content-type", b"application/json") response = { 'Error': None, 'Url': "", 'Url_components': None, 'Token': "", 'Email': "", 'Hostname': "", 'Auth': '' } try: try: token_type = request.args.get('type', None)[0] if token_type not in [ 'web', 'dns', 'web_image', 'ms_word', 'adobe_pdf', 'windows_dir', 'clonedsite', 'qr_code', 'svn', 'smtp', 'sql_server', 'aws_keys', 'signed_exe', 'fast_redirect', 'slow_redirect' ]: raise Exception() except: raise Exception('Unknown type') try: email = request.args.get('email', None)[0] webhook = request.args.get('webhook', None)[0] if not email and not webhook: response['Error'] = 1 raise Exception('No email/webhook supplied') except IndexError: response['Error'] = 1 raise Exception('No email supplied') try: memo = ''.join(request.args.get('memo', None)) if not memo: response['Error'] = 2 raise Exception('No memo supplied') except TypeError: response['Error'] = 2 raise Exception('No memo supplied') if webhook and not is_webhook_valid(webhook): response['Error'] = 3 raise Exception( 'Invalid webhook supplied. Confirm you can POST to this URL.' ) alert_email_enabled = False if not email else True alert_webhook_enabled = False if not webhook else True canarytoken = Canarytoken() if token_type == "web": #always enable the browser scanner by default browser_scanner = True else: browser_scanner = False canarydrop = Canarydrop( type=token_type, generate=True, alert_email_enabled=alert_email_enabled, alert_email_recipient=email, alert_webhook_enabled=alert_webhook_enabled, alert_webhook_url=webhook, canarytoken=canarytoken.value(), memo=memo, browser_scanner_enabled=browser_scanner) if settings.TWILIO_ENABLED: try: if not request.args['mobile'][0]: raise KeyError canarydrop['alert_sms_recipient'] = request.args['mobile'][ 0] canarydrop['alert_sms_enabled'] = True except KeyError: canarydrop['alert_sms_recipient'] = '' canarydrop['alert_sms_enabled'] = False save_canarydrop(canarydrop) response['Token'] = canarytoken.value() response['Url'] = canarydrop.get_url() response['Hostname'] = canarydrop.get_hostname() response['Auth'] = canarydrop['auth'] response['Email'] = email response['Url_components'] = list(canarydrop.get_url_components()) save_canarydrop(canarydrop) try: clonedsite = request.args['clonedsite'][0] if not clonedsite: raise KeyError cloned_token = { 'clonedsite': clonedsite, 'canarytoken': canarytoken.value() } canarydrop.clonedsite_token = save_clonedsite_token( cloned_token) canarydrop['clonedsite'] = clonedsite save_canarydrop(canarydrop) response[ 'clonedsite_js'] = canarydrop.get_cloned_site_javascript() response['clonedsite'] = clonedsite except (IndexError, KeyError): pass try: if not request.args.get('type', None)[0] == 'qr_code': raise Exception() response['qrcode_png'] = canarydrop.get_qrcode_data_uri_png() except: pass try: if not request.args.get('type', None)[0] == 'aws_keys': raise Exception() keys = get_aws_keys(token=canarytoken.value(), server=get_all_canary_domains()[0]) if not keys: raise Exception() response['aws_access_key_id'] = keys[0] response['aws_secret_access_key'] = keys[1] canarydrop['aws_access_key_id'] = keys[0] canarydrop['aws_secret_access_key'] = keys[1] save_canarydrop(canarydrop) except: pass try: if not request.args.get('type', None)[0] == 'web_image': raise Exception() if not settings.WEB_IMAGE_UPLOAD_PATH: raise Exception( "Image upload not supported, set CANARY_WEB_IMAGE_UPLOAD_PATH in frontend.env." ) fields = cgi.FieldStorage( fp=request.content, headers=request.getAllHeaders(), environ={ 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': request.getAllHeaders()['content-type'], }) filename = fields['web_image'].filename filebody = fields['web_image'].value if len(filebody) > settings.MAX_UPLOAD_SIZE: raise Exception('File too large') if not filename.lower().endswith(('.png', '.gif', '.jpg')): raise Exception('Uploaded image must be a PNG, GIF or JPG') ext = filename.lower()[-4:] #create a random local filename r = hashlib.md5(os.urandom(32)).hexdigest() filepath = os.path.join(settings.WEB_IMAGE_UPLOAD_PATH, r[:2], r[2:]) + ext if not os.path.exists(os.path.dirname(filepath)): try: os.makedirs(os.path.dirname(filepath)) except OSError as exc: # Guard against race condition if exc.errno != errno.EEXIST: raise with open(filepath, "w") as f: f.write(filebody) canarydrop['web_image_enabled'] = True canarydrop['web_image_path'] = filepath save_canarydrop(canarydrop) except: pass try: if request.args.get('type', None)[0] != 'signed_exe': raise Exception() fields = cgi.FieldStorage( fp=request.content, headers=request.getAllHeaders(), environ={ 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': request.getAllHeaders()['content-type'], }) #hacky way to parse out file contents and filenames filename = fields['signed_exe'].filename filebody = fields['signed_exe'].value if len(filebody) > settings.MAX_UPLOAD_SIZE: raise Exception('File too large') if not filename.lower().endswith(('exe', 'dll')): raise Exception( 'Uploaded authenticode file must be an exe or dll') signed_contents = make_canary_authenticode_binary( hostname=canarydrop.get_hostname(with_random=False, as_url=True), filebody=filebody) response['file_name'] = filename response[ 'file_contents'] = "data:octet/stream;base64," + base64.b64encode( signed_contents) except: pass try: if request.args.get('type', None)[0] != 'fast_redirect': raise Exception() if not request.args['redirect_url'][0]: raise Exception() canarydrop['redirect_url'] = request.args['redirect_url'][0] save_canarydrop(canarydrop) except: pass try: if request.args.get('type', None)[0] != 'slow_redirect': raise Exception() if not request.args['redirect_url'][0]: raise Exception() canarydrop['redirect_url'] = request.args['redirect_url'][0] save_canarydrop(canarydrop) except: pass except Exception as e: if response['Error'] is None: response['Error'] = 255 log.err('Unexpected error: {err}'.format(err=e)) return simplejson.dumps(response)
def canarytoken(self): """Return the Canarydrop's Canarytoken object.""" return Canarytoken(value=self._drop['canarytoken'])