2020-11-16 Zeek Script

2020-11-20  本文已影响0人  黑小柴

@load

Zeek可以从其他文件中load脚本, 用@load就可以
@load misc/dump-events 用于输出所有日志, 用于debug

zeek默认路径, 可以直接load?
<prefix>/share/zeek
<prefix>/share/zeek/policy
<prefix>/share/zeek/site

@load操作最常用的脚本为/site/local.zeek, 此脚本包含部分zeek的配置信息, 可以添加一些不被默认装载的脚本.
目录<PREFIX>/share/zeek 中/base下的脚本全部会自动被装载.
目录<PREFIX>/share/zeek 中/policy 需要手动装载.

函数

function emphasize(s: string, p:string &default="*"): string{
    return p+s+p;
}

event zeek_init(){
    print emphasize("yes");
    print emphasize("no","-");
}

*yes*
-no-

function 函数名(变量名:类型 &属性): 函数返回值类型{
}

变量

变量的声明是弱类型
常用的有local/global/const等接变量名
也可local/global/const 变量名:变量类型
ps: 没有i++只有++i

原生数据类型

https://docs.zeek.org/en/current/script-reference/types.html

    print /one|two|three/ == "two";  # T
    print /one|two|three/ == "ones"; # F (exact matching)
    print /one|two|three/ in "ones"; # T (embedded matching)
    print /[123].*/ == "2 two";  # T
    print /[123].*/ == "4 four"; # F

features:
count, pattern(正则), time, interval, port, addr, subnet

Zeek 数据类型

event zeek_init()
    {
    print network_time();
    local d:double=111111111.123456789;
    print double_to_time(d);
    
    local t:time=double_to_time(d);
    
    local i:interval=network_time()-t;
    print i;
    
    local p:port=53/tcp;
    print p;
    
    if (127.0.0.1 in 127.0.0.0/31)
        print 222222222222;
    }

type casting

http://mailman.icsi.berkeley.edu/pipermail/zeek/2017-January/011178.html

function example(a: any)
    {
    local s: string;

    if ( a is string )
        s = (a as string);
    }

for if 格式化print

event zeek_init() 
    { 
    local x = "3";

    for ( c in "12345" )
        {
        if ( c == x )
            {
            print "Found it.";
            # A preview of functions: fmt() does substitutions, outputs result.
            print fmt("And by 'it', I mean %s.", x);
            }
        else
            {
            # A quick way to print multiple things on one line.
            print "I'm looking for", x, "not", c;
            }
        }
    }

for 和 while

switch语句接多个条件

event zeek_init() 
    { 
    local result = 0;
    local input = "The Zeek Network Security Monitor";
    for ( c in input )
        {
        switch ( c ) 
            {
            case "a", "e", "i", "o", "u":
                ++result;
                break;
            }
        }
    print result;
    }

event

一些与协议无关的事件, 即不通过协议状态触发的事件
https://docs.zeek.org/en/current/scripts/base/bif/event.bif.zeek.html

global myevent: event(s: string);

global n = 0;

event myevent(s: string) &priority = -10
    {
    ++n;
    }

event myevent(s: string) &priority = 10
    {
    print "myevent", s, n;
    }

event zeek_init()
    {
    print "zeek_init()";
    event myevent("hi");
    schedule 5 sec { myevent("bye") };
    }

event zeek_done()
    {
    print "zeek_done()";
    }

zeek_init()
myevent, hi, 0
myevent, bye, 1
zeek_done()

schedule 5 sec{}, 五秒后执行或在zeek进程结束前执行

hook

hook 是另一种形式的函数,和event的相同点是可以多次定义, 被调用时按照&priority顺序执行。
和event的不同点为:

global myhook: hook(s: string);

hook myhook(s: string) &priority = 10
    {
    print "priority 10 myhook handler", s;
    s = "bye";
    }

hook myhook(s: string)
    {
    print "break out of myhook handling", s;
    break;
    }

