├── test
├── __init__.py
├── zadvanced
│ ├── __init__.py
│ ├── test_hunter.py
│ └── test_router.py
├── zsqlite
│ ├── __init__.py
│ └── test_store_sqlite_indicators_nonpersistent.py
├── zelasticsearch
│ ├── __init__.py
│ ├── test_store_elasticsearch_tokens.py
│ └── test_store_elasticsearch_tokens_edit.py
├── test_router.py
├── test_hunter.py
├── test_gatherer_geo.py
├── test_store.py
├── test_peers.py
├── test_gatherer_peer.py
├── test_gatherer_asn.py
└── test_httpd.py
├── README.txt
├── cif
├── httpd
│ ├── static
│ │ └── favicon.ico
│ ├── views
│ │ ├── __init__.py
│ │ ├── u
│ │ │ ├── __init__.py
│ │ │ ├── submit.py
│ │ │ ├── indicators.py
│ │ │ └── tokens.py
│ │ ├── feed
│ │ │ ├── md5.py
│ │ │ ├── sha1.py
│ │ │ ├── ssdeep.py
│ │ │ ├── url.py
│ │ │ ├── sha256.py
│ │ │ ├── sha512.py
│ │ │ ├── email.py
│ │ │ ├── ipv6.py
│ │ │ ├── fqdn.py
│ │ │ └── ipv4.py
│ │ ├── confidence.py
│ │ ├── help.py
│ │ ├── ping.py
│ │ ├── health.py
│ │ └── tokens.py
│ ├── templates
│ │ ├── layout.html
│ │ ├── flash.html
│ │ ├── login.html
│ │ ├── tokens
│ │ │ ├── form.html
│ │ │ ├── show.html
│ │ │ ├── index.html
│ │ │ └── edit.html
│ │ ├── base.html
│ │ ├── application.html
│ │ ├── submit.html
│ │ ├── indicators.html
│ │ └── nav.html
│ └── common.py
├── __init__.py
├── auth
│ ├── plugin.py
│ └── cif_store
│ │ └── __init__.py
├── exceptions.py
├── store
│ ├── plugin.py
│ ├── sqlite
│ │ ├── message.py
│ │ ├── ip.py
│ │ └── __init__.py
│ ├── indicator_plugin.py
│ ├── dummy.py
│ ├── zelasticsearch
│ │ ├── constants.py
│ │ ├── schema.py
│ │ ├── locks.py
│ │ ├── helpers.py
│ │ └── __init__.py
│ └── token_plugin.py
├── utils
│ ├── __init__.py
│ └── asn_client.py
├── hunter
│ ├── ipv4_resolve_prefix_whitelist.py
│ ├── fqdn_subdomain.py
│ ├── fqdn_wl.py
│ ├── fqdn.py
│ ├── fqdn_ns.py
│ ├── url.py
│ ├── fqdn_cname.py
│ ├── fqdn_mx.py
│ ├── farsight.py
│ ├── spamhaus_fqdn.py
│ └── spamhaus_ip.py
├── gatherer
│ ├── ja3.py
│ ├── peers.py
│ ├── asn.py
│ └── __init__.py
└── constants.py
├── packaging
├── debian
│ ├── compat
│ ├── install
│ ├── rules
│ ├── cif-smrt.conf
│ ├── cif-httpd.conf
│ ├── cif-router.conf
│ ├── cif-hunters.conf
│ ├── changelog
│ ├── cif-storage.conf
│ ├── control
│ └── cif-services.init
├── docker
│ ├── Makefile
│ ├── supervisord.conf
│ ├── Dockerfile
│ └── Dockerfile.base
├── pyinstaller
│ ├── cif.spec
│ ├── cif-router.spec
│ ├── cif-httpd.spec
│ └── csirtg-smrt.spec
├── rpm
│ └── cif.spec
├── macports
│ ├── sysutils
│ │ └── bearded-avenger
│ │ │ └── Portfile
│ └── README.md
└── homebrew
│ └── Library
│ └── Formula
│ └── bearded-avenger.rb
├── .gitattributes
├── dev_requirements.txt
├── docs
├── httpd.rst
└── index.rst
├── helpers
├── es.sh
├── test_ubuntu_blank.sh
├── test_rhel.sh
├── test_ubuntu16.sh
├── test_centos7.sh
├── test_centos7_es.sh
├── test_rhel_es.sh
├── buildbasebox.sh
├── test_ubuntu16_es.sh
├── test_ubuntu16_reboot.sh
└── test_ubuntu16_es_upsert.sh
├── setup.cfg
├── rules
├── default
│ ├── vxvault.yml
│ ├── sblam.yml
│ ├── apwg.yml
│ ├── openphish.yml
│ ├── darklist_de.yml
│ ├── urlhaus_abuse_ch.yml
│ ├── mirc.yml
│ ├── emergingthreats.yml
│ ├── torproject_org.yml
│ ├── sans_edu.yml
│ ├── danger_rules_sk.yml
│ ├── cisco_umbrella.yml
│ ├── tranco.yml
│ ├── phishtank.yml
│ ├── bambenek.yml
│ ├── majestic.yml
│ ├── feodotracker.yml
│ ├── spamhaus.yml
│ ├── sslbl_abuse_ch.yml
│ ├── stopforumspam.yml
│ ├── normshield.yml
│ ├── csirtg.yml
│ └── dataplane.yml
└── examples
│ ├── alienvault.yml
│ ├── faf-bambenek.yml
│ └── blocklist_de.yml
├── hacking
└── develop.conf
├── MANIFEST.in
├── requirements.txt
├── .github
├── issue_template.md
└── workflows
│ └── pr_test.yml
├── Vagrantfile_blank
├── .coveragerc
├── .gitignore
├── Vagrantfile_buildbox
├── README.md
├── Vagrantfile
├── contributing.md
├── reindex_tokens.py
└── setup.py
/test/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/README.txt:
--------------------------------------------------------------------------------
1 | see README.md
2 |
--------------------------------------------------------------------------------
/cif/httpd/static/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/cif/httpd/views/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/packaging/debian/compat:
--------------------------------------------------------------------------------
1 | 9
--------------------------------------------------------------------------------
/test/zadvanced/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/zsqlite/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/cif/httpd/views/u/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/zelasticsearch/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | 'cif' export-subst
2 | cif/_version.py export-subst
3 |
--------------------------------------------------------------------------------
/dev_requirements.txt:
--------------------------------------------------------------------------------
1 | coverage>=4.2
2 | pytest-cov>=2.6
3 | pytest>=4.2
4 | -r requirements.txt
5 |
--------------------------------------------------------------------------------
/packaging/debian/install:
--------------------------------------------------------------------------------
1 | cif /usr/bin
2 | cif-router /usr/bin
3 | cif-httpd /usr/bin
4 | cif-smrt /usr/bin
--------------------------------------------------------------------------------
/cif/__init__.py:
--------------------------------------------------------------------------------
1 |
2 | from ._version import get_versions
3 | VERSION = get_versions()['version']
4 | del get_versions
--------------------------------------------------------------------------------
/cif/httpd/templates/layout.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% include "nav.html" %}
4 |
5 | {% include "flash.html" %}
6 |
--------------------------------------------------------------------------------
/docs/httpd.rst:
--------------------------------------------------------------------------------
1 | HTTP API
2 | ========
3 |
4 | .. automodule:: httpd
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/helpers/es.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | VERSION=5.6.16
6 |
7 | docker run -p 9200:9200 -p 9300:9300 elasticsearch:$VERSION
8 |
--------------------------------------------------------------------------------
/packaging/debian/rules:
--------------------------------------------------------------------------------
1 | #!/usr/bin/make -f
2 | export DH_VERBOSE=1
3 |
4 | override_dh_auto_build override_dh_auto_install:
5 | @
6 |
7 | %:
8 | dh $@
--------------------------------------------------------------------------------
/helpers/test_ubuntu_blank.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export VAGRANT_VAGRANTFILE=Vagrantfile_blank
4 | export CIF_BOOTSTRAP_TEST=1
5 |
6 | time vagrant up
7 |
--------------------------------------------------------------------------------
/test/test_router.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from cif.router import Router
3 |
4 |
5 | def test_router_basics():
6 | with Router(test=True) as r:
7 | pass
8 |
--------------------------------------------------------------------------------
/packaging/debian/cif-smrt.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | pidfile = /var/run/cif-smrt.pid
3 |
4 | [program:cif-smrt]
5 | command = cif-smrt
6 | autostart = true
7 | stderr_logfile = /var/log/cif/cif-smrt.log
--------------------------------------------------------------------------------
/packaging/debian/cif-httpd.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | pidfile = /var/run/cif-httpd.pid
3 |
4 | [program:cif-httpd]
5 | command = cif-httpd
6 | autostart = true
7 | stderr_logfile = /var/log/cif/cif-httpd.log
8 |
--------------------------------------------------------------------------------
/packaging/debian/cif-router.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | pidfile = /var/run/cif-router.pid
3 |
4 | [program:cif-router]
5 | command = cif-router
6 | autostart = true
7 | stderr_logfile = /var/log/cif/cif-router.log
--------------------------------------------------------------------------------
/packaging/debian/cif-hunters.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | pidfile = /var/run/cif-hunters.pid
3 |
4 | [program:cif-hunters]
5 | command = cif-hunters
6 | autostart = true
7 | stderr_logfile = /var/log/cif/cif-hunters.log
--------------------------------------------------------------------------------
/packaging/debian/changelog:
--------------------------------------------------------------------------------
1 | bearded-avenger (%VERSION%-%RELEASE%~%DIST%) %DIST%; urgency=low
2 |
3 | * %VERSION% release
4 |
5 | -- CSIRT Gadgets Foundation. %DATE%
6 |
--------------------------------------------------------------------------------
/packaging/debian/cif-storage.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | pidfile = /var/run/cif-storage.pid
3 |
4 | [program:cif-storage]
5 | command = cif-storage --store sqlite -d
6 | autostart = true
7 | stderr_logfile = /var/log/cif/cif-storage.log
--------------------------------------------------------------------------------
/test/test_hunter.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from cif.hunter import Hunter
4 | from zmq import Context
5 |
6 |
7 | def test_hunter():
8 | with Hunter(Context.instance()) as h:
9 | assert isinstance(h, Hunter)
10 |
--------------------------------------------------------------------------------
/cif/auth/plugin.py:
--------------------------------------------------------------------------------
1 | import abc
2 |
3 |
4 | class Auth(object):
5 | __metaclass__ = abc.ABCMeta
6 |
7 | name = 'base'
8 |
9 | @abc.abstractmethod
10 | def __init__(self, **kwargs):
11 | raise NotImplementedError
12 |
--------------------------------------------------------------------------------
/cif/httpd/templates/flash.html:
--------------------------------------------------------------------------------
1 | {% import "bootstrap/utils.html" as utils %}
2 |
3 | {% with messages = get_flashed_messages(with_categories=true) %}
4 | {% if messages %}
5 | {{ utils.flashed_messages(messages) }}
6 | {% endif %}
7 | {% endwith %}
--------------------------------------------------------------------------------
/helpers/test_rhel.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export CIF_BOOTSTRAP_TEST=1
4 | export CIF_ANSIBLE_SDIST=/vagrant
5 | export CIF_HUNTER_THREADS=2
6 | export CIF_HUNTER_ADVANCED=1
7 | export CIF_GATHERER_GEO_FQDN=1
8 | export CIF_VAGRANT_DISTRO=redhat
9 |
10 | time vagrant up
11 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [bdist_wheel]
2 | universal = 1
3 |
4 | [tool:pytest]
5 | norecursedirs = build
6 |
7 | [versioneer]
8 | VCS = git
9 | style = pep440
10 | versionfile_source = cif/_version.py
11 | versionfile_build = cif/_version.py
12 | tag_prefix =
13 | parentdir_prefix = cif-
14 |
--------------------------------------------------------------------------------
/helpers/test_ubuntu16.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export VAGRANT_VAGRANTFILE=Vagrantfile
4 | export CIF_BOOTSTRAP_TEST=1
5 | export CIF_ANSIBLE_SDIST=/vagrant
6 | export CIF_HUNTER_THREADS=2
7 | export CIF_HUNTER_ADVANCED=1
8 | #export CIF_GATHERER_GEO_FQDN=1
9 |
10 | time vagrant up
11 |
--------------------------------------------------------------------------------
/rules/default/vxvault.yml:
--------------------------------------------------------------------------------
1 | defaults:
2 | provider: vxvault.net
3 | confidence: 9
4 | tlp: green
5 | altid_tlp: clear
6 | tags: malware
7 | values:
8 | - indicator
9 |
10 | feeds:
11 | urls:
12 | remote: http://vxvault.net/URL_List.php
13 | pattern: '^(http:\/\/\S+)$'
--------------------------------------------------------------------------------
/helpers/test_centos7.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export CIF_BOOTSTRAP_TEST=1
4 | export CIF_ANSIBLE_SDIST=/vagrant
5 | export CIF_HUNTER_THREADS=2
6 | export CIF_HUNTER_ADVANCED=1
7 | #export CIF_GATHERER_GEO_FQDN=1
8 | export CIF_VAGRANT_DISTRO=centos
9 |
10 | vagrant box update
11 | time vagrant up
12 |
--------------------------------------------------------------------------------
/rules/default/sblam.yml:
--------------------------------------------------------------------------------
1 | defaults:
2 | provider: sblam.com
3 | confidence: 7
4 | tlp: green
5 | altid_tlp: clear
6 | tags:
7 | - spam
8 | - spammers
9 | feeds:
10 | proxy:
11 | remote: https://sblam.com/blacklist.txt
12 | pattern: '^(\S+)$'
13 | values:
14 | - indicator
--------------------------------------------------------------------------------
/rules/default/apwg.yml:
--------------------------------------------------------------------------------
1 | # requires APWG_TOKEN environment var to be set
2 | # more info from our friends at apwg.org
3 | fetcher: apwg
4 | parser: indicator
5 |
6 | defaults:
7 | confidence: 9
8 | provider: apwg.org
9 | tlp: amber
10 |
11 | feeds:
12 | urls:
13 | defaults:
14 | confidence: 9
--------------------------------------------------------------------------------
/cif/exceptions.py:
--------------------------------------------------------------------------------
1 | from cifsdk.exceptions import CIFException
2 |
3 |
4 | class StoreSubmissionFailed(CIFException):
5 | pass
6 |
7 |
8 | class InvalidSearch(CIFException):
9 | pass
10 |
11 |
12 | class StoreLockError(CIFException):
13 | pass
14 |
15 |
16 | class CIFBusy(CIFException):
17 | pass
18 |
--------------------------------------------------------------------------------
/helpers/test_centos7_es.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export CIF_BOOTSTRAP_TEST=1
4 | export CIF_ANSIBLE_SDIST=/vagrant
5 | export CIF_HUNTER_THREADS=2
6 | export CIF_HUNTER_ADVANCED=1
7 | #export CIF_GATHERER_GEO_FQDN=1
8 | export CIF_VAGRANT_DISTRO=centos
9 | export CIF_ANSIBLE_ES=localhost:9200
10 |
11 | time vagrant up
12 |
--------------------------------------------------------------------------------
/helpers/test_rhel_es.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export CIF_BOOTSTRAP_TEST=1
4 | export CIF_ANSIBLE_SDIST=/vagrant
5 | export CIF_HUNTER_THREADS=2
6 | export CIF_HUNTER_ADVANCED=1
7 | export CIF_GATHERER_GEO_FQDN=1
8 | export CIF_VAGRANT_DISTRO=redhat
9 | export CIF_ANSIBLE_ES=localhost:9200
10 |
11 | time vagrant up
12 |
--------------------------------------------------------------------------------
/rules/default/openphish.yml:
--------------------------------------------------------------------------------
1 | defaults:
2 | tags: phishing
3 | protocol: tcp
4 | provider: openphish.com
5 | tlp: green
6 | reference_tlp: clear
7 | confidence: 9
8 | values: indicator
9 |
10 | feeds:
11 | urls:
12 | itype: url
13 | pattern: ^(.+)$
14 | remote: https://openphish.com/feed.txt
15 |
--------------------------------------------------------------------------------
/cif/store/plugin.py:
--------------------------------------------------------------------------------
1 | import abc
2 |
3 |
4 | class Store(object):
5 | __metaclass__ = abc.ABCMeta
6 |
7 | name = 'base'
8 |
9 | @abc.abstractmethod
10 | def __init__(self):
11 | raise NotImplementedError
12 |
13 | @abc.abstractmethod
14 | def ping(self):
15 | return True
16 |
17 |
--------------------------------------------------------------------------------
/helpers/buildbasebox.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export VAGRANT_VAGRANTFILE=Vagrantfile_buildbox
4 |
5 | if [ -e cifv3.box ]; then
6 | rm cifv3.box
7 | fi
8 |
9 | vagrant box remove cifv3
10 | time vagrant up
11 | vagrant package --output cifv3.box
12 | vagrant box add cifv3 cifv3.box
13 | vagrant destroy -f
14 | rm -rf cifv3.box
15 |
--------------------------------------------------------------------------------
/rules/default/darklist_de.yml:
--------------------------------------------------------------------------------
1 | defaults:
2 | provider: darklist.de
3 | confidence: 7
4 | tlp: green
5 | altid_tlp: clear
6 | tags:
7 | - blacklist
8 | altid: http://www.darklist.de/raw.php
9 |
10 |
11 | feeds:
12 | compromised-ips:
13 | remote: http://www.darklist.de/raw.php
14 | pattern: '^(\S+)$'
15 | values:
16 | - indicator
--------------------------------------------------------------------------------
/helpers/test_ubuntu16_es.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export VAGRANT_VAGRANTFILE=Vagrantfile
4 | export CIF_BOOTSTRAP_TEST=1
5 | export CIF_ANSIBLE_SDIST=/vagrant
6 | export CIF_HUNTER_THREADS=2
7 | export CIF_HUNTER_ADVANCED=1
8 | export CIF_ANSIBLE_ES=localhost:9200
9 | export CIF_ELASTICSEARCH_TEST=1
10 | #export CIF_GATHERER_GEO_FQDN=1
11 |
12 | time vagrant up
13 |
--------------------------------------------------------------------------------
/helpers/test_ubuntu16_reboot.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export VAGRANT_VAGRANTFILE=Vagrantfile
4 | export CIF_BOOTSTRAP_TEST=1
5 | export CIF_ANSIBLE_SDIST=/vagrant
6 | export CIF_HUNTER_THREADS=2
7 | export CIF_HUNTER_ADVANCED=1
8 | #export CIF_GATHERER_GEO_FQDN=1
9 |
10 | time vagrant up
11 |
12 | vagrant reload
13 | vagrant ssh -c 'cd /vagrant/deploymentkit && bash /vagrant/deploymentkit/test.sh'
--------------------------------------------------------------------------------
/packaging/docker/Makefile:
--------------------------------------------------------------------------------
1 | # https://github.com/phusion/baseimage-docker/blob/master/Makefile
2 | NAME = cif
3 | VERSION = latest # make this a version number!
4 |
5 | .PHONY: all build run
6 |
7 | all: build
8 |
9 | build:
10 | @docker build -t $(NAME):$(VERSION) .
11 |
12 | build-clean:
13 | @docker build -t $(NAME):$(VERSION) --no-cache .
14 |
15 | run:
16 | @docker run $(NAME):$(VERSION)
17 |
--------------------------------------------------------------------------------
/helpers/test_ubuntu16_es_upsert.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | export VAGRANT_VAGRANTFILE=Vagrantfile
4 | export CIF_BOOTSTRAP_TEST=1
5 | export CIF_ANSIBLE_SDIST=/vagrant
6 | export CIF_HUNTER_THREADS=2
7 | export CIF_HUNTER_ADVANCED=1
8 | export CIF_ANSIBLE_ES=localhost:9200
9 | export CIF_ELASTICSEARCH_TEST=1
10 | export CIF_STORE_ES_UPSERT_MODE=1
11 | #export CIF_GATHERER_GEO_FQDN=1
12 |
13 | time vagrant up
14 |
--------------------------------------------------------------------------------
/cif/httpd/views/feed/md5.py:
--------------------------------------------------------------------------------
1 | class Md5(object):
2 |
3 | def __init__(self):
4 | pass
5 |
6 | def process(self, data, whitelist):
7 | wl = set()
8 | for x in whitelist:
9 | wl.add(x['indicator'])
10 |
11 | rv = []
12 | for x in data:
13 | if x['indicator'] not in wl:
14 | rv.append(x)
15 |
16 | return rv
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/cif/httpd/views/feed/sha1.py:
--------------------------------------------------------------------------------
1 | class Sha1(object):
2 |
3 | def __init__(self):
4 | pass
5 |
6 | def process(self, data, whitelist):
7 | wl = set()
8 | for x in whitelist:
9 | wl.add(x['indicator'])
10 |
11 | rv = []
12 | for x in data:
13 | if x['indicator'] not in wl:
14 | rv.append(x)
15 |
16 | return rv
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/cif/httpd/views/feed/ssdeep.py:
--------------------------------------------------------------------------------
1 | class Ssdeep(object):
2 |
3 | def __init__(self):
4 | pass
5 |
6 | def process(self, data, allowlist):
7 | allowed = set()
8 | for x in allowlist:
9 | allowed.add(x['indicator'])
10 |
11 | rv = []
12 | for x in data:
13 | if x['indicator'] not in allowed:
14 | rv.append(x)
15 |
16 | return rv
17 |
--------------------------------------------------------------------------------
/cif/httpd/views/feed/url.py:
--------------------------------------------------------------------------------
1 | class Url(object):
2 |
3 | def __init__(self):
4 | pass
5 |
6 | def process(self, data, whitelist):
7 | wl = set()
8 | for x in whitelist:
9 | wl.add(x['indicator'])
10 |
11 | rv = []
12 | for x in data:
13 | if x['indicator'] not in wl:
14 | rv.append(x)
15 |
16 | return rv
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/cif/httpd/views/feed/sha256.py:
--------------------------------------------------------------------------------
1 | class Sha256(object):
2 |
3 | def __init__(self):
4 | pass
5 |
6 | def process(self, data, whitelist):
7 | wl = set()
8 | for x in whitelist:
9 | wl.add(x['indicator'])
10 |
11 | rv = []
12 | for x in data:
13 | if x['indicator'] not in wl:
14 | rv.append(x)
15 |
16 | return rv
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/cif/httpd/views/feed/sha512.py:
--------------------------------------------------------------------------------
1 | class Sha512(object):
2 |
3 | def __init__(self):
4 | pass
5 |
6 | def process(self, data, whitelist):
7 | wl = set()
8 | for x in whitelist:
9 | wl.add(x['indicator'])
10 |
11 | rv = []
12 | for x in data:
13 | if x['indicator'] not in wl:
14 | rv.append(x)
15 |
16 | return rv
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/hacking/develop.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | nodaemon = true
3 | loglevel = DEBUG
4 |
5 | [program:cif-router]
6 | command = cif-router -d
7 | autostart = true
8 | stderr_logfile = log/cif-router.log
9 |
10 | [program:cif-httpd]
11 | command = cif-httpd -d
12 | autostart = true
13 | stderr_logfile = log/cif-httpd.log
14 |
15 | #[program:csirtg-smrt]
16 | #command = csirtg-smrt -d
17 | #autostart = true
18 | #stderr_logfile = log/csirtg-smrt.log
19 |
--------------------------------------------------------------------------------
/rules/default/urlhaus_abuse_ch.yml:
--------------------------------------------------------------------------------
1 | parser: csv
2 | defaults:
3 | provider: urlhaus.abuse.ch
4 | tlp: green
5 | altid_tlp: clear
6 | confidence: 9
7 | tags:
8 | - malware
9 | application: https
10 | protocol: tcp
11 | values:
12 | - null
13 | - reporttime
14 | - indicator
15 | - null
16 | - null
17 | - description
18 | - null
19 | feeds:
20 | Malware:
21 | remote: https://urlhaus.abuse.ch/downloads/csv/
--------------------------------------------------------------------------------
/rules/default/mirc.yml:
--------------------------------------------------------------------------------
1 | defaults:
2 | tags: whitelist
3 | provider: mirc.com
4 | protocol: tcp
5 | tlp: green
6 | altid_tlp: clear
7 | confidence: 8
8 | application: irc
9 | remote: http://www.mirc.com/servers.ini
10 | altid: http://www.mirc.com/servers.ini
11 | lasttime: 'month'
12 |
13 | feeds:
14 | domains:
15 | pattern: SERVER:([a-zA-Z0-9-.]+\.[a-z]{2,3}):(\d+[-[\d+,]+):?GROUP
16 | values:
17 | - indicator
18 | - portlist
--------------------------------------------------------------------------------
/rules/default/emergingthreats.yml:
--------------------------------------------------------------------------------
1 | defaults:
2 | provider: emergingthreats.net
3 | confidence: 8
4 | tlp: green
5 | altid_tlp: clear
6 | tags:
7 | - malware
8 | description: 'compromised host'
9 | altid: http://rules.emergingthreats.net/blockrules/compromised-ips.txt
10 |
11 |
12 | feeds:
13 | compromised-ips:
14 | remote: http://rules.emergingthreats.net/blockrules/compromised-ips.txt
15 | pattern: '^(\S+)$'
16 | values:
17 | - indicator
--------------------------------------------------------------------------------
/packaging/debian/control:
--------------------------------------------------------------------------------
1 | Source: bearded-avenger
2 | Section: admin
3 | Priority: optional
4 | Standards-Version: 3.9.3
5 | Maintainer: Wes Young
6 | Build-Depends: cdbs, debhelper (>= 5.0.0)
7 | Homepage: https://github.com/csirtgadgets/bearded-avenger
8 |
9 | Package: bearded-avenger
10 | Architecture: all
11 | Depends: ${misc:Depends}
12 | Description: The smartest way to consume threat intelligence
13 | The smartest way to consume threat intelligence
14 |
--------------------------------------------------------------------------------
/rules/default/torproject_org.yml:
--------------------------------------------------------------------------------
1 | parser: pattern
2 | defaults:
3 | provider: torproject.org
4 | tlp: green
5 | altid_tlp: clear
6 | confidence: 8.5
7 | feeds:
8 | tor_exit_nodes:
9 | remote: https://check.torproject.org/exit-addresses
10 | pattern: '^ExitAddress\s(\S+)\s(\d{4}-\d{2}-\d{2})\s\S+$'
11 | values:
12 | - indicator
13 | - lasttime
14 | defaults:
15 | tags:
16 | - tor
17 | protocol: tcp
18 | description: 'Tor Exit Node'
19 |
--------------------------------------------------------------------------------
/rules/default/sans_edu.yml:
--------------------------------------------------------------------------------
1 | skip: '^Site$'
2 | defaults:
3 | tlp: green
4 | reference_tlp: clear
5 | provider: 'isc.sans.edu'
6 | pattern: '^(.+)$'
7 | values: indicator
8 | tags: suspicious
9 |
10 | feeds:
11 | block:
12 | remote: https://isc.sans.edu/feeds/block.txt
13 | defaults:
14 | confidence: 8
15 | pattern: ^(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)\t\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b\t(\d+)
16 | values:
17 | - indicator
18 | - mask
19 | tags: scanner
20 |
--------------------------------------------------------------------------------
/cif/httpd/views/confidence.py:
--------------------------------------------------------------------------------
1 | from flask import jsonify
2 | from flask.views import MethodView
3 |
4 | CMAP = {
5 | 10: 'Certain',
6 | 9: 'Highly Confident',
7 | 8: 'Very Confident',
8 | 7: 'Confident',
9 | 6: 'Slightly better than a coin flip',
10 | 5: 'Coin Flip',
11 | 4: 'Slightly worse than a coin flip',
12 | 3: 'Not Confident',
13 | 2: 'Unknown',
14 | 1: 'Unknown',
15 | 0: 'Unknown',
16 | }
17 |
18 |
19 | class ConfidenceAPI(MethodView):
20 |
21 | def get(self):
22 | return jsonify(CMAP)
23 |
--------------------------------------------------------------------------------
/rules/default/danger_rules_sk.yml:
--------------------------------------------------------------------------------
1 | parser: pattern
2 | defaults:
3 | provider: 'danger.rulez.sk'
4 | confidence: 9
5 | tlp: green
6 | altid_tlp: clear
7 |
8 | feeds:
9 | ssh:
10 | remote: http://danger.rulez.sk/projects/bruteforceblocker/blist.php
11 | pattern: '^(\S+)[\s|\t]+#\s(\S+\s\S+)'
12 | values:
13 | - indicator
14 | - lasttime
15 | defaults:
16 | application: ssh
17 | protocol: tcp
18 | portlist: 22
19 | tags:
20 | - scanner
21 | - bruteforce
22 | description: scanner
23 |
24 |
--------------------------------------------------------------------------------
/cif/httpd/templates/login.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% include "flash.html" %}
3 |
4 | {% block content %}
5 | Login
6 | {% if error %}Error: {{ error }}{% endif %}
7 |
8 |
14 |
15 |
16 |
17 |
18 | {% endblock %}
--------------------------------------------------------------------------------
/cif/store/sqlite/message.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy import Column, Integer, ForeignKey, UnicodeText
2 | from sqlalchemy.ext.declarative import declarative_base
3 | from sqlalchemy.orm import relationship
4 | from .indicator import Indicator
5 |
6 | Base = declarative_base()
7 |
8 |
9 | class Message(Base):
10 | __tablename__ = 'messages'
11 |
12 | id = Column(Integer, primary_key=True)
13 | message = Column(UnicodeText)
14 |
15 | indicator_id = Column(Integer, ForeignKey('indicators.id', ondelete='CASCADE'))
16 | indicator = relationship(
17 | Indicator,
18 | )
19 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. bearded-avenger documentation master file, created by
2 | sphinx-quickstart on Tue Oct 27 10:20:35 2015.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to bearded-avenger's documentation!
7 | ===========================================
8 |
9 | Contents:
10 |
11 | .. toctree::
12 | :maxdepth: 2
13 |
14 | httpd.rst
15 |
16 | Getting Started
17 | ===============
18 |
19 | .. code-block:: bash
20 |
21 | $ supervisord
22 |
23 |
24 | Indices and tables
25 | ==================
26 |
27 | * :ref:`genindex`
28 | * :ref:`modindex`
29 | * :ref:`search`
30 |
31 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | prune packaging
2 | include .coveragerc
3 | include README.md COPYING LICENSE
4 | include requirements.txt dev_requirements.txt
5 | include Makefile
6 | include VERSION
7 | include MANIFEST.in
8 | include versioneer.py
9 | include 'cif'
10 | include cif/_version.py
11 | include Vagrantfile
12 | include Vagrantfile.centos
13 | include Vagrantfile_es
14 | include Vagrantfile_prod
15 | include Vagrantfile_prod.centos
16 | recursive-include test *
17 | recursive-include deployment *
18 | recursive-include hacking *
19 | recursive-include docs *
20 | recursive-include packaging *
21 | recursive-include rules *
22 | global-exclude *.retry
23 | global-exclude *.pyc
24 | global-exclude __pycache__
25 |
--------------------------------------------------------------------------------
/packaging/docker/supervisord.conf:
--------------------------------------------------------------------------------
1 | [supervisord]
2 | nodaemon = true
3 | loglevel = debug
4 | user = cif
5 | logfile=/var/log/cif/supervisord.log
6 | pidfile=/tmp/supervisord.pid
7 | redirect_stderr = true
8 |
9 | [program:cif-router]
10 | command=cif-router -d
11 | autostart=true
12 | redirect_stderr=true
13 | redirect_stdout = true
14 | logfile=/var/log/cif/cif-router.log
15 |
16 | [program:cif-storage]
17 | command=cif-storage -d
18 | autostart=true
19 | redirect_stderr=true
20 | redirect_stdout = true
21 | logfile=/var/log/cif/cif-storage.log
22 |
23 | [program:cif-http]
24 | command=cif-httpd -d
25 | autostart=true
26 | redirect_stderr=true
27 | redirect_stdout = true
28 | logfile=/var/log/cif/cif-http.log
29 |
--------------------------------------------------------------------------------
/rules/default/cisco_umbrella.yml:
--------------------------------------------------------------------------------
1 | defaults:
2 | description: 'eval("cisco umbrella #{rank}".format(**obs))'
3 | tags: whitelist
4 | protocol: tcp
5 | altid: 'http://s3-us-west-1.amazonaws.com/umbrella-static/index.html'
6 | provider: umbrella.cisco.com
7 | tlp: green
8 | altid_tlp: clear
9 | lasttime: 'month'
10 | values:
11 | - rank
12 | - indicator
13 | confidence: |
14 | eval(max(0, min(
15 | 12.5 - 2.5 * math.ceil(
16 | math.log10(
17 | int(obs['rank'])
18 | )
19 | ),
20 | 10)))
21 |
22 | feeds:
23 | top-1000:
24 | remote: http://s3-us-west-1.amazonaws.com/umbrella-static/top-1m.csv.zip
25 | pattern: '^(\d+),(\S{4,})$'
26 | limit: 1000
--------------------------------------------------------------------------------
/rules/default/tranco.yml:
--------------------------------------------------------------------------------
1 | parser: csv
2 | defaults:
3 | values:
4 | - rank
5 | - indicator
6 | description: 'eval("tranco list #{rank}".format(**obs))'
7 | tags: whitelist
8 | application:
9 | - http
10 | - https
11 | protocol: tcp
12 | altid: 'eval("https://tranco-list.eu/api/ranks/domain/{indicator}".format(**obs))'
13 | provider: tranco-list.eu
14 | tlp: green
15 | altid_tlp: clear
16 | lasttime: 'month'
17 | confidence: |
18 | eval(max(0, min(
19 | 12.5 - 2.5 * math.ceil(
20 | math.log10(
21 | int(obs['rank'])
22 | )
23 | ),
24 | 10)))
25 |
26 | feeds:
27 | top-1000:
28 | remote: https://tranco-list.eu/top-1m.csv.zip
29 | limit: 1000
--------------------------------------------------------------------------------
/test/zadvanced/test_hunter.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from cif.hunter import Hunter
4 | from tornado.ioloop import IOLoop
5 | import threading
6 | import tempfile
7 | import os
8 |
9 | loop = IOLoop()
10 | ADDR = 'ipc://{}'.format(tempfile.NamedTemporaryFile().name)
11 |
12 |
13 | @pytest.mark.skipif(not os.environ.get('CIF_ADVANCED_TESTS'), reason='requires CIF_ADVANCED_TEST to be true')
14 | def test_zadvanced_hunter_start():
15 | with Hunter(loop=loop, remote=ADDR) as h:
16 | h = Hunter(loop=loop, remote=ADDR)
17 |
18 | t = threading.Thread(target=h.start)
19 |
20 | t.start()
21 |
22 | assert t.is_alive()
23 |
24 | loop.stop()
25 |
26 | t.join()
27 |
28 | assert not t.is_alive()
29 |
--------------------------------------------------------------------------------
/rules/default/phishtank.yml:
--------------------------------------------------------------------------------
1 | # https://www.phishtank.com/developer_info.php
2 | # remote: http://data.phishtank.com/data//online-valid.json.gz
3 | parser: json
4 | token:
5 | remote: http://data.phishtank.com/data/{token}/online-valid.json.gz
6 | defaults:
7 | provider: phishtank.com
8 | tlp: green
9 | altid_tlp: clear
10 | application:
11 | - http
12 | - https
13 | confidence: 9
14 | tags: phishing
15 | protocol: tcp
16 |
17 | feeds:
18 | urls:
19 | itype: url
20 | map:
21 | - submission_time
22 | - url
23 | - target
24 | - phish_detail_url
25 | - details
26 | values:
27 | - lasttime
28 | - indicator
29 | - description
30 | - altid
31 | - additional_data
32 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | setuptools
2 | cython>=0.2
3 | pyzmq>=23.2.1
4 | csirtg_indicator>=1.0.1,<2.0
5 | cifsdk>=3.0.0rc4,<4.0
6 | Flask-Limiter>=0.9.4,<=2.7.0
7 | limits>=1.1.1,<=2.7.1
8 | maxminddb>=2.2.0
9 | geoip2>=2.8.0,<2.9
10 | dnspython>=1.15.0,<=2.2.1
11 | Flask>=1.0
12 | flask-cors>=3.0,<4.0
13 | PyYAML>=4.2b1
14 | SQLAlchemy>=1.4.41
15 | elasticsearch>=5.3,<5.5
16 | elasticsearch-dsl>=5.3,<5.5
17 | html5lib==1.0b8 # bug in csirtg-smrt upstream
18 | msgpack-python>=0.4.8,<0.5.0
19 | apwgsdk==0.0.0a6
20 | csirtg_smrt>=1.0,<2.0
21 | csirtg_dnsdb==0.0.0a4
22 | tornado>=5.1.0
23 | faker==0.7.10
24 | Flask-Bootstrap==3.3.6.0
25 | gevent>=21.12.0
26 | gunicorn==20.1.0
27 | urllib3>=1.26.5
28 | requests>=2.27.1
29 | ujson<=5.5.0
30 |
31 | nltk>=3.6.6 # not directly required, pinned by Snyk to avoid a vulnerability
--------------------------------------------------------------------------------
/packaging/pyinstaller/cif.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python -*-
2 |
3 | name = 'cif'
4 |
5 | block_cipher = None
6 |
7 | a = Analysis(['cifsdk/client/__init__.py'],
8 | binaries=None,
9 | datas=None,
10 | hiddenimports=[],
11 | hookspath=None,
12 | runtime_hooks=None,
13 | excludes=None,
14 | win_no_prefer_redirects=None,
15 | win_private_assemblies=None,
16 | cipher=block_cipher)
17 | pyz = PYZ(a.pure, a.zipped_data,
18 | cipher=block_cipher)
19 | exe = EXE(pyz,
20 | a.scripts,
21 | a.binaries,
22 | a.zipfiles,
23 | a.datas,
24 | name=name,
25 | debug=False,
26 | strip=None,
27 | upx=True,
28 | console=True )
--------------------------------------------------------------------------------
/rules/default/bambenek.yml:
--------------------------------------------------------------------------------
1 | # This is for the open source feeds from Bambenek Consulting
2 | parser: csv
3 |
4 | defaults:
5 | provider: osint.bambenekconsulting.com
6 | tlp: clear
7 | altid_tlp: clear
8 | confidence: 8
9 | tags: botnet
10 | values:
11 | - indicator
12 | - description
13 | - lasttime
14 | - altid
15 |
16 | feeds:
17 | c2_ipmasterlist_high:
18 | remote: http://osint.bambenekconsulting.com/feeds/c2-ipmasterlist-high.txt
19 |
20 | c2_domain_masterlist_high:
21 | remote: http://osint.bambenekconsulting.com/feeds/c2-dommasterlist-high.txt
22 |
23 | dga_domains_high:
24 | remote: http://osint.bambenekconsulting.com/feeds/dga-feed-high.csv.gz
25 | cache: dga-feed-high.csv
26 | defaults:
27 | tags:
28 | - dga
29 | - botnet
--------------------------------------------------------------------------------
/packaging/pyinstaller/cif-router.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python -*-
2 |
3 | name = 'cif-router'
4 |
5 | block_cipher = None
6 |
7 | a = Analysis(['cif/router.py'],
8 | binaries=None,
9 | datas=None,
10 | hiddenimports=[],
11 | hookspath=None,
12 | runtime_hooks=None,
13 | excludes=None,
14 | win_no_prefer_redirects=None,
15 | win_private_assemblies=None,
16 | cipher=block_cipher)
17 | pyz = PYZ(a.pure, a.zipped_data,
18 | cipher=block_cipher)
19 | exe = EXE(pyz,
20 | a.scripts,
21 | a.binaries,
22 | a.zipfiles,
23 | a.datas,
24 | name=name,
25 | debug=False,
26 | strip=None,
27 | upx=True,
28 | console=True )
--------------------------------------------------------------------------------
/packaging/pyinstaller/cif-httpd.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python -*-
2 |
3 | name = 'cif-httpd'
4 |
5 | block_cipher = None
6 |
7 | a = Analysis(['cif/httpd/__init__.py'],
8 | binaries=None,
9 | datas=None,
10 | hiddenimports=[],
11 | hookspath=None,
12 | runtime_hooks=None,
13 | excludes=None,
14 | win_no_prefer_redirects=None,
15 | win_private_assemblies=None,
16 | cipher=block_cipher)
17 | pyz = PYZ(a.pure, a.zipped_data,
18 | cipher=block_cipher)
19 | exe = EXE(pyz,
20 | a.scripts,
21 | a.binaries,
22 | a.zipfiles,
23 | a.datas,
24 | name=name,
25 | debug=False,
26 | strip=None,
27 | upx=True,
28 | console=True )
--------------------------------------------------------------------------------
/rules/default/majestic.yml:
--------------------------------------------------------------------------------
1 | parser: csv
2 | defaults:
3 | values:
4 | - rank
5 | - null
6 | - indicator
7 | description: 'eval("majestic million #{rank}".format(**obs))'
8 | tags: whitelist
9 | application:
10 | - http
11 | - https
12 | protocol: tcp
13 | altid: 'eval("https://majestic.com/reports/majestic-million?domain={indicator}".format(**obs))'
14 | provider: majestic.com
15 | tlp: green
16 | altid_tlp: clear
17 | lasttime: 'month'
18 | confidence: |
19 | eval(max(0, min(
20 | 12.5 - 2.5 * math.ceil(
21 | math.log10(
22 | int(obs['rank'])
23 | )
24 | ),
25 | 10)))
26 |
27 | feeds:
28 | top-1000:
29 | remote: https://downloads.majesticseo.com/majestic_million.csv
30 | skip_first: true
31 | limit: 1000
--------------------------------------------------------------------------------
/packaging/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:2.7.10
2 | MAINTAINER Wes Young (wes@csirtgadgets.org)
3 |
4 | ENV NEWUSER cif
5 | RUN useradd -m $NEWUSER
6 |
7 | RUN pip install pyzmq --install-option="--zmq=bundled"
8 | RUN pip install git+https://github.com/csirtgadgets/py-whiteface-sdk.git
9 | RUN pip install git+https://github.com/csirtgadgets/bearded-avenger.git
10 |
11 | VOLUME /var/lib
12 |
13 | RUN for path in \
14 | /var/lib/cif/cache \
15 | /var/lib/cif/rules \
16 | /var/log/cif \
17 | ; do \
18 | mkdir -p $path; \
19 | chown cif:cif "$path"; \
20 | done
21 |
22 | VOLUME /var/log/cif
23 | VOLUME /var/lib/cif/rules
24 | VOLUME /var/lib/cif/cache
25 |
26 | COPY supervisord.conf /etc/supervisord.conf
27 |
28 | EXPOSE 5000
29 |
30 | CMD ["supervisord", "-c", "/etc/supervisord.conf"]
31 |
--------------------------------------------------------------------------------
/packaging/pyinstaller/csirtg-smrt.spec:
--------------------------------------------------------------------------------
1 | # -*- mode: python -*-
2 |
3 | name = 'csirtg-smrt'
4 |
5 | block_cipher = None
6 |
7 | a = Analysis(['csirtg_smrt/__init__.py'],
8 | binaries=None,
9 | datas=None,
10 | hiddenimports=[],
11 | hookspath=None,
12 | runtime_hooks=None,
13 | excludes=None,
14 | win_no_prefer_redirects=None,
15 | win_private_assemblies=None,
16 | cipher=block_cipher)
17 | pyz = PYZ(a.pure, a.zipped_data,
18 | cipher=block_cipher)
19 | exe = EXE(pyz,
20 | a.scripts,
21 | a.binaries,
22 | a.zipfiles,
23 | a.datas,
24 | name=name,
25 | debug=False,
26 | strip=None,
27 | upx=True,
28 | console=True )
--------------------------------------------------------------------------------
/packaging/docker/Dockerfile.base:
--------------------------------------------------------------------------------
1 | FROM python:2.7.10
2 | MAINTAINER Wes Young (wes@csirtgadgets.org)
3 |
4 | ENV NEWUSER cif
5 | RUN useradd -m $NEWUSER
6 |
7 | RUN pip install pyzmq --install-option="--zmq=bundled"
8 | RUN pip install git+https://github.com/csirtgadgets/py-whiteface-sdk.git
9 | RUN pip install git+https://github.com/csirtgadgets/bearded-avenger.git
10 |
11 | VOLUME /var/lib
12 |
13 | RUN for path in \
14 | /var/lib/cif/cache \
15 | /var/lib/cif/rules \
16 | /var/log/cif \
17 | ; do \
18 | mkdir -p $path; \
19 | chown cif:cif "$path"; \
20 | done
21 |
22 | VOLUME /var/log/cif
23 | VOLUME /var/lib/cif/rules
24 | VOLUME /var/lib/cif/cache
25 |
26 | COPY supervisord.conf /etc/supervisord.conf
27 |
28 | EXPOSE 5000
29 |
30 | CMD ["supervisord", "-c", "/etc/supervisord.conf"]
31 |
--------------------------------------------------------------------------------
/cif/httpd/views/feed/email.py:
--------------------------------------------------------------------------------
1 | PERM_WHITELIST = []
2 |
3 |
4 | class Email(object):
5 |
6 | def __init__(self):
7 | self.wl = set()
8 | for w in PERM_WHITELIST:
9 | self.wl.add(w)
10 |
11 | def match_whitelist(self, wl, d):
12 | bits = d.split('.')
13 |
14 | for i, b in enumerate(bits):
15 | if '.'.join(bits) in wl:
16 | return True
17 | bits.pop(0)
18 |
19 | # https://github.com/jsommers/pytricia
20 | def process(self, data, whitelist):
21 |
22 | wl = self.wl
23 |
24 | for w in whitelist:
25 | wl.add(w['indicator'])
26 |
27 | rv = []
28 | for x in data:
29 | if not self.match_whitelist(wl, x['indicator']):
30 | rv.append(x)
31 |
32 | return rv
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/cif/httpd/views/feed/ipv6.py:
--------------------------------------------------------------------------------
1 | import pytricia
2 | import logging
3 |
4 | PERM_WHITELIST = [
5 | ## TODO -- more
6 | # http://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xhtml
7 | # v6
8 | 'FF01:0:0:0:0:0:0:1',
9 | 'FF01:0:0:0:0:0:0:2',
10 | ]
11 |
12 |
13 | class Ipv6(object):
14 |
15 | def __init__(self):
16 | self.logger = logging.getLogger(__name__)
17 | pass
18 |
19 | def process(self, data, whitelist=[]):
20 | wl = pytricia.PyTricia(128)
21 |
22 | [wl.insert(x, True) for x in PERM_WHITELIST]
23 |
24 | [wl.insert(str(y['indicator']), True) for y in whitelist]
25 |
26 | rv = []
27 | for y in data:
28 | if str(y['indicator']) not in wl:
29 | rv.append(y)
30 |
31 | return rv
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/test/zadvanced/test_router.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import threading
3 | from cif.router import Router
4 | from cif.constants import ROUTER_ADDR
5 | from tornado.ioloop import IOLoop
6 | import tempfile
7 |
8 | loop = IOLoop()
9 |
10 | ROUTER_ADDR = 'ipc://{}'.format(tempfile.NamedTemporaryFile().name)
11 |
12 |
13 | def _router_start():
14 | r = Router(listen=ROUTER_ADDR)
15 | global thread
16 | thread = threading.Thread(target=r.run, args=[loop])
17 | thread.start()
18 | return True
19 |
20 |
21 | def _router_stop():
22 | global thread
23 | loop.stop()
24 | thread.join()
25 |
26 |
27 | @pytest.fixture
28 | def router():
29 | yield _router_start()
30 | _router_stop()
31 |
32 |
33 | @pytest.fixture
34 | def client():
35 | from cif.client.zeromq import ZMQ as Client
36 |
37 | yield Client(ROUTER_ADDR, '1234')
38 |
--------------------------------------------------------------------------------
/rules/default/feodotracker.yml:
--------------------------------------------------------------------------------
1 | defaults:
2 | provider: feodotracker.abuse.ch
3 | tlp: green
4 | altid_tlp: clear
5 | altid: https://feodotracker.abuse.ch/host/
6 | description: feodo
7 |
8 | feeds:
9 | c2:
10 | confidence: 8
11 | remote: https://feodotracker.abuse.ch/downloads/ipblocklist.csv
12 | pattern: ^(\S+\s\S+),(\S+),(\S+),(\S+)$
13 | values:
14 | - firsttime
15 | - indicator
16 | - null
17 | - null
18 | defaults:
19 | tags:
20 | - feodo
21 | - botnet
22 | - c2
23 |
24 | hashes:
25 | confidence: 8
26 | remote: https://feodotracker.abuse.ch/downloads/malware_hashes.csv
27 | pattern: ^(\S+\s\S+),(\S+),(\S+)$
28 | values:
29 | - firsttime
30 | - indicator
31 | - null
32 | defaults:
33 | tags:
34 | - feodo
35 | - botnet
--------------------------------------------------------------------------------
/rules/default/spamhaus.yml:
--------------------------------------------------------------------------------
1 | defaults:
2 | provider: spamhaus.org
3 | confidence: 9
4 | tlp: green
5 | reference_tlp: clear
6 | tags:
7 | - hijacked
8 | reference: http://www.spamhaus.org/sbl/sbl.lasso?query=
9 | pattern: '(.+)\s;\s(.+)'
10 | values:
11 | - indicator
12 | - reference
13 | lasttime: 'month'
14 |
15 | feeds:
16 | drop:
17 | remote: http://www.spamhaus.org/drop/drop.txt
18 |
19 | edrop:
20 | remote: http://www.spamhaus.org/drop/edrop.txt
21 |
22 | dropv6:
23 | remote: https://www.spamhaus.org/drop/dropv6.txt
24 |
25 | # https://github.com/csirtgadgets/csirtg-smrt-py/issues/230
26 | asndrop:
27 | parser: pattern
28 | remote: https://www.spamhaus.org/drop/asndrop.txt
29 | pattern: '^(\S+) ; ([\S+]{2}) \| ([^\n]+)$'
30 | values:
31 | - indicator
32 | - cc
33 | - asn_desc
34 |
--------------------------------------------------------------------------------
/packaging/rpm/cif.spec:
--------------------------------------------------------------------------------
1 | %define name bearded-avenger
2 | %define _version $VERSION
3 |
4 | Name: %{name}
5 | Version: %{_version}
6 | Release: 1%{?dist}
7 | Url: https://github.com/csirtgadgets/bearded-avenger
8 | Summary: The smartest way to consume threat intelligence.
9 | License: GPLv3
10 | Group: Development/Libraries
11 | Source: https://github.com/csirtgadgets/bearded-avenger/archive/%{version}.tar.gz
12 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
13 |
14 | BuildArch: noarch
15 |
16 | %description
17 |
18 | The smartest way to consume threat intelligence.
19 |
20 | %prep
21 | %setup -q
22 |
23 | %build
24 | echo "nothing to build"
25 |
26 | %install
27 | cp -a cif* /usr/bin/
28 |
29 | %clean
30 | rm -rf %{buildroot}
31 |
32 | %files
33 | %defattr(-,root,root)
34 |
35 | %changelog
36 |
37 | * 2015-09-28 - 3.0.0-1
38 | - Release of 3.0.0a1
--------------------------------------------------------------------------------
/rules/default/sslbl_abuse_ch.yml:
--------------------------------------------------------------------------------
1 | parser: csv
2 | defaults:
3 | provider: sslbl.abuse.ch
4 | tlp: green
5 | altid_tlp: clear
6 | confidence: 10
7 | tags: botnet
8 | application: https
9 | protocol: tcp
10 |
11 | feeds:
12 | sslipblacklist:
13 | remote: https://sslbl.abuse.ch/blacklist/sslipblacklist.csv
14 | defaults:
15 | values:
16 | - indicator
17 | - portlist
18 | - description
19 |
20 | dyre_sslipblacklist:
21 | remote: https://sslbl.abuse.ch/blacklist/dyre_sslipblacklist.csv
22 | defaults:
23 | values:
24 | - indicator
25 | - portlist
26 | - description
27 |
28 | ssl_fingerprints:
29 | remote: https://sslbl.abuse.ch/blacklist/sslblacklist.csv
30 | defaults:
31 | tags:
32 | - ssl
33 | - blacklist
34 | values:
35 | - lasttime
36 | - indicator
37 | - description
38 |
--------------------------------------------------------------------------------
/.github/issue_template.md:
--------------------------------------------------------------------------------
1 | # Are you getting value from the project? Have you donated to the project?
2 |
3 | https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YZPQXDLNYZZ3W
4 |
5 | # Did you check the FAQ https://github.com/csirtgadgets/bearded-avenger-deploymentkit/wiki/FAQ ?
6 |
7 | # Are you running with hunters enabled? If so, does turning them off resolve the problem?
8 |
9 | # Expected behavior and actual behavior.
10 |
11 | # Steps to reporduce the problem
12 |
13 | # Relevant logs as a result of the actual behavior
14 | # https://github.com/csirtgadgets/bearded-avenger-deploymentkit/wiki/FAQ#searching-logs
15 |
16 | # Did you attempt to fix the problem and submit a pull request?
17 |
18 | # Specifications like the version of the project, operating system, or hardware.
19 |
20 | # Does adding additional memory to the box resolve the problem?
21 |
22 | # How large is your /var/lib/cif.sqlite database?
23 |
--------------------------------------------------------------------------------
/test/test_gatherer_geo.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from cif.gatherer.geo import Geo
3 | from csirtg_indicator import Indicator
4 | from pprint import pprint
5 |
6 | data = {
7 | 'cc': 'US',
8 | 'city': 'Chesterfield'
9 | }
10 |
11 |
12 | def test_gatherer_geo_v4():
13 | a = Geo()
14 |
15 | def _resolve(i):
16 | i.cc = data['cc']
17 | i.city = data['city']
18 |
19 | a._resolve = _resolve
20 |
21 | i = Indicator(indicator='216.90.108.0')
22 |
23 | a.process(i)
24 |
25 | assert i.cc == data['cc']
26 | assert i.city == data['city']
27 |
28 |
29 | def test_gatherer_geo_v6():
30 | a = Geo()
31 |
32 | def _resolve(i):
33 | i.cc = data['cc']
34 | i.city = data['city']
35 |
36 | a._resolve = _resolve
37 |
38 | i = Indicator(indicator='2607:ff10::c0:1:1:10d')
39 |
40 | a.process(i)
41 |
42 | assert i.cc == data['cc']
43 | assert i.city == data['city']
44 |
--------------------------------------------------------------------------------
/rules/default/stopforumspam.yml:
--------------------------------------------------------------------------------
1 | defaults:
2 | confidence: 7
3 | tlp: green
4 | altid_tlp: clear
5 | provider: stopforumspam.com
6 |
7 | feeds:
8 | ip_list:
9 | remote: 'http://stopforumspam.com/downloads/listed_ip_1_all.zip'
10 | pattern: '^\"(\S+)\",\"(\S+)\",\"(\S+\s\S+)\"$'
11 | values:
12 | - indicator
13 | - null
14 | - lasttime
15 | defaults:
16 | tags:
17 | - spam
18 |
19 | domain-list:
20 | remote: http://stopforumspam.com/downloads/toxic_domains_whole_filtered_10000.txt
21 | pattern: '^(\S+)$'
22 | values:
23 | - indicator
24 | defaults:
25 | tags:
26 | - spam
27 |
28 | mail_list:
29 | remote: 'http://stopforumspam.com/downloads/listed_email_1_all.zip'
30 | pattern: '^\"(\S+)\",\"(\S+)\",\"(\S+\s\S+)\"$'
31 | values:
32 | - indicator
33 | - null
34 | - lasttime
35 | defaults:
36 | tags:
37 | - spam
--------------------------------------------------------------------------------
/test/test_store.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import os
3 | import tempfile
4 | from argparse import Namespace
5 | import pytest
6 | from cif.store import Store
7 | from cifsdk.utils import setup_logging
8 | import arrow
9 |
10 | args = Namespace(debug=True, verbose=None)
11 | setup_logging(args)
12 |
13 | logger = logging.getLogger(__name__)
14 |
15 |
16 | @pytest.fixture
17 | def store():
18 | dbfile = tempfile.mktemp()
19 | with Store(store_type='sqlite', dbfile=dbfile) as s:
20 | s._load_plugin(dbfile=dbfile)
21 | yield s
22 |
23 | if os.path.isfile(dbfile):
24 | os.unlink(dbfile)
25 |
26 |
27 | @pytest.fixture
28 | def indicator():
29 | return {
30 | 'indicator': 'example.com',
31 | 'tags': 'botnet',
32 | 'provider': 'csirtgadgets.org',
33 | 'group': 'everyone',
34 | 'lasttime': arrow.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
35 | 'itype': 'fqdn',
36 | }
37 |
--------------------------------------------------------------------------------
/test/test_peers.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from cif.gatherer.peers import Peer
3 | from csirtg_indicator import Indicator
4 | from pprint import pprint
5 | import warnings
6 | import os
7 |
8 | DISABLE_TESTS = True
9 | if os.environ.get('CIF_GATHERER_PEERS_TEST'):
10 | if os.environ['CIF_GATHERER_PEERS_TEST'] == '1':
11 | DISABLE_TESTS = False
12 |
13 | os.environ['CIF_GATHERERS_PEERS_ENABLED'] = '1'
14 |
15 | data = [
16 | '701 1239 3549 3561 7132 | 216.90.108.0/24 | US | arin | 1998-09-25',
17 | ]
18 |
19 | @pytest.mark.skipif(DISABLE_TESTS, reason='need to set CIF_GATHERER_PEERS_TEST=1 to run')
20 | def test_gatherer_peers():
21 | p = Peer()
22 |
23 | def _resolve(i):
24 | return data
25 |
26 | p._resolve_ns = _resolve
27 | x = p.process(Indicator(indicator='216.90.108.0'))
28 |
29 | if x.peers:
30 | for pp in x.peers:
31 | assert 65535 > int(pp['asn']) > 1
32 | else:
33 | warnings.warn('TC Not Responding...', UserWarning)
34 |
35 |
--------------------------------------------------------------------------------
/test/test_gatherer_peer.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from cif.gatherer.peers import Peer
3 | from csirtg_indicator import Indicator
4 | import warnings
5 | from pprint import pprint
6 | import os
7 |
8 | DISABLE_TESTS = True
9 | if os.environ.get('CIF_GATHERER_PEERS_TEST'):
10 | if os.environ['CIF_GATHERER_PEERS_TEST'] == '1':
11 | DISABLE_TESTS = False
12 |
13 | os.environ['CIF_GATHERERS_PEERS_ENABLED'] = '1'
14 |
15 | data = [
16 | '23028 | 216.90.108.0/24 | US | arin | 1998-09-25',
17 | '701 1239 3549 3561 7132 | 216.90.108.0/24 | US | arin | 1998-09-25',
18 | ]
19 |
20 | @pytest.mark.skipif(DISABLE_TESTS, reason='need to set CIF_GATHERER_PEERS_TEST=1 to run')
21 | def test_gatherer_peer():
22 | a = Peer()
23 |
24 | def _resolve(i):
25 | return data
26 |
27 | a._resolve_ns = _resolve
28 | x = a.process(Indicator(indicator='216.90.108.0'))
29 |
30 | if x.peers:
31 | assert 65535 > int(x.peers[0]['asn']) > 1
32 | else:
33 | warnings.warn('TC Not Responding...', UserWarning)
--------------------------------------------------------------------------------
/cif/auth/cif_store/__init__.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import os
3 |
4 | from cif.auth.plugin import Auth
5 | from cif.store import Store
6 | from cif.utils import strtobool
7 |
8 | STORE_DEFAULT = os.environ.get('CIF_STORE_STORE', 'sqlite')
9 | STORE_NODES = os.getenv('CIF_STORE_NODES')
10 |
11 | TRACE = strtobool(os.environ.get('CIF_AUTH_CIFSTORE_TRACE', True))
12 |
13 | logger = logging.getLogger(__name__)
14 | logger.setLevel(logging.ERROR)
15 |
16 | if TRACE:
17 | logger.setLevel(logging.DEBUG)
18 |
19 | class CifStore(Auth):
20 |
21 | name = 'cif_store'
22 |
23 | def __init__(self, **kwargs):
24 | self.token_cache = kwargs.get('token_cache', {})
25 | self.store = Store(store_type=STORE_DEFAULT, nodes=STORE_NODES)
26 | self.store._load_plugin(store_type=STORE_DEFAULT,
27 | nodes=STORE_NODES, token_cache=self.token_cache)
28 |
29 | def handle_token_search(self, token, **kwargs):
30 | return self.store.store.tokens.auth_search({'token': token})
31 |
32 | Plugin = CifStore
33 |
--------------------------------------------------------------------------------
/Vagrantfile_blank:
--------------------------------------------------------------------------------
1 | #e -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
5 | VAGRANTFILE_API_VERSION = "2"
6 | VAGRANTFILE_LOCAL = 'Vagrantfile.local'
7 |
8 | unless File.directory?('deploymentkit')
9 | puts "Please unzip the latest release of the deploymentkit before continuing..."
10 | puts ""
11 | puts "https://github.com/csirtgadgets/bearded-avenger-deploymentkit/wiki"
12 | puts ""
13 | exit
14 | end
15 |
16 | $script = <
17 | {%- endblock styles %}
18 | {%- endblock head %}
19 |
20 |
21 | {% block body -%}
22 |
23 |
24 | {% block navbar %}
25 | {%- endblock navbar %}
26 |
27 |
28 |
29 |
30 |
31 | {% block content -%}
32 | {%- endblock content %}
33 |
34 |
35 |
36 |
37 |
38 | {% block scripts %}
39 | {%- endblock scripts %}
40 |
41 | {%- endblock body %}
42 |
43 | {%- endblock html %}
44 |
45 |