예제 #1
0
    def render_GET(self, request):
        try:
            token  = request.args.get('token', None)[0]
            fmt    = request.args.get('fmt', None)[0]

            canarydrop = Canarydrop(**get_canarydrop(canarytoken=token))
            if not canarydrop:
                raise NoCanarytokenPresent()

            if fmt == 'zip':
                request.setHeader("Content-Type", "application/zip")
                request.setHeader("Content-Disposition",
                                  'attachment; filename={token}.zip'\
                                  .format(token=token))
                return make_canary_zip(hostname=
                            canarydrop.get_hostname(with_random=False))
            elif fmt == 'msword':
                request.setHeader("Content-Type",
                                  "application/vnd.openxmlformats-officedocument"+\
                                                      ".wordprocessingml.document")
                request.setHeader("Content-Disposition",
                                  'attachment; filename={token}.docx'\
                                  .format(token=token))
                return make_canary_msword(url=canarydrop.get_url())
            elif fmt == 'pdf':
                request.setHeader("Content-Type", "application/pdf")
                request.setHeader("Content-Disposition",
                                  'attachment; filename={token}.pdf'\
                                  .format(token=token))
                return make_canary_pdf(hostname=canarydrop.get_hostname(nxdomain=True, with_random=False))
        except Exception as e:
            log.err('Unexpected error in download: {err}'.format(err=e))


        return NoResource().render(request)
예제 #2
0
    def render_GET(self, request):

        try:
            token = request.args.get('token', None)[0]
            auth = request.args.get('auth', None)[0]
            canarydrop = Canarydrop(**get_canarydrop(canarytoken=token))
            if not canarydrop['auth'] or canarydrop['auth'] != auth:
                raise NoCanarytokenPresent()
            if canarydrop.get('triggered_list', None):
                for timestamp in canarydrop['triggered_list'].keys():
                    formatted_timestamp = datetime.datetime.fromtimestamp(
                        float(timestamp)).strftime('%Y %b %d %H:%M:%S')
                    canarydrop['triggered_list'][
                        formatted_timestamp] = canarydrop[
                            'triggered_list'].pop(timestamp)

            if canarydrop.get('memo'):
                canarydrop['memo'] = unicode(canarydrop['memo'], "utf8")

        except (TypeError, NoCanarytokenPresent):
            return NoResource().render(request)
        g_api_key = get_canary_google_api_key()
        template = env.get_template('history.html')
        return template.render(canarydrop=canarydrop,
                               API_KEY=g_api_key).encode('utf8')
예제 #3
0
    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))
예제 #4
0
    def render_POST(self, request):
        try:
            try:
                token = request.args.get('token', None)[0]
                auth  = request.args.get('auth',  None)[0]

                canarydrop = Canarydrop(**get_canarydrop(canarytoken=token))
                if not canarydrop['auth'] or canarydrop['auth'] != auth:
                    raise NoCanarytokenPresent()

            except (IndexError, TypeError, NoCanarytokenPresent):
                return NoResource().render(request)

            try:
                email_enable_status = request.args.get('email_enable', None)[0] == "on"
            except (TypeError, IndexError):
                email_enable_status = False

            try:
                webhook_enable_status = request.args.get('webhook_enable', None)[0] == "on"
            except (TypeError, IndexError):
                webhook_enable_status = False

            try:
                sms_enable_status = request.args.get('sms_enable', None)[0] == "on"
            except (TypeError, IndexError):
                sms_enable_status = False

            try:
                web_image_status = request.args.get('web_image_enable', None)[0] == "on"
            except (TypeError, IndexError):
                web_image_status = False

            try:
                token_fmt = request.args.get('fmt', None)[0]
            except (TypeError, IndexError):
                token_fmt = ''

            canarydrop['alert_email_enabled'] = email_enable_status
            canarydrop['alert_webhook_enabled'] = webhook_enable_status
            canarydrop['alert_sms_enabled']   = sms_enable_status
            canarydrop['web_image_enabled']   = web_image_status

            save_canarydrop(canarydrop=canarydrop)

            g_api_key = get_canary_google_api_key()
            template = env.get_template('manage.html')
            return template.render(canarydrop=canarydrop, saved=True,
                                        settings=settings, API_KEY=g_api_key).encode('utf8')

        except Exception as e:
            import traceback
            log.err('Exception in manage.html: {e}, {stack}'.format(e=e, stack=traceback.format_exc()))
            template = env.get_template('manage.html')
            return template.render(canarydrop=canarydrop, error=e,
                                        settings=settings).encode('utf8')
 def poll(self, imgur_token=None):
     try:
         count = get_imgur_count(imgur_id=imgur_token["id"])
         if count > imgur_token["count"]:
             canarydrop = Canarydrop(**get_canarydrop(canarytoken=imgur_token["canarytoken"]))
             self.dispatch(canarydrop=canarydrop, count=count, imgur_id=imgur_token["id"])
             imgur_token["count"] = count
             save_imgur_token(imgur_token=imgur_token)
     except Exception as e:
         log.err("Imgur error: {error}".format(error=e))