hook myhook(s: string) &priority = -5
    {
    print "not going to happen", s;
    }

event zeek_init() 
    {
    local ret: bool = hook myhook("hi");
    if ( ret )
        {
        print "all handlers ran";
        }
    }

priority 10 myhook handler, hi
break out of myhook handling, hi

Set

集合, 通过add和delete操作.
local x: set[string]={"one","two","three"};

event zeek_init()
    {
    local x: set[string] = { "one", "two", "three" };
    add x["four"];
    print "four" in x; # T
    delete x["two"];
    print "two" !in x; # T
    add x["one"]; # x is unmodified since 1 is already a member.

    for ( e in x )
        {
        print e;
        }
    }

T
T
one
three
four

Table

event zeek_init() 
    { 
    local x: table[count] of string = { [1] = "one", 
                                        [3] = "three",
                                        [5] = "five" };
    x[7] = "seven";
    print 7 in x; # T
    print x[7]; # seven
    delete x[3];
    print 3 !in x; # T
    x[1] = "1"; # changed the value at index 1

    for ( key in x ) 
        {
        print key,x[key];
        }
    }

T
seven
T
1, 1
5, five
7, seven

Vector

event zeek_init() 
    { 
    local x: vector of string = { "one", "two", "three" };
    print x; # [one, two, three]
    print x[1]; # two
    x[|x|] = "one";
    print x; # [one, two, three, one]

    for ( i in x ) 
        {
        print i;  # Iterates over indices.
        }
    }
[one, two, three]
two
[one, two, three, one]
0
1
2
3

其中第6行为向容器中添加一个新元素, |x|表示容器的长度.

Record

类似结构体, 通过$符号来索引结构体中成员(用.会跟ip地址冲突)
通过?$判断成员是否存在.
type代表用户自定义类型

type MyRecord: record {
    a: string;
    b: count;
    c: bool &default = T;
    d: int &optional;
};

event zeek_init() 
    { 
    local x = MyRecord($a = "vvvvvv", $b = 6, $c = F, $d = -13);
    if ( x?$d )
        {
        print x$d;
        }
    
    x = MyRecord($a = "abc", $b = 3);
    print x$c;  # T (default value of the field)
    print x?$d; # F (optional field was not set)
    }

Record 的重定义

record和enum这种用户自定义类型可以拓展

type MyRecord: record {
    a: string &default="hi";
    b: count  &default=7;
} &redef;

redef record MyRecord += {
    c: bool &optional;
    d: bool &default=F;
    #e: bool; # Not allowed, must be &optional or &default.
};


event zeek_init() 
    {
    print MyRecord();
    print MyRecord($c=T);
    }

[a=hi, b=7, c=<uninitialized>, d=F]
[a=hi, b=7, c=T, d=F]

e.g.

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 };
global my_count = 0;
global inside_networks: set[addr];
global outside_networks: set[addr];

event new_connection(c: connection)
    {
    ++my_count;
    if ( my_count <= 10 )
    {
        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)); 
        #print c$start_time;
    }
    if ( c$id$orig_h in local_subnets)
        {
    add inside_networks[c$id$orig_h];
        }
    else
        add outside_networks[c$id$orig_h];
        
    if ( c$id$resp_h in local_subnets)
        {
        add inside_networks[c$id$resp_h];
        }
    else
        add outside_networks[c$id$resp_h];
    }

event connection_state_remove(c: connection)
    {
    if ( my_count <= 10 )
        {
        print fmt("Connection %s took %s seconds", c$uid, c$duration);  
        }
    }

event zeek_done() 
    {
    print fmt("Saw %d new connections", my_count);
    print "These IPs are considered local";
    for (a in inside_networks)
        {
        print a;
        }
    print "These IPs are considered external";
    for (a in outside_networks)
        {
        print a;
        }
    }

The connection Cy1Vgd4iLmOBM7JTD3 from 192.168.1.1 on port 626/udp to 224.0.0.1 on port 626/udp started at 11/18/09 08:00.
Connection CJj7Bl4if8upezvIAk took 163.0 msecs 820.028305 usecs seconds

