35 |
36 |
37 |
38 |
39 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/client/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | setup(name='tryzeek',
4 | version='0.2.0',
5 | zip_safe=True,
6 | py_modules = ["tryzeek"],
7 | install_requires='requests',
8 | entry_points = {
9 | 'console_scripts': [
10 | 'tryzeek = tryzeek:main',
11 | ]
12 | }
13 | )
14 |
--------------------------------------------------------------------------------
/client/tryzeek.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from optparse import OptionParser
3 | import json
4 | import os
5 | import requests
6 | import sys
7 | import time
8 | import hashlib
9 |
10 | DEFAULT_HOST="https://try.zeek.org/"
11 | HOST = os.getenv("TRYBRO_HOST", DEFAULT_HOST)
12 |
13 | DEFAULT_VERSION="3.0.0"
14 |
15 | def md5(s):
16 | m = hashlib.md5()
17 | m.update(s)
18 | return m.hexdigest()
19 |
20 | def read_file(fn):
21 | with open(fn) as f:
22 | return f.read()
23 |
24 | def run_code(files, version=DEFAULT_VERSION, pcap=None):
25 | main, rest = files[0], files[1:]
26 | sources = [
27 | {"name": "main.zeek", "content": read_file(main)}
28 | ]
29 |
30 | for fn in rest:
31 | sources.append({"name": fn, "content": read_file(fn)})
32 |
33 | req = {
34 | "sources": sources,
35 | "version": version,
36 | "pcap": pcap,
37 | }
38 | data = json.dumps(req)
39 | headers = {'Content-type': 'application/json'}
40 | res = requests.post(HOST + "run", data=data, headers=headers).json()
41 | return res
42 |
43 | def maybe_upload_pcap(pcap):
44 | with open(pcap, 'rb') as f:
45 | contents = f.read()
46 | checksum = md5(contents)
47 |
48 | exists = requests.get(HOST + "pcap/" + checksum).json()["status"]
49 | if not exists:
50 | files = {'pcap': ('file.pcap', contents) }
51 | status = requests.post(HOST + "pcap/upload/" + checksum, files=files).json()['status']
52 | assert status
53 |
54 | return checksum
55 |
56 | def get_files(job):
57 | res = requests.get(HOST + "files/" + job)
58 | file_output = res.json()['files']
59 | for fn, data in file_output.items():
60 | if fn == "stdout.log" or not data: continue
61 | if fn == "stderr.log":
62 | sys.stderr.write(data)
63 | continue
64 | with open(fn, 'w') as f:
65 | f.write(data)
66 |
67 | def run(files, version=DEFAULT_VERSION, pcap=None, link=False):
68 | if pcap:
69 | pcap = maybe_upload_pcap(pcap)
70 | res = run_code(files, version, pcap=pcap)
71 | if link:
72 | sys.stdout.write("http://try.zeek.org/#/trybro/saved/%s\n\n" % res['job'])
73 | sys.stdout.write(res['stdout'])
74 | get_files(res["job"])
75 |
76 | def main():
77 | parser = OptionParser()
78 | parser.add_option("-r", "--readfile", dest="pcap", help="read from given tcpdump file", action="store")
79 | parser.add_option("-l", "--link", dest="link", help="Output sharable link", action="store_true")
80 | parser.add_option("-V", "--bro-version", dest="version", help="Select bro version", action="store", default=DEFAULT_VERSION)
81 | (options, args) = parser.parse_args()
82 |
83 | files = args
84 | run(files, version=options.version, pcap=options.pcap, link=options.link)
85 |
86 | if __name__ == "__main__":
87 | main()
88 |
--------------------------------------------------------------------------------
/client/tryzeek_embed.js:
--------------------------------------------------------------------------------
1 | $.fn.tryzeek = function() {
2 | this.prop("contenteditable", true);
3 | this.wrap("")
4 | this.after(" ");
5 | $(".zeek_example button").click(function() {
6 | var code = $(this).parent().find(".zeek_source").text()
7 | var res = $(this).parent().find(".zeek_result");
8 | res.text("running...");
9 | $.post("https://try.zeek.org/run_simple", {code: code}, function(data) {
10 | var out = data.files['stdout.log'];
11 | var err = data.files['stderr.log'];
12 | if(err) {
13 | res.text(err + "\n" + out);
14 | } else {
15 | res.text(out);
16 | }
17 | }, 'json');
18 | });
19 | return this;
20 | };
21 |
--------------------------------------------------------------------------------
/containers/caddy/Caddyfile.notls:
--------------------------------------------------------------------------------
1 | {
2 | auto_https off
3 | }
4 |
5 | :80 {
6 | reverse_proxy {
7 | to api:8000
8 | }
9 | header -Server
10 |
11 | log {
12 | output stdout
13 | format console
14 | }
15 | encode gzip
16 | }
17 |
--------------------------------------------------------------------------------
/containers/caddy/Caddyfile.tls:
--------------------------------------------------------------------------------
1 | {
2 | on_demand_tls {
3 | interval 1d
4 | burst 5
5 | }
6 | }
7 |
8 | {$SITE_ADDRESS} {
9 | reverse_proxy {
10 | to api:8000
11 | }
12 | header -Server
13 |
14 | log {
15 | output stdout
16 | format console
17 | }
18 | encode gzip
19 | }
20 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | redis:
4 | image: redis
5 | restart: always
6 | networks:
7 | - backend
8 | volumes:
9 | - ${TRYZEEK_DATA:-./tryzeek_data}:/data
10 |
11 | worker:
12 | build: manager
13 | command: rq worker --with-scheduler --url redis://redis
14 | volumes:
15 | - /var/run/docker.sock:/var/run/docker.sock
16 | - /brostuff:/brostuff
17 | restart: always
18 | deploy:
19 | replicas: 5
20 | depends_on:
21 | - redis
22 | networks:
23 | - backend
24 |
25 | version-updater:
26 | build: manager
27 | command: python3 version.py -i 4020
28 | init: true
29 | volumes:
30 | - /var/run/docker.sock:/var/run/docker.sock
31 | restart: always
32 | depends_on:
33 | - redis
34 | networks:
35 | - backend
36 |
37 | api:
38 | build: manager
39 | command: gunicorn -w 4 -b 0.0.0.0 app:app --log-file - --max-requests 500 --timeout 20
40 | restart: always
41 | depends_on:
42 | - redis
43 | networks:
44 | - backend
45 | - frontend
46 |
47 | proxy:
48 | image: caddy
49 | restart: always
50 | environment:
51 | - ACME_AGREE=true
52 | - ENABLE_TELEMETRY=false
53 | - SITE_ADDRESS=${SITE_ADDRESS:-try.zeek.org:443, try.bro.org:443}
54 | volumes:
55 | - $HOME/.caddy:/data
56 | - ./containers/caddy/Caddyfile.${CADDY-tls}:/etc/caddy/Caddyfile
57 | networks:
58 | - frontend
59 | ports:
60 | - "80:80/tcp"
61 | - "443:443/tcp"
62 |
63 | networks:
64 | backend:
65 | frontend:
66 |
--------------------------------------------------------------------------------
/manager/.dockerignore:
--------------------------------------------------------------------------------
1 | web-ui/node_modules
2 |
--------------------------------------------------------------------------------
/manager/Dockerfile:
--------------------------------------------------------------------------------
1 | # tryzeek
2 | #
3 | # VERSION 0.3
4 |
5 | FROM node:22.12 AS web-builder
6 | ADD web-ui/package.json web-ui/
7 | ADD web-ui/package-lock.json web-ui/
8 | RUN cd web-ui && npm install
9 | ADD web-ui web-ui
10 | RUN make -C web-ui
11 |
12 | FROM debian:bookworm-slim
13 | LABEL org.opencontainers.image.authors="Justin Azoff "
14 |
15 | RUN apt-get update && \
16 | apt-get dist-upgrade -yq && \
17 | apt-get install -yq python3-pip python3-dev rsync && \
18 | rm /var/lib/apt/lists/*list -vf && \
19 | true
20 |
21 | RUN mkdir /brostuff
22 |
23 | ADD requirements.txt requirements.txt
24 | RUN pip3 install --break-system-packages -r requirements.txt
25 |
26 | ADD . /src
27 | WORKDIR /src
28 |
29 | # Add the webpack output to the web root
30 | COPY --from=web-builder web-ui/build/ web-ui-build
31 | RUN cp web-ui-build/*.* static/
32 | RUN rsync -avP web-ui-build/static/ static/
33 |
34 | RUN cd static/examples && ./pack.py
35 |
--------------------------------------------------------------------------------
/manager/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template, request, redirect, make_response
2 | from flask_jsonpify import jsonify
3 | import glob
4 | import hashlib
5 | import os
6 |
7 | import backend
8 | import metrics
9 | from format import fmt
10 |
11 | class FlaskStaticCors(Flask):
12 | def send_static_file(self, filename):
13 | response = super(FlaskStaticCors, self).send_static_file(filename)
14 | response.headers['Access-Control-Allow-Origin'] = '*'
15 | return response
16 |
17 | app = FlaskStaticCors(__name__)
18 |
19 | @app.route('/favicon.ico')
20 | def favicon():
21 | return app.send_static_file("favicon.ico")
22 |
23 | @app.route('/mode-zeek.js')
24 | def zeek_mode():
25 | return app.send_static_file("mode-zeek.js")
26 |
27 | @app.route("/")
28 | def index():
29 | return app.send_static_file("index.html")
30 |
31 | @app.route("/metrics")
32 | def bro_metrics():
33 | return render_template('metrics.html', metrics=metrics.get())
34 |
35 | @app.route("/metrics.json")
36 | def bro_metrics_json():
37 | return cors_jsonify(**metrics.get())
38 |
39 | @app.route("/saved/")
40 | def saved(job):
41 | return corsify(make_response(backend.get_saved(job)))
42 |
43 | @app.route("/run", methods=['OPTIONS'])
44 | def run_options_for_cors():
45 | return cors_jsonify(ok="ok")
46 |
47 | @app.route("/run", methods=['POST'])
48 | def run():
49 | sources = request.json.get('sources', '')
50 | pcap = request.json.get('pcap', '')
51 | version = request.json.get('version', '')
52 | if pcap and '--' in pcap:
53 | pcap = None
54 |
55 | job_id, stdout = backend.run_code(sources, pcap=pcap, version=version)
56 | return cors_jsonify(job=job_id, stdout=stdout)
57 |
58 | @app.route("/run_simple", methods=['GET', 'POST'])
59 | def run_simple():
60 | stdin = request.args.get("code") or request.form.get("code") or 'print "Huh?";'
61 | version = request.args.get("version") or request.form.get("version")
62 |
63 | files = backend.run_code_simple(stdin, version=version)
64 | return cors_jsonify(files=files)
65 |
66 | @app.route("/stdout/")
67 | def stdout(job):
68 | txt = backend.get_stdout(job)
69 | if txt is None:
70 | return 'wait', 202
71 | return cors_jsonify(txt=txt)
72 |
73 | @app.route("/files/")
74 | def files(job):
75 | files = backend.get_files(job)
76 | return cors_jsonify(files=files)
77 |
78 | @app.route("/files/.json")
79 | def files_json(job):
80 | files = backend.get_files_json(job)
81 | return cors_jsonify(files=files)
82 |
83 | @app.route("/versions.json")
84 | def versions():
85 | default_version, versions = backend.zeek_versions_from_redis()
86 | return cors_jsonify(versions=versions, default=default_version)
87 |
88 | @app.route("/pcap/upload/", methods=['OPTIONS'])
89 | def pcap_upload_options_for_cors(checksum):
90 | return cors_jsonify(ok="ok")
91 |
92 | @app.route("/pcap/upload/", methods=['POST'])
93 | def pcap_upload(checksum):
94 | contents = request.files['pcap'].read()
95 | actual = md5(contents)
96 | ok = actual == checksum
97 | if ok:
98 | backend.save_pcap(checksum, contents)
99 | return cors_jsonify(status=ok, checksum=actual)
100 |
101 | @app.route("/pcap/")
102 | def has_pcap(checksum):
103 | status = backend.check_pcap(checksum)
104 | return cors_jsonify(status=status)
105 |
106 | @app.route("/example/")
107 | def example(name):
108 | return redirect("/#/trybro?example=%s" % name)
109 |
110 | @app.route("/pcaps.json")
111 | def pcap_list():
112 | paths = glob.glob(os.path.join(app.static_folder, "pcaps/*.pcap"))
113 | pcaps = list(map(os.path.basename, paths))
114 | return cors_jsonify(available=pcaps)
115 |
116 | @app.route("/format", methods=['POST'])
117 | def format():
118 | sources = request.json.get('sources', [])
119 | errors = {}
120 | for src in sources:
121 | # If anything goes wrong, just leave it unchanged.
122 | try:
123 | src['content'], error = fmt(src['content'])
124 | if error:
125 | errors[src['name']] = [error]
126 | except Exception as err:
127 | pass
128 |
129 | return cors_jsonify(sources=sources, errors=errors)
130 |
131 | def md5(s):
132 | m = hashlib.md5()
133 | m.update(s)
134 | return m.hexdigest()
135 |
136 | def cors_jsonify(**kwargs):
137 | response = jsonify(**kwargs)
138 | return corsify(response)
139 |
140 | def corsify(response):
141 | response.headers['Access-Control-Allow-Origin'] = '*'
142 | response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
143 | return response
144 |
145 | app.debug = False
146 |
147 | if __name__ == "__main__":
148 | app.run(debug=True)
149 |
--------------------------------------------------------------------------------
/manager/backend.py:
--------------------------------------------------------------------------------
1 | import time
2 | import json
3 | import hashlib
4 | import traceback
5 | import uuid
6 |
7 | import redis
8 |
9 | import bro_ascii_reader
10 | import rq
11 | import metrics
12 |
13 | from common import get_cache_key, get_redis, get_redis_raw, get_rq
14 | from version import zeek_versions_from_redis
15 |
16 | r = get_redis()
17 | r_raw = get_redis_raw()
18 |
19 | q = get_rq()
20 |
21 | CACHE_EXPIRE = 60*10
22 | SOURCES_EXPIRE = 60*60*24*30
23 |
24 | def wait_for_result(r):
25 | while r.result is None:
26 | time.sleep(0.1)
27 | return r.result
28 |
29 | def get_job_id():
30 | return uuid.uuid4().hex
31 |
32 | def run_code(sources, pcap, version=None):
33 | """Try to find a cached result for this submission
34 | If not found, submit a new job to the worker"""
35 | default_version, versions = zeek_versions_from_redis()
36 | if version not in versions:
37 | version = default_version
38 |
39 | metrics.log_execution(version)
40 | cache_key = get_cache_key(sources, pcap, version)
41 | job_id = r.get(cache_key)
42 | if job_id:
43 | metrics.log_cache_hit()
44 | r.expire(cache_key, CACHE_EXPIRE)
45 | r.expire('stdout:%s' % job_id, CACHE_EXPIRE + 5)
46 | r.expire('files:%s' % job_id, CACHE_EXPIRE + 5)
47 | r.expire('sources:%s' % job_id, SOURCES_EXPIRE)
48 | return job_id, get_stdout(job_id)
49 | job_id = get_job_id()
50 | job_data = {
51 | "job_id": job_id,
52 | "sources": sources,
53 | "pcap": pcap,
54 | "version": version
55 | }
56 | result = wait_for_result(q.enqueue("worker.run_code", sources=sources,
57 | pcap=pcap, version=version, job_id=job_id))
58 | return job_id, result
59 |
60 | def run_code_simple(stdin, version=None):
61 | sources = [
62 | {"name": "main.zeek", "content": stdin}
63 | ]
64 | job_id, stdout = run_code(sources, pcap=None, version=version)
65 | files = get_files_json(job_id)
66 | return files
67 |
68 | def get_stdout(job):
69 | stdout_key = 'stdout:%s' % job
70 | stdout = r.get(stdout_key)
71 | if stdout:
72 | r.expire(stdout_key, CACHE_EXPIRE+5)
73 | return stdout
74 |
75 | def get_files(job):
76 | files_key = 'files:%s' % job
77 | files = r.hgetall(files_key)
78 | return files
79 |
80 | def get_files_json(job):
81 | files = get_files(job)
82 | return parse_tables(files)
83 |
84 | def get_saved(job):
85 | sources_key = 'sources:%s' % job
86 | return r.get(sources_key)
87 |
88 | def parse_tables(files):
89 | for fn, contents in files.items():
90 | if contents.startswith("#sep"):
91 | files[fn] = bro_ascii_reader.reader(contents.splitlines(), max_rows=200)
92 | return files
93 |
94 | def save_pcap(checksum, contents):
95 | pcap_key = "pcaps:%s" % checksum
96 | r_raw.set(pcap_key, contents)
97 | r_raw.expire(pcap_key, 60*60)
98 | return True
99 |
100 | def check_pcap(checksum):
101 | pcap_key = "pcaps:%s" % checksum
102 | exists = r_raw.exists(pcap_key)
103 |
104 | if exists:
105 | r_raw.expire(pcap_key, 60*60)
106 | return exists
107 |
--------------------------------------------------------------------------------
/manager/bro_ascii_reader.py:
--------------------------------------------------------------------------------
1 | def reader(f, max_rows=None):
2 | line = ''
3 | headers = {}
4 | it = iter(f)
5 | while not line.startswith("#types"):
6 | line = next(it).rstrip()
7 | k,v = line[1:].split(None, 1)
8 | headers[k] = v
9 |
10 | sep = headers['separator'].encode().decode("unicode_escape")
11 |
12 | for k,v in headers.items():
13 | if sep in v or k in ('fields', 'types'):
14 | headers[k] = v.split(sep)
15 |
16 | headers['separator'] = sep
17 | fields = headers['fields']
18 | types = headers['types']
19 | set_sep = headers['set_separator']
20 |
21 | rows = []
22 | for row in it:
23 | if row.startswith("#close"):
24 | break
25 | parts = row.rstrip().split(sep)
26 | rows.append(parts)
27 |
28 | if max_rows and len(rows) > max_rows:
29 | mid = max_rows // 2
30 | rows = rows[:mid] + rows[-mid:]
31 |
32 | return {
33 | "header": fields,
34 | "types": types,
35 | "rows": rows,
36 | }
37 |
--------------------------------------------------------------------------------
/manager/common.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 | import json
3 | import os
4 |
5 | import redis
6 | import rq
7 |
8 | REDIS_HOST = os.environ.get("REDIS_HOST", "redis")
9 |
10 | def get_cache_key(sources, pcap, version):
11 | key = [sources, pcap, version]
12 | h = hashlib.sha1(json.dumps(key).encode())
13 | h = h.hexdigest()
14 | cache_key = f"cache:{h}"
15 | return cache_key
16 |
17 |
18 | def get_redis() -> redis.StrictRedis:
19 | return redis.StrictRedis(REDIS_HOST, charset="utf-8", decode_responses=True)
20 |
21 |
22 | def get_redis_raw():
23 | return redis.Redis(REDIS_HOST)
24 |
25 |
26 | def get_rq():
27 | return rq.Queue(connection=get_redis_raw())
28 |
--------------------------------------------------------------------------------
/manager/format.py:
--------------------------------------------------------------------------------
1 | import io
2 | import re
3 |
4 | import zeekscript
5 |
6 |
7 | ERROR_REGEX = r'line (\d+), col (\d+)'
8 |
9 | def parse_error(error):
10 | # This is a tuple of... (string, some number, actual error)
11 | txt = error[2]
12 | # 'cannot parse line 0, col 0: "function() {"'
13 |
14 | match = re.search(ERROR_REGEX, txt)
15 | if not match:
16 | return None
17 |
18 | line = int(match.group(1))
19 | col = int(match.group(2))
20 |
21 | return {
22 | 'row': line,
23 | 'column': col,
24 | 'type': "error",
25 | 'text': txt,
26 | }
27 |
28 | def fmt(txt):
29 | s = zeekscript.Script(io.StringIO(txt))
30 | s.parse()
31 | if s.has_error():
32 | return txt, parse_error(s.get_error())
33 | buf = io.BytesIO()
34 | s.format(buf)
35 | return buf.getvalue().decode(), None
36 |
--------------------------------------------------------------------------------
/manager/metrics.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | from redis import Redis
3 | r = Redis(host="redis")
4 |
5 | def log_execution(version):
6 | date = datetime.datetime.today().strftime("%Y-%m-%d")
7 | r.incr("trybro:metrics:executions")
8 | r.hincrby("trybro:metrics:executions_bydate", date, 1)
9 | r.hincrby("trybro:metrics:executions_byversion", version, 1)
10 |
11 | def log_cache_hit():
12 | r.incr("trybro:metrics:cache_hits")
13 |
14 | def get():
15 | return {
16 | "executions": r.get("trybro:metrics:executions"),
17 | "cache_hits": r.get("trybro:metrics:cache_hits"),
18 | "bydate": r.hgetall("trybro:metrics:executions_bydate"),
19 | "byversion": r.hgetall("trybro:metrics:executions_byversion"),
20 | }
21 |
--------------------------------------------------------------------------------
/manager/requirements.txt:
--------------------------------------------------------------------------------
1 | async-timeout==4.0.2
2 | certifi==2024.7.4
3 | chardet==5.0.0
4 | charset-normalizer==2.1.1
5 | click==8.1.3
6 | colorama==0.4.6
7 | coverage==6.5.0
8 | Deprecated==1.2.13
9 | docker-py==1.10.6
10 | docker-pycreds==0.4.0
11 | Flask==2.3.2
12 | Flask-Jsonpify==1.5.0
13 | gunicorn==22.0.0
14 | html5lib==1.1
15 | idna==3.7
16 | importlib-metadata==5.0.0
17 | itsdangerous==2.1.2
18 | Jinja2==3.1.4
19 | Markdown==3.4.1
20 | MarkupSafe==2.1.1
21 | mock==4.0.3
22 | packaging==21.3
23 | pyparsing==3.0.9
24 | redis==4.4.4
25 | requests==2.32.0
26 | rq==1.11.1
27 | six==1.16.0
28 | supervisor==4.2.4
29 | urllib3==1.26.19
30 | webencodings==0.5.1
31 | websocket-client==1.4.2
32 | Werkzeug==3.0.6
33 | wrapt==1.14.1
34 | zipp==3.19.1
35 | zeekscript==1.2.9
36 |
--------------------------------------------------------------------------------
/manager/runbro:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | export ZEEK_DNS_FAKE=1
4 | export BRO_DNS_FAKE=1
5 |
6 | for prog in /bro/bin/bro /bro/bin/zeek /usr/local/zeek/bin/zeek ; do
7 | if [ -x $prog ] ; then
8 | PROG=$prog
9 | fi
10 | done
11 |
12 | cd /brostuff/*/ || exit 1
13 | opts=""
14 |
15 | if [ -e file.pcap ]; then
16 | opts="-r file.pcap"
17 | fi
18 |
19 |
20 | chown nobody . ./*
21 | #Try both, just in case
22 | mv main.zeek try.zeek || mv main.bro try.zeek
23 |
24 | cat < __pre.zeek
25 | redef Site::local_nets += { 0.0.0.0/0 };
26 | @ifndef(zeek_init)
27 | global zeek_init: event();
28 | global zeek_done: event();
29 | event bro_init() { event zeek_init() ; }
30 | event bro_done() { event zeek_done() ; }
31 | @endif
32 | EOF
33 | su -s /bin/sh nobody -c "/usr/bin/timeout -k 2 15 $PROG -C $opts local __pre.zeek ./try.zeek > stdout.log 2> stderr.log"
34 |
35 | #remove harmless message
36 | grep -v 'NB-DNS' stderr.log | grep -v 'issue DNS request' > tmp.log
37 | mv tmp.log stderr.log
38 |
39 | #remove useless output files
40 | rm -f loaded_scripts.log packet_filter.log notice_policy.log
41 |
--------------------------------------------------------------------------------
/manager/runbro-1.5:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | export BRO_DNS_FAKE=1
4 |
5 | cd /brostuff/*/ || exit 1
6 | opts=""
7 |
8 | if [ -e file.pcap ]; then
9 | opts="-r file.pcap"
10 | fi
11 |
12 |
13 | mv main.zeek try.bro
14 |
15 | cat < __pre.bro
16 | const use_dpd = T;
17 | @load brolite
18 | redef log_rotate_interval = 0secs;
19 | redef local_nets += { 0.0.0.0/0 };
20 |
21 | @ifndef(zeek_init)
22 | global zeek_init: event();
23 | global zeek_done: event();
24 | event bro_init() { event zeek_init() ; }
25 | event bro_done() { event zeek_done() ; }
26 | @endif
27 | EOF
28 |
29 | chown nobody . *
30 |
31 | su -s /bin/sh nobody -c \
32 | "/usr/bin/timeout -k 2 15 /bro/bin/bro -f 'ip or not ip' -C $opts __pre.bro ./try.bro > stdout.log 2> stderr.log"
33 |
34 | #remove harmless message
35 | grep -v 'NB-DNS' stderr.log > tmp.log
36 | mv tmp.log stderr.log
37 |
38 | #remove useless output files
39 | rm -f loaded_scripts.log packet_filter.log
40 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/bro-types/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | print "Time to figure out why Zeek is special";
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/bro-types/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Zeek Datatypes
2 | pcaps:
3 |
4 | Zeek Datatypes
5 | ===================
6 |
7 | As a network monitoring system Zeek has its focus on networks and includes some data types
8 | specifically helpful when working with networks.
9 |
10 | * `time` - an absolute point in time. The built-in function
11 | `network_time` returns Zeek's notion of *now* (which is derived from
12 | the packets it analyzes). The only way to create an
13 | arbitrary time value is via the `double_to_time(d)`, with `d`
14 | being a variable of type `double` representing seconds since the
15 | UNIX epoch..
16 | * `interval` - a relative unit of time. Known units are `usec`,
17 | `msec`, `sec`, `min`, `hr`, or `day` (any may be pluralized by
18 | adding "s" to the end). Examples: `3secs`, `-1min`.
19 | * `port` - a transport-level port number. Examples: `80/tcp`,
20 | `53/udp`.
21 | * `addr` - an IP address. Examples: `1.2.3.4`, `[2001:db8::1]`.
22 | * `subnet` - a set of IP addresses with a common prefix, using CDIR notation. Example:
23 | `192.168.0.0/16`. Note that the `/` operator used on an address as
24 | the left operand produces a subnet mask of bit-width equal to the value
25 | of the right operand.
26 |
27 |
28 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/composite-types/comp-type-intro/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | print "Go to the next page to learn about sets";
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/composite-types/comp-type-intro/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Composite Datatypes
2 | pcaps:
3 |
4 | Composite Datatypes
5 | ===================
6 |
7 | We have already used simple data types like `string` and `int`.
8 | We now introduce the complex datatypes
9 | `set`, `table`, `vector`, and `record`. This will allow to solve more
10 | complex script exercises.
11 |
12 | On the following pages we introduce each of the complex types on its own page.
13 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/composite-types/index:
--------------------------------------------------------------------------------
1 | set
2 | table
3 | vector
4 | record
5 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/composite-types/record/main.zeek:
--------------------------------------------------------------------------------
1 | type MyRecord: record {
2 | a: string;
3 | b: count;
4 | c: bool &default = T;
5 | d: int &optional;
6 | };
7 |
8 | event zeek_init()
9 | {
10 | local x = MyRecord($a = "vvvvvv", $b = 6, $c = F, $d = -13);
11 | if ( x?$d )
12 | {
13 | print x$d;
14 | }
15 |
16 | x = MyRecord($a = "abc", $b = 3);
17 | print x$c; # T (default value of the field)
18 | print x?$d; # F (optional field was not set)
19 | }
20 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/composite-types/record/readme.markdown:
--------------------------------------------------------------------------------
1 | title: record
2 | pcaps:
3 |
4 | Record
5 | =======
6 |
7 | A `record` is a user-defined collection of named values of
8 | heterogeneous types, similar to a struct in C. Fields are dereferenced via the `$` operator
9 | (`.`, as used in other languages, would be ambiguous in Zeek because of
10 | IPv4 address literals). Optional field existence is checked via the
11 | `?$` operator.
12 |
13 |
14 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/composite-types/set/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | local x: set[string] = { "one", "two", "three" };
4 | add x["four"];
5 | print "four" in x; # T
6 | delete x["two"];
7 | print "two" !in x; # T
8 | add x["one"]; # x is unmodified since 1 is already a member.
9 |
10 | for ( e in x )
11 | {
12 | print e;
13 | }
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/composite-types/set/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Set
2 | pcaps:
3 |
4 | Set
5 | ===================
6 |
7 | A `set` is a collection of unique values. Sets use the `add` and
8 | `delete` operators to add and remove elements, and the `in`
9 | operator to test for membership.
10 |
11 | Run the example.
12 |
13 | In this example we first define a set of strings, containing the words "one", "two", and "three".
14 | The we add the string "four" to it. Thus the test for membership of "four" will result in "T" for
15 | true. The same way we can delete "two" from the set, testing if "two is not a member will result
16 | in "T" again. Adding the string "one" has no effect since it is already in the set.
17 | We can also use a for loop to print each member of a set.
18 |
19 |
20 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/composite-types/table/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | local x: table[count] of string = { [1] = "one",
4 | [3] = "three",
5 | [5] = "five" };
6 | x[7] = "seven";
7 | print 7 in x; # T
8 | print x[7]; # seven
9 | delete x[3];
10 | print 3 !in x; # T
11 | x[1] = "1"; # changed the value at index 1
12 |
13 | for ( key in x )
14 | {
15 | print key;
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/composite-types/table/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Table
2 | pcaps:
3 |
4 | Table
5 | ===================
6 |
7 | A `table` is an associative collection that maps a set of unique indices
8 | to other values. The same way as for sets, the `delete` operator is used to remove
9 | elements, however, adding elements is done just by assigning to an index as shown in this code example.
10 |
11 | Tables are comparable to arrays, hashes, or maps in other languages.
12 |
13 | Run the example. Most of it is the same as for sets. You can experiment with searching in sets and tables for example.
14 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/composite-types/vector/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | local x: vector of string = { "one", "two", "three" };
4 | print x; # [one, two, three]
5 | print x[1]; # two
6 | x[|x|] = "one";
7 | print x; # [one, two, three, one]
8 |
9 | for ( i in x )
10 | {
11 | print i; # Iterates over indices.
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/composite-types/vector/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Vector
2 | pcaps:
3 |
4 | Vector
5 | =======
6 |
7 | A `vector` is a collection of values with 0-based indexing.
8 | In comparison to sets this allows to store the same value twice.
9 |
10 | Line 6 shows an example of the length operator.
11 | This line adds a new element at the end of the list.
12 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/control-flow/if/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | local x = "3";
4 |
5 | for ( c in "12345" )
6 | {
7 | if ( c == x )
8 | {
9 | print "Found it.";
10 | # A preview of functions: fmt() does substitutions, outputs result.
11 | print fmt("And by 'it', I mean %s.", x);
12 | }
13 | else
14 | {
15 | # A quick way to print multiple things on one line.
16 | print "I'm looking for", x, "not", c;
17 | }
18 | }
19 | }
20 |
21 |
22 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/control-flow/if/readme.markdown:
--------------------------------------------------------------------------------
1 | title: If
2 | pcaps:
3 | pred: while
4 | succ: script-exercise-1
5 |
6 | If Statement
7 | ================
8 |
9 | If statements conditionally execute another statement or block of statements.
10 | Play with the given example.
11 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/control-flow/index:
--------------------------------------------------------------------------------
1 | if
2 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/event/main.zeek:
--------------------------------------------------------------------------------
1 | global myevent: event(s: string);
2 |
3 | global n = 0;
4 |
5 | event myevent(s: string) &priority = -10
6 | {
7 | ++n;
8 | }
9 |
10 | event myevent(s: string) &priority = 10
11 | {
12 | print "myevent", s, n;
13 | }
14 |
15 | event zeek_init()
16 | {
17 | print "zeek_init()";
18 | event myevent("hi");
19 | schedule 5 sec { myevent("bye") };
20 | }
21 |
22 | event zeek_done()
23 | {
24 | print "zeek_done()";
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/event/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Event
2 | pcaps:
3 |
4 | Event
5 | ===================
6 |
7 | We introduced events briefly in the first example to be able to do anything
8 | with the Zeek language. Events are actually a special flavor of functions
9 | but are essential to how Zeek works.
10 | They differ from functions in the following ways:
11 |
12 | * They may be scheduled and executed at a later time, so that their
13 | effects may not be realized directly after they are invoked.
14 | * They return no value -- they can't since they're not called directly
15 | but rather scheduled for later execution.
16 | * Multiple bodies can be defined for the same event, each one is
17 | deemed an "event handler". When it comes time to execute an
18 | event, all handler bodies for that event are executed in order of
19 | `&priority`.
20 |
21 | In the Zeek documentation, there is a detailed chapter about Zeek's event engine, how Zeek and the scripts
22 | interact, and what role the `event` plays in a Zeek script. Please [read](https://docs.zeek.org/en/current/scripting/index.html#the-event-queue-and-event-handlers).
23 | A reference for predefined events not related to protocol or file analysis is [here](https://docs.zeek.org/en/current/scripts/base/bif/event.bif.zeek.html).
24 |
25 | This example shows how to define and trigger a custom event.
26 |
27 | * We first see an event declaration of "myevent" that takes the string "s".
28 | * The the event handler implementation follows. The `&priority` attribute is optional and
29 | may be used to influence the order in which event handler bodies execute.
30 | If omitted, &priority is implicitly 0. In the example the priority is `-10` and thus very low.
31 | When this handler is called it will increment `n` from `0` to `1`.
32 | * The next handler for the same event sets the priority to 10. This handler will print the string "myevent"
33 | and the current values of the variables `s` and `n`.
34 | * Next we see the already familiar `zeek_init` event that is executed
35 | once when Zeek starts. It schedules the event twice.
36 | The first execution is a 'a soon as possible"
37 | schedule, the `schedule 5 sec {}` executes either in 5 seconds or upon Zeek shutting down, whichever
38 | happens first.
39 |
40 | Run the code and follow the order in which the events are executed.
41 |
42 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/exercise1/exercise/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | print "find meeeeeee!";
4 | }
5 |
6 | event zeek_done()
7 | {
8 | print "fizz buzz";
9 | }
10 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/exercise1/exercise/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Exercise
2 | pcaps:
3 |
4 | Exercise
5 | ==========================
6 |
7 | Now that we have types, operators, functions, loops and logic control we can
8 | go into a first exercise.
9 |
10 | As you have seen, Zeek supports pattern matching.
11 | Pattern matching can be a powerful tool especially in the area of network debugging and security.
12 | Finding specific things in logs is an efficient way to make a change in many situations.
13 |
14 | * Write a program to remove every letter "e" from an arbitrary string
15 | of your choosing (does not have to be done in-place).
16 |
17 | * Write a program that prints the numbers from 1 to 100. But for
18 | multiples of three, print "Fizz" instead of the number; and for
19 | multiples of five, print "Buzz". For numbers which are multiples of
20 | both three and five print "FizzBuzz".
21 |
22 | The solution to this exercise follows on the next page.
23 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/exercise1/index:
--------------------------------------------------------------------------------
1 | exercise
2 | solution
3 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/exercise1/solution/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | local result = "";
4 |
5 | for ( c in "testing" )
6 | {
7 | if ( c != "e" )
8 | {
9 | result = result + c;
10 | # Compound assignment, ``result += c``, also works.
11 | }
12 | }
13 | print result;
14 | }
15 |
16 | #Recursive approach w/ string concatenation.
17 | function fizzbuzz(i: count)
18 | {
19 | # Modulo, string concatenation approach.
20 | local s = "";
21 |
22 | if ( i % 3 == 0 )
23 | s += "Fizz";
24 |
25 | if ( i % 5 == 0 )
26 | s += "Buzz";
27 |
28 | if ( s == "" )
29 | print i;
30 | else
31 | print s;
32 |
33 | if ( i < 100 )
34 | fizzbuzz(i + 1);
35 | }
36 |
37 | event zeek_done()
38 | {
39 | fizzbuzz(1);
40 | }
41 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/exercise1/solution/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Exercise 1: Solution
2 | pcaps:
3 |
4 | Exercise 1 Solution
5 | =====================================
6 |
7 | Here is the solution for the first exercise.
8 |
9 | In the zeek\_init event we have a simple for-loop that iterates over
10 | the string "testing". Every character is tested if it is not an "e".
11 | Every other character is added to the end of the string in the variable "result".
12 | The resulting string is the printed and should contain no more "e"s.
13 |
14 | The second example shows recursive usage of a function.
15 | The recursion counts to 100 and replaces every 3rd number by "Fizz", every
16 | fifth by "Buzz". To do this the modulo operation is used.
17 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/exercise2/index:
--------------------------------------------------------------------------------
1 | script-exercise-2
2 | solution-script-exercise-2
3 |
4 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/exercise2/script-exercise-2/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | print "use all the Zeek types";
4 | }
5 |
6 | event zeek_done()
7 | {
8 | print "and tell me what you learned";
9 | }
10 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/exercise2/script-exercise-2/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Exercise
2 | pcaps: exercise_traffic.pcap
3 | order:
4 |
5 | Exercise
6 | ==========================
7 |
8 | By now we have all basic concepts of the Zeek scripting language.
9 | To finish the first part of your journey into the Zeek language solve the following exercise.
10 |
11 | Consider the following list of subnets as your given local subnets:
12 |
13 | 192.168.1.0/24, 192.68.2.0/24, 172.16.0.0/20, 172.16.16.0/20, 172.16.32.0/20, 172.16.48.0/20.
14 |
15 | Write a script that:
16 |
17 | * tells for the first 10 new connections source IP and port, destinations IP and port, connection ID, time when the connection started.
18 | * counts all connections seen and prints them in the end.
19 | * prints out for each unique IP address if its is local or external.
20 |
21 | To solve this exercise please load the traffic sample exercise_traffic.pcap.
22 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/exercise2/solution-script-exercise-2/main.zeek:
--------------------------------------------------------------------------------
1 | global local_subnets: set[subnet] = { 192.168.1.0/24, 192.68.2.0/24, 172.16.0.0/20, 172.16.16.0/20, 172.16.32.0/20, 172.16.48.0/20 };
2 | global my_count = 0;
3 | global inside_networks: set[addr];
4 | global outside_networks: set[addr];
5 |
6 | event new_connection(c: connection)
7 | {
8 | ++my_count;
9 | if ( my_count <= 10 )
10 | {
11 | print fmt("The connection %s from %s on port %s to %s on port %s started at %s.", c$uid, c$id$orig_h, c$id$orig_p, c$id$resp_h, c$id$resp_p, strftime("%D %H:%M", c$start_time));
12 | }
13 | if ( c$id$orig_h in local_subnets)
14 | {
15 | add inside_networks[c$id$orig_h];
16 | }
17 | else
18 | add outside_networks[c$id$orig_h];
19 |
20 | if ( c$id$resp_h in local_subnets)
21 | {
22 | add inside_networks[c$id$resp_h];
23 | }
24 | else
25 | add outside_networks[c$id$resp_h];
26 | }
27 |
28 | event connection_state_remove(c: connection)
29 | {
30 | if ( my_count <= 10 )
31 | {
32 | print fmt("Connection %s took %s seconds", c$uid, c$duration);
33 | }
34 | }
35 |
36 | event zeek_done()
37 | {
38 | print fmt("Saw %d new connections", my_count);
39 | print "These IPs are considered local";
40 | for (a in inside_networks)
41 | {
42 | print a;
43 | }
44 | print "These IPs are considered external";
45 | for (a in outside_networks)
46 | {
47 | print a;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/exercise2/solution-script-exercise-2/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Exercise 2
2 | pcaps: exercise_traffic.pcap
3 |
4 | Exercise: Solution
5 | ==========================
6 |
7 | The solution is one possible way to solve this exercise.
8 |
9 | * First we write local subnets into a set.
10 | * To count all connections we declare the global counter my\_count.
11 | * To learn about every new connection we simply use the event [new\_connection](https://docs.zeek.org/en/current/scripts/base/bif/event.bif.zeek.html#id-new_connection).
12 | Every time this
13 | event is triggered we increase the counter. For the first 10 connections we print source IP and port and
14 | destination IP and port, plus connection ID and time. To get the connection ID we need the filed uid of the connection.
15 | To print the start time of the connection in human readable form we use the Zeek bif [strftime](https://docs.zeek.org/en/current/scripts/base/bif/bro.bif.zeek.html?highlight=strftime#id-strftime).
16 | * The duration of a connection - expressed as an interval - can be retrieved when the connection ends.
17 | The event [connection\_state\_remove](https://docs.zeek.org/en/current/scripts/base/bif/event.bif.zeek.html?highlight=connection_state_remove#id-connection_state_remove)
18 | is triggered when a connection is about to be removed from memory. Then we can simply ask for the duration.
19 | * At the very end inside the zeek\_done event we compute the rest. Print the number of connections stored in my\_count
20 | and use a for-loop to print out a list of all unique IPs and if they are local or external IPs.
21 | In this example we simply define which subnets are considered local. This does not mean that the list is complete. In a real
22 | world example this should be verified and documented in [networks.cfg](https://github.com/zeek/zeekctl/blob/master/doc/zeekctl.rst).
23 |
24 |
25 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/functions/main.zeek:
--------------------------------------------------------------------------------
1 | # Function implementation.
2 | function emphasize(s: string, p: string &default = "*"): string
3 | {
4 | return p + s + p;
5 | }
6 |
7 |
8 | event zeek_init()
9 | {
10 | # Function calls.
11 | print emphasize("yes");
12 | print emphasize("no", "_");
13 | }
14 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/functions/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Functions
2 | pcaps:
3 |
4 | Functions
5 | ==========
6 |
7 | Introducing a programming language often encounters mutual dependencies on different pieces of knowledge.
8 | As a basic part we introduce functions now. To show you a working example we need to use some
9 | elements that are explained later.
10 |
11 | This example function takes one string argument and another optional string argument.
12 | It returns a string.
13 | The function is declared and implemented at the same time. The function is then called
14 | within the zeek\_init event.
15 |
16 | What do we see here?
17 |
18 | Input parameters are specified within parentheses in a comma separated list. The return value follows after the colon.
19 | All parameters in this function are of type 'string'. We will see more about types in Zeek in the next
20 | [lesson](http://try.zeek.org/example/primitive_datatypes).
21 |
22 | The second argument in this example is optional. This is because of the [attribute](https://docs.zeek.org/en/current/script-reference/attributes.html)
23 | &default. In the example here the default value would be '\*' in case the second parameter is missing.
24 |
25 | Another element seen here is the '+'-operator that concatenates the strings in this case.
26 |
27 | At last when the function is used, the resulting values are simply printed to STDOUT.
28 |
29 | Another side note on the relation between functions and events: Events
30 | are a kind of function as well, and both can only be declared at the global
31 | level; one cannot nest them.
32 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/hook/main.zeek:
--------------------------------------------------------------------------------
1 | global myhook: hook(s: string);
2 |
3 | hook myhook(s: string) &priority = 10
4 | {
5 | print "priority 10 myhook handler", s;
6 | s = "bye";
7 | }
8 |
9 | hook myhook(s: string)
10 | {
11 | print "break out of myhook handling", s;
12 | break;
13 | }
14 |
15 | hook myhook(s: string) &priority = -5
16 | {
17 | print "not going to happen", s;
18 | }
19 |
20 | event zeek_init()
21 | {
22 | local ret: bool = hook myhook("hi");
23 | if ( ret )
24 | {
25 | print "all handlers ran";
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/hook/readme.markdown:
--------------------------------------------------------------------------------
1 | title: hook
2 | pcaps:
3 |
4 | Hook
5 | =======
6 |
7 | Hooks are yet another flavor of function. They are similar to events
8 | in that they can also have multiple bodies. However they are different
9 | in two regards:
10 |
11 | * They do execute immediately when invoked (i.e. they're not scheduled
12 | like events).
13 | * The way the body of a hook handler terminates determines if further
14 | handlers get executed. If the end of the
15 | body, or a `return` statement, is reached, the next hook handler
16 | will be executed. If, however, a hook handler body terminates with a `break`
17 | statement, no remaining hook handlers will execute.
18 |
19 | Hooks are useful to provide customization points for modules, as they
20 | allow to outsource decisions to site-specific code.
21 |
22 | In this example we included the mentioned break statement, so the hook
23 | with priority `-5` is never executed. Try to play with this statement and
24 | the priorities to change the behavior of this example code.
25 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/index:
--------------------------------------------------------------------------------
1 | loading
2 | functions
3 | variables
4 | primitive-datatypes
5 | operators
6 | control-flow
7 | loops
8 | exercise1
9 | switches
10 | event
11 | hook
12 | composite-types
13 | redefinitions
14 | bro-types
15 | exercise2
16 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/loading/main.zeek:
--------------------------------------------------------------------------------
1 | @load misc/dump-events
2 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/loading/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Loading Scripts
2 | pcaps:
3 |
4 | Loading Scripts
5 | ===============
6 |
7 | Like most programming languages, Zeek has the ability to load in script code
8 | from other files. There is a directive, `@load` which provides the capability.
9 |
10 | The code here shows a simple script that does nothing but loading a script. The script [misc/dump-events](https://docs.zeek.org/en/current/scripts/policy/misc/dump-events.zeek.html) prints the events that Zeek generates out to standard output in a readable form. This is for debugging only and can be used to help understand events and their parameters. Note that it will show only events for which a handler is defined.
11 |
12 | A small note needs to be made here because there are some default paths defined by Zeek automatically which make it easier to load many of the scripts that are included with Zeek. The default paths are as follows (based on the installed prefix directory):
13 |
14 | - `/share/bro`
15 | - `/share/bro/policy`
16 | - `/share/bro/site`
17 |
18 | The most common use case of the load statement is in [local.zeek](https://github.com/zeek/zeekctl/blob/master/doc/zeekctl.rst#site-specific-customization).
19 | This file is part of Zeek's configuration files and adds further scripts that are not loaded by default. A reference of all scripts that can be loaded is found [here](https://docs.zeek.org/en/current/script-reference/scripts.html).
20 | Everything you see there in `base/` is loaded by default, e.g., policies have to be loaded via the load statement.
21 |
22 |
23 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/loops/for/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | for ( character in "abc" )
4 | {
5 | print character;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/loops/for/readme.markdown:
--------------------------------------------------------------------------------
1 | title: For Loops
2 | pcaps:
3 |
4 | For Loops
5 | ================
6 |
7 | Zeek provides a "foreach" style loop.
8 | In the given example we simply iterate through the string "abc"
9 | and print the current character.
10 |
11 | Note: Iterating over any collection other than a vector won't provide any guarantee of the order
12 | Zeek iterates over the collection. If the order is important the collection should be a vector.
13 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/loops/index:
--------------------------------------------------------------------------------
1 | for
2 | while
3 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/loops/while/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | local i = 0;
4 |
5 | while ( i < 5 )
6 | print ++i;
7 |
8 | while ( i % 2 != 0 )
9 | {
10 | local finish_up = F;
11 |
12 | if ( finish_up == F )
13 | print "nope";
14 | ++i;
15 | next;
16 |
17 | if ( finish_up )
18 | break;
19 | }
20 | print i;
21 | }
22 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/loops/while/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Loops: While
2 | pcaps:
3 |
4 | Loops: While
5 | ================
6 |
7 | A "while" loop iterates over a body statement as long as a given condition remains true.
8 |
9 | A [break](https://docs.zeek.org/en/current/script-reference/statements.html#keyword-break)
10 | statement can be used at any time to immediately terminate
11 | the "while" loop, and a
12 | [next](https://docs.zeek.org/en/current/script-reference/statements.html#keyword-next)
13 | statement can be used to skip to the next loop iteration.
14 |
15 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/operators/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | print "Try to figure out what happens if ";
4 | print "you use numbers as strings and compare them with 'ints'";
5 | print "get to know Zeek's types and operators so you don't ";
6 | print "need to look them up all them time in later exercises.";
7 | }
8 |
9 | event zeek_done()
10 | {
11 | print "Well done!";
12 | }
13 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/operators/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Operators
2 | pcaps:
3 |
4 | Operators
5 | ==========
6 |
7 | So far we have functions, variables, and we can even type them.
8 | We still can't connect two (or more) values to build a new one.
9 | So now we can talk about operators that are used to manipulate, inspect, or compare data.
10 |
11 | Explore the operators below to play with the Zeek elements we have so
12 | far. In the next two steps, we introduce loops
13 | and if-statements so that we can solve more complex exercises.
14 |
15 | Arithmetic Operators
16 | -----------------------
17 |
18 | Name | Syntax | Example Usage
19 | ------------- | --------- | --------------------------------------------------
20 | Addition | ``a + b`` | ``print 2 + 2; # 4``
21 | Subtraction | ``a - b`` | ``print 2 - 2; # 0``
22 | Multiplication | ``a * b`` | ``print 4 * 4; # 16``
23 | Division | ``a / b`` | ``print 15 / 3; # 5``
24 | Modulo | ``a % b`` | ``print 18 % 15; # 3``
25 | Unary Plus | ``+a`` | ``local a = +1; # Force use of a signed integer``
26 | Unary Minus | ``-a`` | ``local a = 5; print -a; # -5``
27 | Increment | ``++a`` | ``local a = 1; print ++a, a; # 2, 2``
28 | Decrement | ``--a`` | ``local a = 2; print --a, a; # 1, 1``
29 |
30 | Assignment Operators
31 | --------------------
32 |
33 | Name | Syntax | Example Usage
34 | -----------------------| ---------- | ------------------------
35 | Assignment | ``a = b`` | ``local a = 7;``
36 | Addition assignment | ``a += b`` | ``local a = 7; a += 2; # 9``
37 | Subtraction assignment | ``a -= b`` | ``local a = 7; a -= 2; # 5``
38 |
39 | Relational Operators
40 | ---------------------
41 |
42 | Name | Syntax | Example Usage
43 | --------------- | ---------- | ----------------------
44 | Equality | ``a == b`` | ``print 2 == 2; # T``
45 | Inequality | ``a != b`` | ``print 2 != 2; # F``
46 | Less | ``a < b`` | ``print 2 < 3; # T``
47 | Less or Equal | ``a <= b`` | ``print 2 <= 2; # T``
48 | Greater | ``a > b`` | ``print 2 > 3; # F``
49 | Greater or Equal | ``a >= b`` | ``print 2 >= 2; # T``
50 |
51 | Logical Operators
52 | ------------------
53 |
54 | Name | Syntax | Example Usage
55 | ---------------- | ---------- | ----------------------
56 | Logical NOT | ``! a`` | ``print !T; # F``
57 | Logical AND | ``a && b`` | ``print T && F; # F``
58 | Logical OR | ``a || b`` | ``print F || T; # T``
59 |
60 | Other Operators
61 | ----------------
62 |
63 | Name | Syntax | Example Usage
64 | ---------------- | ------------------------ | -----------------------------
65 | Member Inclusion | ``a in b`` | ``print "z" in "test"; # F``
66 | Member Exclusion | ``a !in b`` | ``print "z" !in "test"; # T``
67 | Size/Length | ``|a|`` | ``print |"test"|; # 4``
68 | Absolute Value | ``|a|`` | ``print |-5|; # 5``
69 | Index | ``a[i]`` | ``print "test"[2]; # s``
70 | String Slicing | ``a[i:j], a[i:], a[:j]`` | ``print "testing"[2:4]; # st``
71 |
72 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/primitive-datatypes/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | local x : string = "two";
4 | local y : int = 10000000000000000000;
5 | print "y is a large int:", y;
6 | print "x is a short string:", x;
7 |
8 | #pattern matching
9 | print /one|two|three/ == "two"; # T
10 | print /one|two|three/ == "ones"; # F (exact matching)
11 | print /one|two|three/ in "ones"; # T (embedded matching)
12 | print /[123].*/ == "2 two"; # T
13 | print /[123].*/ == "4 four"; # F
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/primitive-datatypes/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Primitive Datatypes
2 | pcaps:
3 |
4 | Primitive Datatypes
5 | ===================
6 |
7 | Now that we have variables we can talk about which data types we can use and assign to variables.
8 | In this lesson we introduce the simpler types.
9 |
10 | Zeek has a static type system (i.e., the type of data a variable holds is
11 | fixed) with type inference, e.g., `local x = 0` is equivalent to
12 | `local x: count = 0`. It also implicitly promotes/coerces types in
13 | certain situations.
14 |
15 | The full reference on types in Zeek can be found [here](https://docs.zeek.org/en/current/script-reference/types.html).
16 | For now, look through the simple types. Most of the types should be familiar from other programming languages,
17 | e.g., `bool`, `double`, `int`, `count`, `string`, `pattern` (a regular expression using [flex's syntax](http://westes.github.io/flex/manual/Patterns.html)).
18 | But Zeek as a network monitoring system introduces also a set of domain-specific types that are explained
19 | in the [reference](https://docs.zeek.org/en/current/script-reference/types.html).
20 | Examples are `time`, `interval`, `port`, `addr`, and `subnet`.
21 |
22 | These custom Zeek types and the more complex types will be discussed in detailed examples in later lessons.
23 |
24 | Run the code in this example. Try to play with the given code example,
25 | e.g. change the given types. Does that work?
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/redefinitions/index:
--------------------------------------------------------------------------------
1 | redef-records
2 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/redefinitions/redef-records/main.zeek:
--------------------------------------------------------------------------------
1 | type MyRecord: record {
2 | a: string &default="hi";
3 | b: count &default=7;
4 | } &redef;
5 |
6 | redef record MyRecord += {
7 | c: bool &optional;
8 | d: bool &default=F;
9 | #e: bool; # Not allowed, must be &optional or &default.
10 | };
11 |
12 | event zeek_init()
13 | {
14 | print MyRecord();
15 | print MyRecord($c=T);
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/redefinitions/redef-records/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Redefinitions
2 | pcaps:
3 |
4 | Redefinitions for records
5 | ============================
6 |
7 | `redef` not only works with values, but also
8 | certain *types*. Namely `record` (and `enum`) may be extended, which is shown in this
9 | code example.
10 |
11 | Redefining records is especially helpful when working with given modules.
12 |
13 | Run this code example. Play with the the printing command, change the `redef` and see what effects
14 | happen.
15 |
16 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/redefinitions/redef/main.zeek:
--------------------------------------------------------------------------------
1 | const pi = 3.14 &redef;
2 | redef pi = 3.1415;
3 |
4 | event zeek_init()
5 | {
6 | const two = 2;
7 | #redef two = 1; # not allowed
8 | #pi = 5.5; # not allowed
9 | print pi;
10 | print two;
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/redefinitions/redef/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Redefinitions
2 | pcaps:
3 |
4 | Redefinitions
5 | ============================
6 |
7 | Zeek supports redefining constants, but only at parse-time, not at
8 | run-time. This feature may not be that useful when writing your own
9 | scripts for private usage, but it's the suggested way for script authors
10 | to advertise "knobs and switches" that one may choose to configure.
11 | These are usually values that one doesn't want to accidentally modify
12 | while Zeek is running, but that the author either can't know ahead of
13 | time (e.g. local IP addresses of interest), may differ across
14 | environments (e.g. trusted SSL certificates), or may evolve over
15 | time (e.g. a list of known cipher suites).
16 |
17 | Normally, the declaration and the `redef` would live in different
18 | scripts (e.g. the declaration in a script from the "standard library"
19 | that comes with Zeek and the `redef` in the script you write), but
20 | this is just an example.
21 |
22 | Run the code and try to uncomment the line
23 |
24 | redef two = 1;
25 |
26 | Then uncomment the next line.
27 |
28 |
29 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/switches/index:
--------------------------------------------------------------------------------
1 | switch
2 | switch-exercise
3 | solution-switch-exercise
4 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/switches/solution-switch-exercise/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | local result = 0;
4 | local input = "The Zeek Network Security Monitor";
5 | for ( c in input )
6 | {
7 | switch ( c )
8 | {
9 | case "a", "e", "i", "o", "u":
10 | ++result;
11 | break;
12 | }
13 | }
14 | print result;
15 | }
16 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/switches/solution-switch-exercise/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Switch Exercise: Solution
2 | pcaps:
3 |
4 | Switch Exercise: Solution
5 | ==========================================
6 |
7 | Write a program that relies on a switch statement to count the
8 | number of vowels (a, e, i, o, u) in an arbitrary string of your
9 | choosing.
10 |
11 | Here is an example that works.
12 | We loop through the string that is given in the variable `input`.
13 | Inside the for loop every character is sent to the switch to test if it is a vowel. If so, the
14 | variable `result` is incremented.
15 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/switches/switch-exercise/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | print "write a switch to count vowels!";
4 | }
5 |
6 |
7 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/switches/switch-exercise/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Switch Exercise
2 | pcaps:
3 |
4 | Switch Exercise
5 | ================================
6 |
7 | Write a program that relies on a switch statement to count the
8 | number of vowels (a, e, i, o, u) in an arbitrary string of your
9 | choosing.
10 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/switches/switch/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | local x = 4;
4 |
5 | switch ( x )
6 | {
7 | case 0:
8 | # This block only executes if x is 0.
9 | print "case 0";
10 | break;
11 | case 1, 2, 3:
12 | # This block executes if any of the case labels match.
13 | print "case 1, 2, 3";
14 | break;
15 | case 4:
16 | print "case 4 and ...";
17 | # Block ending in the "fallthrough" also execute subsequent case.
18 | fallthrough;
19 | case 5:
20 | # This block may execute if x is 4 or 5.
21 | print "case 5";
22 | break;
23 | default:
24 | # This block executed if no other case matches.
25 | print "default case";
26 | break;
27 | }
28 | }
29 |
30 |
31 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/switches/switch/readme.markdown:
--------------------------------------------------------------------------------
1 | title: The switch statement
2 | pcaps:
3 |
4 | The Switch Statement
5 | =====================
6 |
7 | Sometimes a switch statement is a more convenient way to organize code.
8 | For example, consider a switch instead of large chains of "else if"
9 | blocks if there's a large chain of OR'd conditions.
10 |
11 | The syntax is similar to other common languages, "switch - variable - label".
12 | In Zeek it is possible to collect two or more label values to execute the same block of code.
13 | Also you can declare a default case if the input value does not match any of the cases.
14 | You must finish each case block with either "break" statement (to
15 | continue after the switch), or an explicit "fallthrough" to proceed
16 | into the subsequent case.
17 |
18 | Now click "next" to solve an exercise using a switch.
19 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/variables/main.zeek:
--------------------------------------------------------------------------------
1 | global x = "Hello";
2 |
3 | event zeek_init()
4 | {
5 | print x;
6 |
7 | const y = "Guten Tag";
8 | # Changing value of 'y' is not allowed.
9 | #y = "Nope";
10 |
11 | local z = "What does that mean?";
12 | print z;
13 | }
14 |
15 | event zeek_done()
16 | {
17 | x = "Bye";
18 | print x;
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/manager/static/examples/basics/variables/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Variables
2 | pcaps:
3 |
4 | Variables
5 | ===========
6 |
7 | You can assign arbitrary data to a variable in order to store it for later use.
8 | A `local` variable differs from a `global` in that its
9 | scope is restricted to the body of a function
10 | and will be assigned its initial
11 | value each time the function body is executed.
12 |
13 | The reference on declaring variables, constants, functions etc is found
14 | [here](https://docs.zeek.org/en/current/script-reference/statements.html).
15 | More on types and all things that can be declared will follow in later lessons of this
16 | tutorial.
17 |
18 | Run the example for this exercise. Try to print 'z' in the second event. Does that work?
19 |
20 |
--------------------------------------------------------------------------------
/manager/static/examples/congrats/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | print "Congratulations on your first lesson in Zeek Scripting!";
4 | }
5 |
6 | event zeek_done()
7 | {
8 | print "Well done!";
9 | }
10 |
--------------------------------------------------------------------------------
/manager/static/examples/congrats/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Congrats
2 | pcaps:
3 |
4 | Congratulations
5 | ==========================
6 |
7 | You have finished all lessons in Zeek Script we have provided so far.
8 | Welcome in the world of Zeek. We hope you enjoyed this little journey.
9 |
10 | Feedback is more than welcome, please write to [info@zeek.org](info@zeek.org).
11 |
12 | To find more resources to learn Zeek visit the [Zeek web site](https://www.zeek.org).
13 | Or go back to the [Tutorial Index](https://old.zeek.org/documentation/tutorials/index.html).
14 |
--------------------------------------------------------------------------------
/manager/static/examples/hello/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | print "Hello, World!";
4 | }
5 |
6 | event zeek_done()
7 | {
8 | print "Goodbye, World!";
9 | }
10 |
--------------------------------------------------------------------------------
/manager/static/examples/hello/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Hello World
2 | pcaps:
3 |
4 | Hello World
5 | ============
6 |
7 | Welcome to our interactive Zeek tutorial. (Note that "Zeek" is the
8 | new name of what used to be known as the "Bro" network monitoring system.
9 | The old "Bro" name still frequently appears in the system's documentation
10 | and workings, including in the names of events and the suffix used for
11 | script files.)
12 |
13 | Click run and see the Zeek magic happen. You may need to scroll
14 | down a bit to get to the output.
15 |
16 | In this simple example you can see already a specialty of Zeek, the "event". Zeek is event-driven.
17 | This means you can control any execution by making it dependent on an event trigger.
18 | Our example here would not work without an event to be triggered so we use the two events that are always raised,
19 | zeek_init()
20 | and
21 | zeek_done()
22 |
23 | The first is executed when Zeek is started, the second when Zeek terminates, so we can use these for example
24 | when no traffic is actually analyzed as we do for our basic examples
25 | (see [here](https://docs.zeek.org/en/current/scripts/base/bif/event.bif.zeek.html) for more on these basic events).
26 | In this tutorial we will come back to events in the lesson about [complex data types](http://try.zeek.org/example/events).
27 |
28 | Other than that, all this script does is sending warm greetings to new Zeek users by printing to STDOUT.
29 |
30 | Try.Zeek allows you to hide the text if you want to script console to be full width. Find the button "Hide Text" and give it a try.
31 |
32 | Every example can be run with a pcap file, you can select one below the script area. You can also
33 | upload your own pcap-examples. Select a pcap and click run again. Below the print-output you will find tabs
34 | with the familar log-file names. You can click on each row inside a log file and get more details. If Zeek logs are not yet
35 | familiar to you please go to the documentation on [log files](https://docs.zeek.org/en/current/script-reference/log-files.html).
36 |
37 | When you are ready you can just click on next above to start the next example, or jump directly to a topic in the following list
38 |
39 | Basics
40 | ======
41 | * [Loading Scripts](#/?example=basics-loading)
42 | * [Functions](#/?example=basics-functions)
43 | * [Variables](#/?example=basics-variables)
44 | * [Primitive Datatypes](#/?example=basics-primitive-datatypes)
45 | * [Operators](#/?example=basics-operators)
46 | * [If](#/?example=basics-control-flow-if)
47 | * [For Loops](#/?example=basics-loops-for)
48 | * [Loops: While](#/?example=basics-loops-while)
49 | * [Exercise](#/?example=basics-exercise1-exercise)
50 | * [Exercise 1: Solution](#/?example=basics-exercise1-solution)
51 | * [The switch statement](#/?example=basics-switches-switch)
52 | * [Switch Exercise](#/?example=basics-switches-switch-exercise)
53 | * [Switch Exercise: Solution](#/?example=basics-switches-solution-switch-exercise)
54 | * [Event](#/?example=basics-event)
55 | * [hook](#/?example=basics-hook)
56 | * [Set](#/?example=basics-composite-types-set)
57 | * [Table](#/?example=basics-composite-types-table)
58 | * [Vector](#/?example=basics-composite-types-vector)
59 | * [record](#/?example=basics-composite-types-record)
60 | * [Redefinitions](#/?example=basics-redefinitions-redef-records)
61 | * [Zeek Datatypes](#/?example=basics-bro-types)
62 | * [Exercise](#/?example=basics-exercise2-script-exercise-2)
63 | * [Exercise 2](#/?example=basics-exercise2-solution-script-exercise-2)
64 |
65 | Modules
66 | =======
67 | * [Writing a Module](#/?example=modules-module)
68 | * [Writing a Module: Export](#/?example=modules-export)
69 | * [Writing a Module: Logging](#/?example=modules-log-factorial)
70 |
71 | Logs
72 | ====
73 | * [Filtering Logs](#/?example=logs-filter-logs)
74 | * [Rename Logs](#/?example=logs-rename-logs)
75 | * [Raising a Notice](#/?example=new-notice)
76 |
77 | Sumstats
78 | ========
79 | * [The Summary Statistics Framework](#/?example=sumstats-sumstats1)
80 | * [SumStats Exercise Solution Part 1](#/?example=sumstats-sumstats2)
81 | * [SumStats Exercise Solution Part 2](#/?example=sumstats-sumstats3)
82 |
83 | Intel Framework
84 | ===============
85 | * [Intel](#/?example=intel-intel-1)
86 |
--------------------------------------------------------------------------------
/manager/static/examples/index:
--------------------------------------------------------------------------------
1 | hello
2 | basics
3 | modules
4 | logs
5 | new-notice
6 | sumstats
7 | intel
8 | congrats
9 |
--------------------------------------------------------------------------------
/manager/static/examples/intel/index:
--------------------------------------------------------------------------------
1 | intel-1
2 |
--------------------------------------------------------------------------------
/manager/static/examples/intel/intel-1/intel-1.dat:
--------------------------------------------------------------------------------
1 | #fields indicator indicator_type meta.source
2 | www.reddit.com Intel::DOMAIN my_special_source
3 |
--------------------------------------------------------------------------------
/manager/static/examples/intel/intel-1/main.zeek:
--------------------------------------------------------------------------------
1 | @load frameworks/intel/seen
2 |
3 | redef Intel::read_files += {
4 | fmt("%s/intel-1.dat", @DIR)
5 | };
6 |
--------------------------------------------------------------------------------
/manager/static/examples/intel/intel-1/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Intel
2 | pcaps: http.pcap
3 |
4 | The Intel Framework
5 | ====================
6 |
7 | The Intel Framework provides an interface to feed your own intelligence data into Zeek.
8 |
9 | "Intelligence data is critical to the process of monitoring for security purposes. There is always data which will be discovered through the incident response process and data which is shared through private communities. The goals of Zeek's Intelligence Framework are to consume that data, make it available for matching, and provide infrastructure around improving performance, memory utilization, and generally making all of this easier."
10 |
11 | Find the whole documentation on the Intelligence Framework on
12 | our [website](https://docs.zeek.org/en/current/frameworks/intel.html).
13 | You will also find details on input formats etc.
14 |
15 | Run the example given. Have a look at the extra file "intel-1.dat".
16 | This the source intel data that you feed into Zeek.
17 |
18 | As you can see the script to read an intel data file and make Zeek
19 | notify you if it sees a match is very simple at the start.
20 | The "seen"-policy needs to be loaded. In a real setup, this would be done in the local.zeek file.
21 | The second step is to tell Zeek where to find the file and its name.
22 |
23 | Please have a look at the results. You can notice a new log-file called intel.log which contains
24 | all seen matches. As always the uid allows you to investigate further which connections were involved in this match and in what way.
25 |
26 | It is also possible to raise notices based on intel data. To see how this works have a look at the
27 | documentation mentioned above.
28 |
29 |
--------------------------------------------------------------------------------
/manager/static/examples/logs/filter-logs/factorial.zeek:
--------------------------------------------------------------------------------
1 | module Factor;
2 |
3 | export {
4 | # Append the value LOG to the Log::ID enumerable.
5 | redef enum Log::ID += { LOG };
6 |
7 | # Define a new type called Factor::Info.
8 | type Info: record {
9 | num: count &log;
10 | factorial_num: count &log;
11 | };
12 | global factorial: function(n: count): count;
13 | global mod5: function(id: Log::ID, path: string, rec: Factor::Info) : string;
14 | }
15 |
16 | function factorial(n: count): count
17 | {
18 | if ( n == 0 )
19 | return 1;
20 |
21 | else
22 | return ( n * factorial(n - 1) );
23 | }
24 |
25 | function mod5(id: Log::ID, path: string, rec: Factor::Info) : string
26 | {
27 | if ( rec$factorial_num % 5 == 0 )
28 | return "factor-mod5";
29 |
30 | else
31 | return "factor-non5";
32 | }
33 |
--------------------------------------------------------------------------------
/manager/static/examples/logs/filter-logs/main.zeek:
--------------------------------------------------------------------------------
1 | @load factorial
2 |
3 | event zeek_init()
4 | {
5 | Log::create_stream(Factor::LOG, [$columns=Factor::Info, $path="factor"]);
6 |
7 | local filter: Log::Filter = [$name="split-mod5s", $path_func=Factor::mod5];
8 | Log::add_filter(Factor::LOG, filter);
9 | Log::remove_filter(Factor::LOG, "default");
10 | }
11 |
12 | event zeek_done()
13 | {
14 | local numbers: vector of count = vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
15 | for ( n in numbers )
16 | Log::write( Factor::LOG, [$num=numbers[n],
17 | $factorial_num=Factor::factorial(numbers[n])]);
18 | }
19 |
--------------------------------------------------------------------------------
/manager/static/examples/logs/filter-logs/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Filtering Logs
2 | pcaps:
3 | pred: rename-logs
4 | succ: new-notice
5 |
6 | Filtering Logs
7 | =========================
8 |
9 | As said in the last lesson, filtering allows to manipulate Zeek's logging in several ways. Renaming the log-file is one.
10 | Splitting the stream into two log files is the one we explore in this lesson.
11 |
12 | For this we go back to the factorial module. The goal now is to split the logging stream in two. We send all results to
13 | one log-file that are divisible evenly by 5, the others to a second log-file.
14 | Which record is sent to which log-file is decided dynamically based on the
15 | modulo function. Find more details on dynamically determining log paths
16 | [here](https://docs.zeek.org/en/current/frameworks/logging.html#determine-log-path-dynamically).
17 |
18 | Now run the code example. You see that there are now two log-files, one called `num` and `factorial_num`.
19 | Lets look at the code. In the module *factorial.zeek* we add a new function, the `path_func` we
20 | are going to use. Again, the function is also added to the export section. The function returns whether a number is in
21 | our modulo-5 category or not and then returns a string accordingly. The strings returned are the names of the two new log files.
22 | In *main.zeek* you will find that we added more lines to `zeek_init`. We create a
23 | filter called *split-mod5s*, add that new filter and remove the `default` filter.
24 | Comment out the line 9 that removes the dafault and see what happens.
25 |
26 |
--------------------------------------------------------------------------------
/manager/static/examples/logs/index:
--------------------------------------------------------------------------------
1 | filter-logs
2 | rename-logs
3 |
--------------------------------------------------------------------------------
/manager/static/examples/logs/rename-logs/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | # Replace default filter for the Conn::LOG stream in order to
4 | # change the log filename.
5 |
6 | local f = Log::get_filter(Conn::LOG, "default");
7 | f$path = "myconn";
8 | Log::add_filter(Conn::LOG, f);
9 | }
10 |
--------------------------------------------------------------------------------
/manager/static/examples/logs/rename-logs/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Rename Logs
2 | pcaps: exercise_traffic.pcap
3 |
4 | Rename Logs
5 | =============
6 |
7 | Creating your own Logs is already very useful. Another feature in Zeek allows you to modify existing logging, too.
8 | This feature is called filtering, although it allows more than to simply filter out certain fields.
9 | A stream has one or more filters attached to it (a stream without any filters will not produce any log output).
10 | When a stream is created, it automatically gets a default filter attached to it.
11 | This default filter can be removed or replaced, or other filters can be added to the stream.
12 | This is accomplished by using either the
13 | [Log::add_filter](https://docs.zeek.org/en/current/scripts/base/frameworks/logging/main.zeek.html#id-Log::add_filter)
14 | or [Log::remove_filter](https://docs.zeek.org/en/current/scripts/base/frameworks/logging/main.zeek.html#id-Log::remove_filter)
15 | function. The default filter writes all fields to the logfile that carry the `&log` attribute.
16 | In this tutorial we will show you how to use filters to do such tasks as rename a log file,
17 | split the output into multiple files, control which records are written, and set a custom rotation interval.
18 |
19 | We start with a very simple case. In the code example we simply replace the default log
20 | filter with a new filter that specifies a value for the “path” field. We'll come back to the factorial example later.
21 |
22 | Step by step:
23 | First the function *get_filter* assoziates the new filter *f* with the logging stream of the
24 | [connection analyzer log strteam](https://docs.zeek.org/en/current/scripts/base/protocols/conn/).
25 | After that the new name `myconn` is set. This new filter has to be added to the logging stream.
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/manager/static/examples/modules/export/factorial.zeek:
--------------------------------------------------------------------------------
1 | module Factor;
2 |
3 | export {
4 | global factorial: function(n: count): count;
5 | }
6 |
7 | function factorial(n: count): count
8 | {
9 | if ( n == 0 )
10 | return 1;
11 |
12 | else
13 | return ( n * factorial(n - 1) );
14 | }
15 |
--------------------------------------------------------------------------------
/manager/static/examples/modules/export/main.zeek:
--------------------------------------------------------------------------------
1 | @load factorial
2 |
3 | event zeek_done()
4 | {
5 | local numbers: vector of count = vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
6 | for ( n in numbers )
7 | print fmt("%d", Factor::factorial(numbers[n]));
8 | }
9 |
--------------------------------------------------------------------------------
/manager/static/examples/modules/export/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Writing a Module: Export
2 | pcaps:
3 |
4 | Writing a Module: Export
5 | =========================
6 |
7 | In this tutorial you will create a module that computes the factorial function (n!)
8 | and writes the result to a log file.
9 |
10 | As said before a module is a semantic entity. This means also that all variables and
11 | functions that you want to use outside of that entity need to be made available.
12 | In Zeek this is done through an `export` block.
13 |
14 | In the example here you see two Zeek files. One is the module-script factorial.zeek,
15 | one is main.zeek, the script that uses the module the resulting values. You can simply click on the
16 | tabs with the file names to switch between the Zeek-files.
17 |
18 | Let's have a closer look on the code.
19 | The first line declares that this is a module named Factor.
20 | We will come back to this later.
21 | The next thing is the export environment. Every record, variable, and function
22 | that needs to be accessed from other scripts has to go here.
23 | In this case the export environment contains a function declaration,
24 | expecting one parameter, returning one result value, both of type count.
25 | Note that export values always have to be `global`. Otherwise they can't be used
26 | later.
27 |
28 | The second part is the function implementation that simply computes the factorial of
29 | a given *n*.
30 |
31 | Now switch tabs and looks at main.zeek. The first line is the already
32 | known `load`-statement. This time it loads factorial.zeek.
33 | Inside the event we define a vector of length 9, our *n*s that we will
34 | give to the function as parameters.
35 | Then we call iterate over the vector, calling the function and printing the result.
36 | Note the syntax for calling the function. Before the function name we have to give the
37 | module name (Factor not factorial). Every time a parameter or function from the export-section needs
38 | to be used the module name has to be given, too.
39 |
40 |
--------------------------------------------------------------------------------
/manager/static/examples/modules/index:
--------------------------------------------------------------------------------
1 | module
2 | export
3 | log-factorial
4 |
--------------------------------------------------------------------------------
/manager/static/examples/modules/log-factorial/factorial.zeek:
--------------------------------------------------------------------------------
1 | module Factor;
2 |
3 | export {
4 | # Append the value LOG to the Log::ID enumerable.
5 | redef enum Log::ID += { LOG };
6 |
7 | # Define a new type called Factor::Info.
8 | type Info: record {
9 | num: count &log;
10 | factorial_num: count &log;
11 | };
12 | global factorial: function(n: count): count;
13 | }
14 |
15 | function factorial(n: count): count
16 | {
17 | if ( n == 0 )
18 | return 1;
19 |
20 | else
21 | return ( n * factorial(n - 1) );
22 | }
23 |
--------------------------------------------------------------------------------
/manager/static/examples/modules/log-factorial/main.zeek:
--------------------------------------------------------------------------------
1 | @load factorial
2 |
3 | event zeek_init()
4 | {
5 | # Create the logging stream.
6 | Log::create_stream(Factor::LOG, [$columns=Factor::Info, $path="factor"]);
7 | }
8 |
9 | event zeek_done()
10 | {
11 | local numbers: vector of count = vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
12 | for ( n in numbers )
13 | Log::write( Factor::LOG, [$num=numbers[n],
14 | $factorial_num=Factor::factorial(numbers[n])]);
15 | }
16 |
--------------------------------------------------------------------------------
/manager/static/examples/modules/log-factorial/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Writing a Module: Logging
2 | pcaps:
3 |
4 | Writing a Module: Logging
5 | =========================
6 |
7 | Often a new module creates new data that you may want to collect in a new log file, too.
8 | Manipulating Logs in Zeek is a useful tool and is more than just adding more log-files or fields.
9 | We use the case of the factorial module to introduce you to the [logging framework](https://docs.zeek.org/en/current/frameworks/logging.html)
10 |
11 | Again, we first look into factorial.zeek.
12 | In the export section you find a new line that uses `redef` to add a new value named `LOG`
13 | to the `Log::ID` enumerable. This enumerable is part of Zeek's logging framework. You can find details
14 | [here](https://docs.zeek.org/en/current/scripts/base/frameworks/logging/main.zeek.html).
15 |
16 | The next step is to create a record that contains the columns of the future log file. The record
17 | is named `Info`. We create two columns named `num` and `factorial_num`. `num` is there to list the current value
18 | of `n`, `factorial_num` logs the factorial of `n`. Both variables have the attribute `&log` which
19 | tells Zeek that a field of the given name has to be added to the logging stream.
20 |
21 | During this tutorial you have already seen some attributes. Attributes are used to add certain properties to functions and
22 | variables. For example the `&redef` attribute allows to redefine a global constant or extend a type. `&optional` allows a
23 | value in a record field to be missing. The list of all attributes is found [here](https://docs.zeek.org/en/current/script-reference/attributes.html?highlight=attributes).
24 |
25 | Now please switch to the file main.zeek. At the beginning of our script we need to create the new logging
26 | stream. [Log::create\_stream](https://docs.zeek.org/en/current/scripts/base/frameworks/logging/main.zeek.html?highlight=log%3A%3Acreate_stream#id-Log::create_stream) does exactly this.
27 | The necessary parameters are of course the module's `LOG` value, and the record that holds the logging fields.
28 | The variable `$path` tells Zeek how it should name the new log-file. Note that the Log stream needs to be initialized within the zeek\_init event.
29 |
30 | The next step looks very similar to the one before, but instead of printing the results to Stdout we now
31 | write to the new log, using the [Log::write](https://docs.zeek.org/en/current/scripts/base/frameworks/logging/main.zeek.html?highlight=log%3A%3Awrite#id-Log::write) function.
32 |
33 | One more note on writing to logs: In this example we wrote all results within zeek\_done, in a real world example this
34 | is usually done inside an event handler that has to do with the log-file.
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/manager/static/examples/modules/module/main.zeek:
--------------------------------------------------------------------------------
1 | event zeek_init()
2 | {
3 | print "Welcome back!";
4 | }
5 |
6 | event zeek_done()
7 | {
8 | print "Ready to write a module?";
9 | }
10 |
--------------------------------------------------------------------------------
/manager/static/examples/modules/module/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Writing a Module
2 | pcaps:
3 |
4 | Writing a Module
5 | =====================
6 |
7 | A module in Zeek is a semantic entity that defines a new name space.
8 | The work flow usually is that solving a problem results in a new module.
9 | A module can be a file or a bundle of files, a package. See below on this page.
10 |
11 | It is important to know
12 | that you cannot write new protocol events, you can only react in a different way on an event that is already implemented
13 | in Zeek. Extending Zeek with [new analyzers](https://old.zeek.org/development/howtos/dpd.html) and
14 | creating new events is a topic that is beyond the scope of Try.Zeek.
15 | Usually a module reacts on already existing internal events coming from the Zeek event engine.
16 | Events that are not working on traffic can created within a Zeek script, though.
17 |
18 | Before you dive into Zeek Modules we would like to point you on the
19 | [Zeek Scripting Conventions](https://old.zeek.org/development/howtos/script-conventions.html).
20 | Apart from naming conventions the Zeek scripts sets use a convention for file-names and
21 | the setup of Modules. We've already talked about
22 | [loading scripts](http://try.zeek.org/examples/loading). If you have a look into the
23 | [Zeek Script Packages](https://docs.zeek.org/en/current/script-reference/packages.html)
24 | you will find that each Module consists at least of two files, `__load__.zeek` and
25 | `main.zeek`. The first one should list all files that are part of the module (also `main.zeek`)
26 | The directory name in which all those files are collected gives the name to the module.
27 | When loading a module Zeek will look into this directory expecting the `__load__.zeek` script.
28 | In this tutorial we will not use this convention most of the time since we keep all examples in Try.Zeek.
29 | If you want to convert the final Zeek Module that we create in this tutorial to test it with your Zeek installation you can also
30 | try the naming conventions for Zeek Modules.
31 |
32 | For the next lessons you will need the knowledge from the previous lessons.
33 |
--------------------------------------------------------------------------------
/manager/static/examples/new-notice/factorial.zeek:
--------------------------------------------------------------------------------
1 | module Factor;
2 |
3 | export {
4 | redef enum Log::ID += { LOG };
5 | #Append a new notice value to the Notice::Type enumerable.
6 | redef enum Notice::Type += { Interesting_Result };
7 |
8 | const interesting_result = 120 &redef;
9 |
10 | type Info: record {
11 | num: count &log;
12 | factorial_num: count &log;
13 | };
14 | global factorial: function(n: count): count;
15 | global mod5: function(id: Log::ID, path: string, rec: Factor::Info) : string;
16 | global result : count = 0;
17 | }
18 |
19 | function factorial(n: count): count
20 | {
21 | if ( n == 0 )
22 | {
23 | result = 1;
24 | return 1;
25 | }
26 |
27 | else
28 | {
29 | result = n * factorial(n - 1);
30 | return result;
31 | }
32 | }
33 |
34 | function mod5(id: Log::ID, path: string, rec: Factor::Info) : string
35 | {
36 | if ( rec$factorial_num % 5 == 0 )
37 | return "factor-mod5";
38 |
39 | else
40 | return "factor-non5";
41 | }
42 |
--------------------------------------------------------------------------------
/manager/static/examples/new-notice/main.zeek:
--------------------------------------------------------------------------------
1 | @load factorial
2 |
3 | event zeek_init()
4 | {
5 | Log::create_stream(Factor::LOG, [$columns=Factor::Info, $path="factor"]);
6 |
7 | local filter: Log::Filter = [$name="split-mod5s", $path_func=Factor::mod5];
8 | Log::add_filter(Factor::LOG, filter);
9 | Log::remove_filter(Factor::LOG, "default");
10 | }
11 |
12 | event zeek_done()
13 | {
14 | local numbers: vector of count = vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
15 | for ( i in numbers )
16 | {
17 | local result = Factor::factorial(numbers[i]);
18 | Log::write( Factor::LOG, [$num=numbers[i],
19 | $factorial_num=result]);
20 | if ( result == Factor::interesting_result)
21 | {
22 | NOTICE([$note=Factor::Interesting_Result,
23 | $msg = "Something happened!",
24 | $sub = fmt("result = %d", result)]);
25 | }
26 | }
27 | }
28 |
29 |
30 |
--------------------------------------------------------------------------------
/manager/static/examples/new-notice/readme.markdown:
--------------------------------------------------------------------------------
1 | title: Raising a Notice
2 | pcaps:
3 |
4 | Raising a Notice
5 | =====================
6 |
7 | One of the easiest ways to customize Zeek is writing a local notice policy.
8 | Apart from looking into log files you can ask Zeek to send you emails, either for a
9 | certain situation or aggregated summary emails about warnings etc.
10 | This feature is given through the [Notice Framework](https://docs.zeek.org/en/current/frameworks/notice.html).
11 |
12 | In this lesson we start by creating a new notice. In Try.Zeek the notice can only be made into a log file.
13 | It can't send an email. Please run the code example and have a look at the new log-file.
14 | Apart from the message itself it tells you the name of the notice. This is especially useful for aggregated summaries.
15 |
16 | Lets have a look on the code. Start with factorial.zeek. We append a new notice type value in the export section.
17 | For this example we say that *120* is an interesting value we want to be notified about. So we make it a constant that
18 | can be changed to something else later.
19 | Now the Factor moudle can be asked to rais a notice.
20 |
21 | In main.zeek, every time the factorial is computed we ask if it is an interesting result.
22 | If so, the notice is raised. The fields `msg` and `sub` are given. You can put any text there that will later help you
23 | to find out what you need. The Notice Framework can be a little confusing. It is easier to handle if you
24 | remind yourself that it is simply a function.
25 |
26 | Sending emails through the Notice Frameworks requires a working sendmail config on your system. This lesson should give you a start with this topic. Please go ahead and try it out within your local Zeek installation.
27 |
28 |
--------------------------------------------------------------------------------
/manager/static/examples/pack.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # encoding=utf8
3 | import sys
4 |
5 | import os
6 | import glob
7 | import json
8 | import markdown
9 |
10 |
11 | HELP_FILE = "readme.markdown"
12 | MULTI_VALUE_FIELDS = ['pcaps']
13 |
14 | def main_first_sort_key(f):
15 | if f['name'] == 'main.zeek':
16 | return (0, '')
17 | else:
18 | return (1, f['name'])
19 |
20 | def redirect_example_links(source):
21 | return source.replace("http://try.zeek.org/example/", "#/trybro?example=")
22 |
23 | def clean_path(path):
24 | if path.startswith("./"):
25 | path = path[2:]
26 | if path == '.':
27 | path = ''
28 | return path
29 |
30 | def fix_path(path):
31 | return clean_path(path).replace("/", "-")
32 |
33 | def pack(example):
34 | sources = []
35 | for fn in os.listdir(example):
36 | if fn == HELP_FILE: continue
37 | full = os.path.join(example, fn)
38 | with open(full) as f:
39 | sources.append({
40 | "name": fn,
41 | "content": f.read(),
42 | })
43 |
44 | sources.sort(key=main_first_sort_key)
45 |
46 | packed_example = {
47 | 'sources': sources,
48 | 'path': fix_path(example),
49 | 'parent': clean_path(os.path.dirname(example))
50 | }
51 |
52 | full_help_filename = os.path.join(example, HELP_FILE)
53 | if os.path.exists(full_help_filename):
54 | md = markdown.Markdown(extensions = ['markdown.extensions.meta', 'markdown.extensions.tables'])
55 | with open(full_help_filename) as f:
56 | source = f.read()
57 | source = redirect_example_links(source)
58 | html = md.convert(source)
59 | #HACK, FIXME: We are having issues with | chars inside tables
60 | #The python parser doesn't seem to support \|, at least not inside code blocks
61 | #This hack lets ``|`` be rendered as a | in a code block.
62 | html = html.replace("|", "|")
63 | packed_example['html'] = html
64 | for k, vs in md.Meta.items():
65 | if k not in MULTI_VALUE_FIELDS:
66 | packed_example[k] = vs[0]
67 | else:
68 | packed_example[k] = vs
69 |
70 | return packed_example
71 |
72 | def read_index(fn):
73 | with open(fn) as f:
74 | return f.read().split()
75 |
76 | def pack_recursive(e):
77 |
78 | directory_children = os.listdir(e)
79 | if 'index' in directory_children:
80 | index = read_index(os.path.join(e, "index"))
81 | children = { f: pack_recursive(os.path.join(e, f)) for f in index }
82 | example = { "path": fix_path(e), "index": index, "children": children, "child_count": len(children)}
83 | else:
84 | example = pack(e)
85 |
86 | return example
87 |
88 | add_next(examples)
89 |
90 | def flatten(examples, flat=None):
91 | if flat is None:
92 | flat = []
93 | if 'index' in examples:
94 | for i in examples['index']:
95 | flatten(examples['children'][i], flat)
96 | else:
97 | flat.append(examples)
98 |
99 | return flat
100 |
101 | def add_next_and_prev(flattened):
102 | prev = None
103 | for f in flattened:
104 | f['prev'] = prev
105 | prev = {'path': f['path'], 'title': f['title']}
106 |
107 | next = None
108 | for f in reversed(flattened):
109 | f['next'] = next
110 | next = {'path': f['path'], 'title': f['title']}
111 |
112 |
113 | def main():
114 | examples = pack_recursive(".")
115 | flat = flatten(examples)
116 |
117 | add_next_and_prev(flat)
118 |
119 | with open("examples.json", 'w') as f:
120 | json.dump(flat, f)
121 |
122 | if __name__ == "__main__":
123 | main()
124 |
--------------------------------------------------------------------------------
/manager/static/examples/sumstats/index:
--------------------------------------------------------------------------------
1 | sumstats1
2 | sumstats2
3 | sumstats3
4 |
--------------------------------------------------------------------------------
/manager/static/examples/sumstats/sumstats1/main.zeek:
--------------------------------------------------------------------------------
1 | @load base/frameworks/sumstats
2 | event zeek_init()
3 | {
4 | local r1 = SumStats::Reducer($stream="dns.lookup", $apply=set(SumStats::UNIQUE));
5 | SumStats::create([$name="dns.requests.unique",
6 | $epoch=6hrs,
7 | $reducers=set(r1),
8 | $epoch_result(ts: time, key: SumStats::Key, result: SumStats::Result) =
9 | {
10 | local r = result["dns.lookup"];
11 | print fmt("%s did %d total and %d unique DNS requests in the last 6 hours.",
12 | key$host, r$num, r$unique);
13 | }]);
14 | }
15 |
16 | event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count)
17 | {
18 | if ( c$id$resp_p == 53/udp && query != "" )
19 | SumStats::observe("dns.lookup", [$host=c$id$orig_h], [$str=query]);
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/manager/static/examples/sumstats/sumstats1/readme.markdown:
--------------------------------------------------------------------------------
1 | title: The Summary Statistics Framework
2 | pcaps: exercise_traffic.pcap
3 |
4 | The Summary Statistics Framework
5 | ==================================
6 |
7 | The Summary Statistics framework (short sumstats) is a very useful tool to get a deep understanding
8 | about what
9 | is going on in your network. A good example is the scan-detector that correlates many short,
10 | maybe even failed connections that seem unrelated, together and gives a warning about
11 | a scanner activity. To many users this framework appears difficult to use. This tutorial
12 | is meant to change that.
13 |
14 | Alongside this tutorial you can read the
15 | [documentation](https://docs.zeek.org/en/current/frameworks/sumstats.html)
16 | explaining the terminology used for the Sumstats framework. This tutorial follows (in parts)
17 | the live tutorial Seth Hall gave at BroCon 2014, which is available as Youtube
18 | [video](https://youtu.be/9YsenekNaSI)
19 |
20 |
21 | Run the code to the left and have a look on the output. Now lets go through the code.
22 |
23 | First sumstats needs something to count, i.e. a Zeek event. For this example we chose the event
24 | "dns\_request", we will count unique DNS requests, that is unique requests per host.
25 | The "if" line is there to ensure real DNS requests (via port 53) that are also not empty.
26 | This specific case would quickly kill the memory of your Zeek system, because it collects
27 | every unique DNS request for every host it can see, so one option would be to limit this to port
28 | 53, non-empty requests and only local hosts.
29 | If it is a real request where we want to observe something, that is where the sumstats observer is used.
30 | The string dns.lookup is an arbitrary name, it could be something else. The principle is that a stream
31 | of information is observed (counted), the stream gets a name to later be addressed by.
32 | The next part is the key, in this case the host which sends the request. To know the actual unique request
33 | also the query string needs to be part of the key.
34 |
35 | Now there is a stream that is observed, the next step is to reduce (i.e. summarize) the stream and then do
36 | something with it. The reducer gets a variable name, r1 in this case, is attached to the stream named
37 | dns.lookup and also needs at least one reducing function that is applied on the stream.
38 | In this example the method used is "UNIQUE".
39 | More than one calculation method can be applied, they are all listed in the
40 | [sumstats reference](https://docs.zeek.org/en/current/scripts/base/frameworks/sumstats/main.zeek.html#type-SumStats::Calculation).
41 | There can also be more than one reducer, an example for this is explained in the documentation for
42 | [MIME type statistics](https://docs.zeek.org/en/current/mimestats/index.html).
43 |
44 | The third step is to link the reducer to a SumStats to finally do something with it.
45 | The SumStats also gets a name to reference later. An epoch is assigned, in this case 6 hours.
46 | After 6 hours or the end of the trace it will come back with the results.
47 | The reducer (or set of reducers) is attached.
48 | The call back function is epoch result which is the key given in the observer before,
49 | and it will give you the result.
50 | Now you can access the results for the stream named dns.lookup. In this case we print the host,
51 | the total number of DNS requests and the number of unique requests.
52 |
53 | Comment out the two lines within the epoch\_result and directly print result. You can see
54 | all fields available to print out.
55 |
56 | Exercise: Use the heuristic version of the unique calculation, HLL\_UNIQUE, you find it
57 | in the [documentation](https://docs.zeek.org/en/current/scripts/base/frameworks/sumstats/main.zeek.html#type-SumStats::Calculation). Then take a sample of size 5. For the solution go to the next page.
58 |
--------------------------------------------------------------------------------
/manager/static/examples/sumstats/sumstats2/main.zeek:
--------------------------------------------------------------------------------
1 | @load base/frameworks/sumstats
2 | event zeek_init()
3 | {
4 | local r1 = SumStats::Reducer($stream="dns.lookup", $apply=set(SumStats::HLL_UNIQUE, SumStats::SAMPLE), $num_samples=5);
5 | SumStats::create([$name="dns.requests.unique",
6 | $epoch=6hrs,
7 | $reducers=set(r1),
8 | $epoch_result(ts: time, key: SumStats::Key, result: SumStats::Result) =
9 | {
10 | local r = result["dns.lookup"];
11 | print fmt("%s did %d total and %d unique DNS requests in the last 6 hours.",
12 | key$host, r$num, r$hll_unique);
13 | }]);
14 | }
15 |
16 | event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count)
17 | {
18 | if ( c$id$resp_p == 53/udp && query != "" )
19 | SumStats::observe("dns.lookup", [$host=c$id$orig_h], [$str=query]);
20 | }
21 |
--------------------------------------------------------------------------------
/manager/static/examples/sumstats/sumstats2/readme.markdown:
--------------------------------------------------------------------------------
1 | title: SumStats Exercise Solution
2 | pcaps: exercise_traffic.pcap
3 |
4 | SumStats Exercise Solution
5 | ==============================
6 |
7 | On the left is the solution to the exercise. Note that you not only need to change the reducer but also
8 | the field names in the print statement. Try again to print the whole result to see all the options.
9 | Also for this traffic example the probabilistic calculation is too good and you won't see a difference.
10 | You can print out the fields hll\_error\_margin hll\_confidence to see the error that is made by using
11 | this option. Both parameters can also be set using the same syntax as for the sample size.
12 |
13 | Next Exercise
14 | -------------
15 |
16 | Sumstats becomes especially useful if used with thresholds. Write a sumstats script
17 | that counts the DNS lookups and writes a notice if a host does more than 10 DNS lookups.
18 | Have a look at the available SumStat
19 | [functions](https://docs.zeek.org/en/current/scripts/base/frameworks/sumstats/main.zeek.html?highlight=sumstats#type-SumStats::SumStat)
20 | to find out how to work with thresholds.
21 |
--------------------------------------------------------------------------------
/manager/static/examples/sumstats/sumstats3/main.zeek:
--------------------------------------------------------------------------------
1 | @load base/frameworks/sumstats
2 |
3 | redef enum Notice::Type +=
4 | {
5 | ExcessiveRequests
6 | };
7 |
8 | const excessive_limit: double = 10 &redef;
9 |
10 | event zeek_init()
11 | {
12 | local r1 = SumStats::Reducer($stream="dns.lookup", $apply=set(SumStats::SUM));
13 | SumStats::create([$name="dns.requests",
14 | $epoch=6hrs,
15 | $threshold = excessive_limit,
16 | $reducers=set(r1),
17 | $threshold_val(key: SumStats::Key, result: SumStats::Result) =
18 | {
19 | return result["dns.lookup"]$sum;
20 | },
21 | $threshold_crossed(key: SumStats::Key, result: SumStats::Result) =
22 | {
23 | local r = result["dns.lookup"];
24 | NOTICE([
25 | $note=ExcessiveRequests,
26 | $src=key$host,
27 | $msg=fmt("%s has made more than %.0f DNS requests.", key$host, r$sum),
28 | $sub=cat(r$sum),
29 | $identifier=cat(key$host)
30 | ]);
31 | }
32 | ]);
33 | }
34 |
35 | event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count)
36 | {
37 | if ( c$id$resp_p == 53/udp && query != "" )
38 | SumStats::observe("dns.lookup", [$host=c$id$orig_h], [$str=query]);
39 | }
40 |
41 |
--------------------------------------------------------------------------------
/manager/static/examples/sumstats/sumstats3/readme.markdown:
--------------------------------------------------------------------------------
1 | title: SumStats Exercise Solution
2 | pcaps: sumstat.pcap
3 |
4 | SumStats Exercise Solution
5 | ==================================
6 |
7 | On the left is the solution to the exercise.
8 | As seen before in this tutorial to raise a notice we need to add a new type of notice.
9 | Instead of UNIQUE this time we calculate the sum of all requests. 10 is a very low number but serves the
10 | purpose of an exercise. This time we don't use the epoch result but react to a crossed threshold.
11 | In order to do this we need to evaluate the threshold first, once it is crossed we send out the notice.
12 | Within this platform we can only write it to the notice.log but in reality it can of course be sent as
13 | an email to warn the security admin about suspicious behavior.
14 |
--------------------------------------------------------------------------------
/manager/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeek/try-zeek/764c096477c823348b20dc5bf4b2b2586deba6ce/manager/static/favicon.ico
--------------------------------------------------------------------------------
/manager/static/pcaps/exercise_traffic.pcap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeek/try-zeek/764c096477c823348b20dc5bf4b2b2586deba6ce/manager/static/pcaps/exercise_traffic.pcap
--------------------------------------------------------------------------------
/manager/static/pcaps/http.pcap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeek/try-zeek/764c096477c823348b20dc5bf4b2b2586deba6ce/manager/static/pcaps/http.pcap
--------------------------------------------------------------------------------
/manager/static/pcaps/ssh.pcap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeek/try-zeek/764c096477c823348b20dc5bf4b2b2586deba6ce/manager/static/pcaps/ssh.pcap
--------------------------------------------------------------------------------
/manager/static/pcaps/sumstat.pcap:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeek/try-zeek/764c096477c823348b20dc5bf4b2b2586deba6ce/manager/static/pcaps/sumstat.pcap
--------------------------------------------------------------------------------
/manager/templates/base.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Try Zeek
12 | {% block title %}
13 | {% endblock %}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
30 |
31 |
32 |
33 |
34 |
36 |
37 |