예제 #6
0
    def render_POST(self, request):
        request.responseHeaders.addRawHeader(b"content-type",
                                             b"application/json")
        response = {}
        try:
            token = request.args.get('token', None)[0]
            auth = request.args.get('auth', None)[0]
            setting = request.args.get('setting', None)[0]

            canarydrop = Canarydrop(**get_canarydrop(canarytoken=token))
            if not canarydrop['auth'] or canarydrop['auth'] != auth:
                raise NoCanarytokenPresent()

            if setting not in [
                    'clonedsite', 'email_enable', 'webhook_enable',
                    'sms_enable', 'browser_scanner_enable', 'web_image_enable'
            ]:
                raise NoCanarytokenPresent()

        except (IndexError, TypeError, NoCanarytokenPresent):
            return NoResource().render(request)

        if setting == 'clonedsite':
            try:
                clonedsite = request.args['clonedsite'][0]
                if not clonedsite:
                    raise KeyError

                cloned_token = {'clonedsite': clonedsite, 'canarytoken': token}
                canarydrop.clonedsite_token = save_clonedsite_token(
                    cloned_token)
                save_canarydrop(canarydrop)
                response[
                    'clonedsite_js'] = canarydrop.get_cloned_site_javascript()
                response['clonedsite'] = clonedsite
            except (IndexError, KeyError):
                return NoResource().render(request)
        elif setting == "email_enable":
            canarydrop['alert_email_enabled'] = request.args['value'][
                0] == "on"
        elif setting == "webhook_enable":
            canarydrop['alert_webhook_enabled'] = request.args['value'][
                0] == "on"
        elif setting == "sms_enable":
            canarydrop['alert_sms_enabled'] = request.args['value'][0] == "on"
        elif setting == "browser_scanner_enable":
            canarydrop['browser_scanner_enabled'] = request.args['value'][
                0] == "on"
        elif setting == "web_image_enable":
            canarydrop['web_image_enabled'] = request.args['value'][0] == "on"

        save_canarydrop(canarydrop=canarydrop)
        response['result'] = 'success'

        return simplejson.dumps(response)
예제 #7
0
 def poll(self, imgur_token=None):
     try:
         count = get_imgur_count(imgur_id=imgur_token['id'])
         if count > imgur_token['count']:
             canarydrop = Canarydrop(**get_canarydrop(
                             canarytoken=imgur_token['canarytoken']))
             self.dispatch(canarydrop=canarydrop, count=count,
                           imgur_id=imgur_token['id'])
             imgur_token['count'] = count
             save_imgur_token(imgur_token=imgur_token)
     except Exception as e:
         log.warn('Imgur error: {error}'.format(error=e))
    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)
예제 #9
0
    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
예제 #10
0
    def render_GET(self, request):

        try:
            token = request.args.get('token', None)[0]
            auth  = request.args.get('auth', None)[0]
            canarydrop = Canarydrop(**get_canarydrop(canarytoken=token))
            if not canarydrop['auth'] or canarydrop['auth'] != auth:
                raise NoCanarytokenPresent()

        except (TypeError, NoCanarytokenPresent):
            return NoResource().render(request)

        template = env.get_template('manage.html')
        return template.render(canarydrop=canarydrop).encode('utf8')
예제 #11
0
    def render_GET(self, request):

        try:
            token = request.args.get('token', None)[0]
            auth = request.args.get('auth', None)[0]
            canarydrop = Canarydrop(**get_canarydrop(canarytoken=token))
            if not canarydrop['auth'] or canarydrop['auth'] != auth:
                raise NoCanarytokenPresent()

        except (TypeError, NoCanarytokenPresent):
            return NoResource().render(request)

        template = env.get_template('manage.html')
        return template.render(canarydrop=canarydrop).encode('utf8')
