当前位置: 首页 > 工具软件 > Zeek > 使用案例 >

zeek脚本语言编写入门

姬凡
2023-12-01

其实大部分都是文档翻译的(也许是全部)
https://docs.zeek.org/en/current/examples/scripting/index.html

概述

扩展名为.zeek
默认目录:share/zeek
放在share/zeek/site的不会在升级时被覆盖或者修改
zeek生成的事件可以参考:base/bif/event.bif.zeek
*.bif是zeek的内建函数文件,也是生成在线文档的基础。
zeek脚本语法参考:https://docs.zeek.org/en/current/script-reference/index.html
框架参考:https://docs.zeek.org/en/current/frameworks/index.html

脚本示例

@load

定义脚本使用的库

@load base/frameworks/files
@load base/frameworks/notice
@load frameworks/files/hash-all-files

确保zeek加载了文件框架,通知框架和hash所有文件的脚本

module

定义命名空间

module TeamCymruMalwareHashRegistry;

export

解释自定义变量,作为脚本命令空间的一部分

export {
    redef enum Notice::Type += {
        ## The hash value of a file transferred over HTTP matched in the
        ## malware hash registry.
        Match
    };

    ## File types to attempt matching against the Malware Hash Registry.
    option match_file_types = /application\/x-dosexec/ |
                             /application\/vnd.ms-cab-compressed/ |
                             /application\/pdf/ |
                             /application\/x-shockwave-flash/ |
                             /application\/x-java-applet/ |
                             /application\/jar/ |
                             /video\/mp4/;

    ## The Match notice has a sub message with a URL where you can get more
    ## information about the file. The %s will be replaced with the SHA-1
    ## hash of the file.
    option match_sub_url = "https://www.virustotal.com/en/search/?query=%s";

    ## The malware hash registry runs each malware sample through several
    ## A/V engines.  Team Cymru returns a percentage to indicate how
    ## many A/V engines flagged the sample as malicious. This threshold
    ## allows you to require a minimum detection rate.
    option notice_threshold = 10;
}

重新定义了一个可枚举的常量,描述了将使用通知框架生成的通知类型。
定义一些常量用作阈值等

function

函数

function do_mhr_lookup(hash: string, fi: Notice::FileInfo)
    {
    local hash_domain = fmt("%s.malware.hash.cymru.com", hash);

    when ( local MHR_result = lookup_hostname_txt(hash_domain) )
        {
        # Data is returned as "<dateFirstDetected> <detectionRate>"
        local MHR_answer = split_string1(MHR_result, / /);

        if ( |MHR_answer| == 2 )
            {
            local mhr_detect_rate = to_count(MHR_answer[1]);

            if ( mhr_detect_rate >= notice_threshold )
                {
                local mhr_first_detected = double_to_time(to_double(MHR_answer[0]));
                local readable_first_detected = strftime("%Y-%m-%d %H:%M:%S", mhr_first_detected);
                local message = fmt("Malware Hash Registry Detection rate: %d%%  Last seen: %s", mhr_detect_rate, readable_first_detected);
                local virustotal_url = fmt(match_sub_url, hash);
                # We don't have the full fa_file record here in order to
                # avoid the "when" statement cloning it (expensive!).
                local n: Notice::Info = Notice::Info($note=Match, $msg=message, $sub=virustotal_url);
                Notice::populate_file_info2(fi, n);
                NOTICE(n);
                }
            }
        }
    }

event

针对特定事件执行的内容

event file_hash(f: fa_file, kind: string, hash: string)
    {
    if ( kind == "sha1" && f?$info && f$info?$mime_type &&
         match_file_types in f$info$mime_type )
        do_mhr_lookup(hash, Notice::create_file_info(f));

file_hash事件处理程序,传递file,哈希算法的种类,哈希值
zeek执行异步操作不影响性能时使用when语句块

事件队列和事件处理器:

zeek的脚本语言是事件驱动的,zeek的核心功能是把事件放入有序的事件队列中,允许事件处理程序在先到先服务的基础上处理事件。
当zeek检测到发起的dns请求时,触发dns_request事件,并传递数据

数据类型和数据结构

范围(scope)

声明变量的两种形式:

  1. scope name: type
  2. scope name = expression
    expression的计算结果和type一样,例如:
local a:int
local a=10

全局变量

当脚本使用module关键字提供了命名空间时,必须更加注意全局声明以确保预期的效果。
在带有命名空间的脚本中声明全局变量时,两种可能的结果:

  1. 仅在命名空间的上下文可用
  2. 如果在export块中声明了全局变量,可以通过<module name>::<variable name>来对其他脚本生效

常量

const关键字,使用&redef的话,只能在解析时设置或者更改常量,以后(运行时)不可更改。redef常量不能在事件处理程序中更改。
举例:
base/protocols/http/main.zeek文件中:

module HTTP;
export {
    ## This setting changes if passwords used in Basic-Auth are captured or
    ## not.
    const default_capture_password = F &redef;
}

如果想打开这个default_capture_password设置,需要在启动zeek之前在site/local.zeek添加如下行:

@load base/protocols/http
redef HTTP::default_capture_password = T;

局部变量

函数function内定义的local的局部变量,在函数结束后会被销毁。同理事件event中的变量在事件结束后会被销毁。

数据结构

原子类型

Data TypeDescriptionzh-cn
int64 bit signed integer64位有符号整数
count64 bit unsigned integer64位无符号整数
doubledouble precision floating precision双精度浮点
boolboolean (T/F)布尔类型
addrIP address, IPv4 and IPv6IP地址
porttransport layer port传输层端口
subnetCIDR subnet maskCIDR格式子网掩码
timeabsolute epoch time绝对时间
intervala time interval时间间隔
patternregular expression正则表达式

集合

储存相同数据类型的唯一元素。
可用的方法:adddeletefor ( i in ssl_ports )
for循环无法保证集合遍历的顺序

类似python字典,键-值映射,值不唯一,键唯一

local ssl_services: table[string] of port;
ssl_services = table(["SSH"] = 22/tcp, ["HTTPS"] = 443/tcp);

向量

类似python列表,有序

local v1: vector of count;
local v2 = vector(1, 2, 3, 4);

原子类型

  • addr:主机名定义的话zeek会发送dns查询,得到一个set[addr]
  • port:无符号整数/协议名(tcp,udp,icmp,unknown),协议大小顺序unknown < tcp < udp < icmp,例如65535/tcp<0/udp
  • subnet:cidr表示法
  • time:current_time系统时间, network_time来自实时流或者pcap最后处理数据包的时间戳
  • interval:usec, msec, sec, min, hr, or day
  • pattern:正则匹配

复合类型

记录数据类型:结合type关键词和record可以生成复合类型

type Service: record {
    name: string;
    ports: set[port];
    rfc: count;
};

简单的使用更具描述性的名称定义数据结构:type string_array: table[count] of string;

自定义日志

https://docs.zeek.org/en/current/examples/scripting/index.html#custom-logging

抛出通知

https://docs.zeek.org/en/current/examples/scripting/index.html#raising-notices

 类似资料: