Snort 安装及使用
安装
在 Arch 上,大概是由于没有及时更新,目前官方库中的 Snort 已经过时,无法拉取源码,会报404
因此需要去官网拉取最新的源码手动编译
wget https://www.snort.org/downloads/snort/daq-2.0.7.tar.gz tar xvzf daq-2.0.7.tar.gz cd daq-2.0.7 ./configure && make && sudo make install cd .. wget https://www.snort.org/downloads/snort/snort-2.9.16.tar.gz tar xvzf snort-2.9.16.tar.gz cd snort-2.9.16 ./configure --enable-sourcefire && make && sudo make install cd ..
在这里,daq本身还需要依赖flex
、bison
、rpc-compat
,好在这两个可以直接使用包管理安装
DAQ
DAQ(Data Acquisition) 是数据采集模块,使用--daq-list
可以看到已安装到 Snort 的数据采集模块
$ snort --daq-list Available DAQ modules: pcap(v3): readback live multi unpriv nfq(v7): live inline multi ipfw(v3): live inline multi unpriv dump(v3): readback live inline multi unpriv afpacket(v5): live inline multi unpriv
默认情况下,Snort 使用的是 pcap。
联动防火墙
Snort 本身只是一个入侵检测软件,但可以使用 inline 模式来实现丢弃警告的包。但 inline 模式对设备网卡有所要求,另一个可行的思路是使用程序监控 Snort 日志,并自动插入到防火墙(不局限于 iptables,也可以使用 PowerShell 插入到 Windows 防火墙)
比较常见的思路是使用 Guardian 来实现 Snort 和 iptables 的联动1,但不幸的是 Guardian 已经年久失修,需要修改代码或安装libperl4-corelibs-perl
才能运行。
当然,更省事的办法是自己来实现类似的程序。
大概思路是监听日志文件的改动,发现改动后使用正则表达式提取出对端 IP,使用 Shell 命令将其插入至 iptables2 3 中。
下面是一个可行的 Go 程序(需要sudo
运行),如果加以修改,也可用于插入至 Windows 防火墙
package main import ( "bytes" "fmt" "log" "os" "os/exec" "regexp" "strings" "github.com/fsnotify/fsnotify" ) const filename = "/home/ohyee/projects/network_security/snort/log/alert" var f *os.File // var reader *bufio.Reader var regex *regexp.Regexp var iptables string var buffer = make([]byte, 1024) var offset int64 = 0 type Alert struct { srcip string srcport string dstip string dstport string protocol string } func alert() { for { buf := bytes.NewBuffer([]byte{}) for { length, err := f.ReadAt(buffer, offset) fmt.Println(offset, err) if length == 0 { break } offset += int64(length) buf.Write(buffer) } if buf.Len() == 0 { break } line := buf.String() fmt.Println(line) res := regex.FindAllStringSubmatch(line, -1) for _, item := range res { alerts := Alert{ srcip: item[1], srcport: item[2], dstip: item[3], dstport: item[4], protocol: item[5], } fmt.Printf("%+v", alerts) ban(alerts) } } } func ban(a Alert) { args := []string{"-I", "INPUT", "-s", a.srcip, "-d", a.dstip, "-p", strings.ToLower(a.protocol), "-j", "REJECT"} if a.dstport != "" { args = append(args, "--dport", a.dstport[1:]) } cmd := exec.Command(iptables, args...) if b, err := cmd.CombinedOutput(); err != nil { fmt.Printf("Error %s %+v\n", b, err) } else { fmt.Printf("Ban %s -> %s (%s)\n", a.srcip, a.dstip, a.protocol) } } func main() { var err error if f, err = os.Open(filename); err != nil { return } defer f.Close() if regex, err = regexp.Compile("([\\d.]+)([:\\d]*) -> ([\\d.]+)([:\\d]*)[\\n\\s]*([a-zA-Z]+)"); err != nil { panic(err) } if iptables, err = exec.LookPath("iptables"); err != nil { panic(err) } watcher, err := fsnotify.NewWatcher() if err != nil { log.Fatal(err) } defer watcher.Close() alert() done := make(chan bool) go func() { for { select { case event := <-watcher.Events: if event.Op&fsnotify.Write == fsnotify.Write { fmt.Println("modified file:", event.Name) alert() } case err := <-watcher.Errors: fmt.Println("error:", err) } } }() err = watcher.Add(filename) if err != nil { log.Fatal(err) } <-done }