예제 #12
0
 def received_imgur_count(self, body, imgur_token):
     try:
         body = simplejson.loads(body)
         count = int(body['data'][imgur_token['id']])
         log.info('Count for imgur token '+imgur_token['id']+ ' was '+str(count))
         if count > imgur_token['count']:
             canarydrop = Canarydrop(**get_canarydrop(
                             canarytoken=imgur_token['canarytoken']))
             self.dispatch(canarydrop=canarydrop, count=count,
                           imgur_id=imgur_token['id'])
             imgur_token['count'] = count
             save_imgur_token(imgur_token=imgur_token)
     except Exception as e:
         log.warn('Imgur error: {error}'.format(error=e))
예제 #13
0
    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
예제 #14
0
    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)
예제 #15
0
    def render_POST(self, request):
        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

            token = request.args.get('token', None)[0]
            fmt = request.args.get('fmt', None)[0]
            if fmt not in ['authenticode']:
                raise Exception('Unsupported token type for POST.')

            canarydrop = Canarydrop(**get_canarydrop(canarytoken=token))
            if not canarydrop:
                raise NoCanarytokenPresent()

            if fmt == 'authenticode':
                filename = fields['file_for_signing'].filename
                filebody = fields['file_for_signing'].value
                if len(filebody) > int(settings.MAX_UPLOAD_SIZE):
                    response['Error'] = 4
                    response[
                        'Message'] = 'File too large. File size must be < ' + str(
                            int(settings.MAX_UPLOAD_SIZE) /
                            (1024 * 1024)) + 'MB.'
                    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)
                request.setHeader("Content-Type", "octet/stream")
                request.setHeader("Content-Disposition",
                                  'attachment; filename={filename}.signed'\
                                  .format(filename=filename))
                return signed_contents

        except Exception as e:
            log.err('Unexpected error in POST download: {err}'.format(err=e))
            template = env.get_template('error.html')
            return template.render(error=e.message).encode('utf8')

        return NoResource().render(request)
예제 #16
0
    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
예제 #17
0
    def poll(self, linkedin_account=None):
        try:
            current_count = get_linkedin_viewer_count(
                                username=linkedin_account['username'],
                                password=linkedin_account['password'])
        except LinkedInFailure as e:
            log.err('Could not retrieve linkedin view count: {error}'\
                    .format(error=e))
            return

        if current_count > linkedin_account['count']:
            canarydrop = Canarydrop(**get_canarydrop(
                            canarytoken=linkedin_account['canarytoken']))
            self.dispatch(canarydrop=canarydrop, count=current_count, 
                          linkedin_username=linkedin_account['username'])
            linkedin_account['count'] = current_count
            save_linkedin_account(linkedin_account=linkedin_account)
예제 #18
0
    def poll(self, bitcoin_account=None):
        try:
            current_balance = get_bitcoin_address_balance(
                                address=bitcoin_account['address'])
        except BitcoinFailure as e:
            log.err('Could not retrieve bitcoin balance: {error}'\
                    .format(error=e))
            return

        if current_balance> bitcoin_account['balance']:
            canarydrop = Canarydrop(**get_canarydrop(
                            canarytoken=bitcoin_account['canarytoken']))
            self.dispatch(canarydrop=canarydrop, new_balance=current_balance, 
                          old_balance=bitcoin_account['balance'],
                          address=bitcoin_account['address'])
            bitcoin_account['balance'] = current_balance
            save_bitcoin_account(bitcoin_account=bitcoin_account)
예제 #19
0
    def render_POST(self, request):
        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

            token  = request.args.get('token', None)[0]
            fmt    = request.args.get('fmt', None)[0]
            if fmt not in ['authenticode']:
                raise Exception('Unsupported token type for POST.')

            canarydrop = Canarydrop(**get_canarydrop(canarytoken=token))
            if not canarydrop:
                raise NoCanarytokenPresent()

            if fmt == 'authenticode':
                filename = fields['file_for_signing'].filename
                filebody = fields['file_for_signing'].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)
                request.setHeader("Content-Type", "octet/stream")
                request.setHeader("Content-Disposition",
                                  'attachment; filename={filename}.signed'\
                                  .format(filename=filename))
                return signed_contents


        except Exception as e:
            log.err('Unexpected error in POST download: {err}'.format(err=e))
            template = env.get_template('error.html')
            return template.render(error=e.message).encode('utf8')

        return NoResource().render(request)