Module

@load factorial

event zeek_done()
    {
    local numbers: vector of count = vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);    
    for ( n in numbers )
        print fmt("%d", Factor::factorial(numbers[n]));
    }

factorial.zeek

module Factor;

export {
    global factorial: function(n: count): count;
    }
    
function factorial(n: count): count
    {
    if ( n == 0 )
        return 1;
    
    else
        return ( n * factorial(n - 1) );
    }

Manipulating Logs

main.zeek

@load factorial

event zeek_init()
    {
    # Create the logging stream.
    Log::create_stream(Factor::LOG, [$columns=Factor::Info, $path="factor"]);
    }

event zeek_done()
    {
    local numbers: vector of count = vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);    
    for ( n in numbers )
        Log::write( Factor::LOG, [$num=numbers[n],
                                  $factorial_num=Factor::factorial(numbers[n])]);
    }

factorial.zeek

module Factor;

export {
    # Append the value LOG to the Log::ID enumerable.
    redef enum Log::ID += { LOG };

    # Define a new type called Factor::Info.
    type Info: record {
        num:           count &log;
        factorial_num: count &log;
        };
    global factorial: function(n: count): count;
    }
    
function factorial(n: count): count
    {
    if ( n == 0 )
        return 1;
    
    else
        return ( n * factorial(n - 1) );
    }

Filtering Logs

main.zeek

@load factorial

event zeek_init()
    {
    Log::create_stream(Factor::LOG, [$columns=Factor::Info, $path="factor"]);
    
    local filter: Log::Filter = [$name="split-mod5s", $path_func=Factor::mod5];
    Log::add_filter(Factor::LOG, filter);
    Log::remove_filter(Factor::LOG, "default");
    }

event zeek_done()
    {
    local numbers: vector of count = vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);    
    for ( n in numbers )
        Log::write( Factor::LOG, [$num=numbers[n],
                                  $factorial_num=Factor::factorial(numbers[n])]);
    }

factorial.zeek

module Factor;

export {
    # Append the value LOG to the Log::ID enumerable.
    redef enum Log::ID += { LOG };

    # Define a new type called Factor::Info.
    type Info: record {
        num:           count &log;
        factorial_num: count &log;
        };
    global factorial: function(n: count): count;
    global mod5: function(id: Log::ID, path: string, rec: Factor::Info) : string;
    }
    
function factorial(n: count): count
    {
    if ( n == 0 )
        return 1;
    
    else
        return ( n * factorial(n - 1) );
    }
    
function mod5(id: Log::ID, path: string, rec: Factor::Info) : string    
    {
    if ( rec$factorial_num % 5 == 0 )
        return "factor-mod5";
    
    else
        return "factor-non5";
    }

Notice

https://docs.zeek.org/en/current/frameworks/notice.html
redef enum Notice::Type += { Interestring_Result};

NOTICE([$note=Factor::Interesting_Result, $msg = "Something happened!", $sub = fmt("result = %d", result)]);

SumStats Framework

@load base/frameworks/sumstats
event zeek_init()
    {
    local r1 = SumStats::Reducer($stream="dns.lookup", $apply=set(SumStats::UNIQUE));
    SumStats::create([$name="dns.requests.unique",
                      $epoch=6hrs,
                      $reducers=set(r1),
                      $epoch_result(ts: time, key: SumStats::Key, result: SumStats::Result) =
                        {
                        local r = result["dns.lookup"];
                        print fmt("%s did %d total and %d unique DNS requests in the last 6 hours.", 
                                    key$host, r$num, r$unique);
                        }]);
    }

event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count)
    {
    if ( c$id$resp_p == 53/udp && query != "" )
        SumStats::observe("dns.lookup", [$host=c$id$orig_h], [$str=query]);
    }
上一篇下一篇

猜你喜欢

热点阅读