예제 #20
0
    def render_GET(self, request):

        try:
            token = request.args.get('token', None)[0]
            auth  = request.args.get('auth', None)[0]
            canarydrop = Canarydrop(**get_canarydrop(canarytoken=token))
            if not canarydrop['auth'] or canarydrop['auth'] != auth:
                raise NoCanarytokenPresent()
            if canarydrop.get('triggered_list', None):
                for timestamp in canarydrop['triggered_list'].keys():
                    formatted_timestamp = datetime.datetime.fromtimestamp(
                                float(timestamp)).strftime('%Y %b %d %H:%M:%S')
                    canarydrop['triggered_list'][formatted_timestamp] = canarydrop['triggered_list'].pop(timestamp)

        except (TypeError, NoCanarytokenPresent):
            return NoResource().render(request)
        g_api_key = get_canary_google_api_key()
        template = env.get_template('manage.html')
        return template.render(canarydrop=canarydrop, API_KEY=g_api_key).encode('utf8')
예제 #21
0
    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))
예제 #22
0
    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
예제 #23
0
    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))
예제 #24
0
    def render_POST(self, request):
        try:
            try:
                token = request.args.get('token', None)[0]
                auth = request.args.get('auth', None)[0]

                canarydrop = Canarydrop(**get_canarydrop(canarytoken=token))
                if not canarydrop['auth'] or canarydrop['auth'] != auth:
                    raise NoCanarytokenPresent()

            except (IndexError, NoCanarytokenPresent):
                return NoResource().render(request)

            try:
                email_enable_status = request.args.get('email_enable',
                                                       None)[0] == "on"
            except (TypeError, IndexError):
                email_enable_status = False

            try:
                sms_enable_status = request.args.get('sms_enable',
                                                     None)[0] == "on"
            except (TypeError, IndexError):
                sms_enable_status = False

            canarydrop['alert_email_enabled'] = email_enable_status
            canarydrop['alert_sms_enabled'] = sms_enable_status

            save_canarydrop(canarydrop=canarydrop)

            template = env.get_template('manage.html')
            return template.render(canarydrop=canarydrop,
                                   saved=True,
                                   settings=settings).encode('utf8')

        except Exception as e:
            template = env.get_template('manage.html')
            return template.render(canarydrop=canarydrop,
                                   error=e,
                                   settings=settings).encode('utf8')
예제 #25
0
    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))
예제 #26
0
    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
예제 #27
0
    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))
예제 #28
0
    def render_POST(self, request):
        try:
            try:
                token = request.args.get('token', None)[0]
                auth  = request.args.get('auth',  None)[0]

                canarydrop = Canarydrop(**get_canarydrop(canarytoken=token))
                if not canarydrop['auth'] or canarydrop['auth'] != auth:
                    raise NoCanarytokenPresent()

            except (IndexError, NoCanarytokenPresent):
                return NoResource().render(request)

            try:
                email_enable_status = request.args.get('email_enable', None)[0] == "on"
            except (TypeError, IndexError):
                email_enable_status = False

            try:
                sms_enable_status = request.args.get('sms_enable', None)[0] == "on"
            except (TypeError, IndexError):
                sms_enable_status = False

            canarydrop['alert_email_enabled'] = email_enable_status
            canarydrop['alert_sms_enabled']   = sms_enable_status

            save_canarydrop(canarydrop=canarydrop)

            template = env.get_template('manage.html')
            return template.render(canarydrop=canarydrop, saved=True,
                                        settings=settings).encode('utf8')

        except Exception as e:
            template = env.get_template('manage.html')
            return template.render(canarydrop=canarydrop, error=e,
                                        settings=settings).encode('utf8')
예제 #29
0
 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)
예제 #30
0
    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
예제 #31
0
    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)
예제 #32
0
    def render_POST(self, request):
        try:
            try:
                token = request.args.get('token', None)[0]
                auth  = request.args.get('auth',  None)[0]

                canarydrop = Canarydrop(**get_canarydrop(canarytoken=token))
                if not canarydrop['auth'] or canarydrop['auth'] != auth:
                    raise NoCanarytokenPresent()

            except (IndexError, NoCanarytokenPresent):
                return NoResource().render(request)

            try:
                email_enable_status = request.args.get('email_enable', None)[0] == "on"
            except (TypeError, IndexError):
                email_enable_status = False

            try:
                webhook_enable_status = request.args.get('webhook_enable', None)[0] == "on"
            except (TypeError, IndexError):
                webhook_enable_status = False

            try:
                sms_enable_status = request.args.get('sms_enable', None)[0] == "on"
            except (TypeError, IndexError):
                sms_enable_status = False

            try:
                web_image_status = request.args.get('web_image_enable', None)[0] == "on"
            except (TypeError, IndexError):
                web_image_status = False

            try:
                token_fmt = request.args.get('fmt', None)[0]
            except (TypeError, IndexError):
                token_fmt = ''

            canarydrop['alert_email_enabled'] = email_enable_status
            canarydrop['alert_webhook_enabled'] = webhook_enable_status
            canarydrop['alert_sms_enabled']   = sms_enable_status
            canarydrop['web_image_enabled']   = web_image_status

            if token_fmt == 'web_image':
                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=canarydrop)
            g_api_key = get_canary_google_api_key()
            template = env.get_template('manage.html')
            return template.render(canarydrop=canarydrop, saved=True,
                                        settings=settings, API_KEY=g_api_key).encode('utf8')

        except Exception as e:
            import traceback
            log.err('Exception in manage.html: {e}, {stack}'.format(e=e, stack=traceback.format_exc()))
            template = env.get_template('manage.html')
            return template.render(canarydrop=canarydrop, error=e,
                                        settings=settings).encode('utf8')
예제 #33
0
    def render_GET(self, request):
        try:
            token = request.args.get('token', None)[0]
            fmt = request.args.get('fmt', None)[0]
            auth = request.args.get('auth', None)[0]
            canarydrop = Canarydrop(**get_canarydrop(canarytoken=token))
            if not canarydrop:
                raise NoCanarytokenPresent()
            if not canarydrop['auth'] or canarydrop['auth'] != auth:
                raise NoCanarytokenPresent()

            if fmt == 'zip':
                request.setHeader("Content-Type", "application/zip")
                request.setHeader("Content-Disposition",
                                  'attachment; filename={token}.zip'\
                                  .format(token=token))
                return make_canary_zip(hostname=canarydrop.get_hostname(
                    with_random=False))
            elif fmt == 'msword':
                request.setHeader("Content-Type",
                                  "application/vnd.openxmlformats-officedocument"+\
                                                      ".wordprocessingml.document")
                request.setHeader("Content-Disposition",
                                  'attachment; filename={token}.docx'\
                                  .format(token=token))
                return make_canary_msword(url=canarydrop.get_url())
            elif fmt == 'pdf':
                request.setHeader("Content-Type", "application/pdf")
                request.setHeader("Content-Disposition",
                                  'attachment; filename={token}.pdf'\
                                  .format(token=token))
                return make_canary_pdf(hostname=canarydrop.get_hostname(
                    nxdomain=True, with_random=False))
            elif fmt == 'awskeys':
                request.setHeader("Content-Type", "text/plain")
                request.setHeader("Content-Disposition",
                                  'attachment; filename=credentials')
                text="[default]\naws_access_key={id}\naws_secret_access_key={k}\nregion={r}\noutput={o}"\
                        .format(id=canarydrop['aws_access_key_id'], k=canarydrop['aws_secret_access_key'], r=canarydrop['region'], o=canarydrop['output'])
                return text
            elif fmt == 'incidentlist_json':
                request.setHeader("Content-Type", "text/plain")
                request.setHeader("Content-Disposition",
                                  'attachment; filename={token}_history.json'\
                                  .format(token=token))
                return simplejson.dumps(canarydrop['triggered_list'], indent=4)
            elif fmt == 'incidentlist_csv':
                request.setHeader("Content-Type", "text/plain")
                request.setHeader("Content-Disposition",
                                  'attachment; filename={token}_history.csv'\
                                  .format(token=token))
                csvOutput = StringIO()
                incident_list = canarydrop['triggered_list']

                writer = csv.writer(csvOutput)

                details = []
                for key in incident_list:
                    for element in incident_list[key].keys():
                        details.append(element)

                headers = ["Timestamp"] + details
                writer.writerow(headers)
                items = []
                for item in details:
                    for key in incident_list:
                        items.append(incident_list[key][item])

                for key in incident_list:
                    data = [
                        datetime.datetime.fromtimestamp(
                            float(key)).strftime('%Y-%m-%d %H:%M:%S.%s')
                    ] + items
                    writer.writerow(data)

                return csvOutput.getvalue()

        except Exception as e:
            log.err('Unexpected error in download: {err}'.format(err=e))

        return NoResource().render(request)
예제 #34
0
    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)
예제 #35
0
 def dispatch(self, **kwargs):
     canarytoken = kwargs.pop('canarytoken')
     # TODO: If canarydrop no longer exists, delete key -> canarytoken mapping in WireGuard keymap
     kwargs['canarydrop'] = Canarydrop(**queries.get_canarydrop(canarytoken))
     InputChannel.dispatch(self, **kwargs)