9 21

跨平台的安全检测工具包

概述

xsec-checker是一款服务器安全检测的辅助工具,由GO语言开发,天生支持跨平台,同一份代码可以交叉编译出linux与windows平台下的可执行文件,且无任何库的依赖。

关于跨平台说点题外话,笔者工作前7,8年一直在游戏行业,从安全、运维及开发都有涉猎,记得移动互联网兴起时,许多手机游戏都是先只支持iphone平台,后来才慢慢支持Android平台的,原因是同一款游戏的客户端,需要2个团队,一个team用objective-c开发iphone版的,另一个team用java再重写一版android平台的,到了后期的维护成本及复杂度可想而知。

当时国内最流行的手游开发框架是cocos2d-iphone,是objective-c实现的,后来王哲推出了c++版本的cocos2d-x,只写一套c++版本的代码就可以交叉编译出多种平台的客户端,极大地提高了手机游戏开发的效率。

但业内马上又出现了新的难题,因C++语言难以驾驭,靠谱的C++非常不好招而且人员成本很高,后来cocos2d-x又推出了lua与js的绑定版本,这样的话,在一个研发Team中,只需极少的C++大神就可以搭建好底层框架,具体的业务与逻辑代码,能快速上手lua与js的新手就可以做了,甚至连策划都可以上手,直接写游戏逻辑代码验证自己的设计了,减少沟通与在验证玩法时反反复复让研发修改代码的成本。

目前安全界流行使用python,笔者建议在有高性能要求、跨平台部署、无外部依赖、部署方便、源码加密等要求的场景下使用go语言,go同python一样,也是种全栈的语言。

目前实现的功能如下所示:

项目地址:https://github.com/netxfly/sec_check

使用说明:

  • 使用帮助
$ ./main 
NAME:
   xsec checker - linux and windows security detect tool

USAGE:
   main [global options] command [command options] [arguments...]

VERSION:
   20180914

AUTHOR:
   netxfly <x@xsec.io>

COMMANDS:
     info      host info
     init      init rule from yara files
     ps        list process
     netstat   list connection
     pstree    list process tree
     loginlog  list login record
     autoruns  list autoruns
     crontab   list crontab
     scan      Malicious program scanning
     dump      dump all result to json
     web       Startup a web server to view check result
     help, h   Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --debug, -d             debug mode
   --path value, -p value  yara rules path (default: "rules")
   --type value, -t value  scan type, such as: process, file (default: "process")
   --file value, -f value  File path to scan
   --verbose, --vv         verbose mode
   --server value          http server address
   --port value            http port (default: 8000)
   --help, -h              show help
   --version, -v           print the version
  • 查看主机信息
 ./main info
{"HostInfo":{"hostname":"xxxxxx","uptime":102930,"bootTime":1537410991,"procs":196,"os":"linux","platform":"centos","platformFamily":"rhel","platformVersion":"6.3","kernelVersion":"2.6.32-220.23.2.mi6.el6.x86_64","virtualizationSystem":"","virtualizationRole":"","hostid":"b5d52e45-48ee-4730-98c3-5d8b2f2de48b"},"InterfaceInfo":[{"mtu":16436,"name":"lo","hardwareaddr":"","flags":["up","loopback"],"addrs":[{"addr":"127.0.0.1/8"}]},{"mtu":1500,"name":"eth0","hardwareaddr":"fa:16:3e:75:12:f5","flags":["up","broadcast","multicast"],"addrs":[{"addr":"10.10.10.10/24"}]}]} <nil>
  • 查看进程

  • 查看网络连接

  • 查看进程树

  • 查看登录日志

  • 查看自启动项

  • 查看crontab

  • 初始化yara规则

该命令会把当前rules目录下的所有yara规则初始化一个rules.db文件,以后需要扫描的时候,不需要再把rules目录下的一堆规则复制到机器上了,只需要把rules.db放到检测程序的当前目录下即可。

需要注意的是,不能加太多的规则,否则扫描速度太慢,建议只加常见后门的规则,保持在500条之内,(yara扫描时会占满一个cpu核心,测试通过协程并发扫描的时候,测试服务器直接无响应了2次,暂时先改回了单线程模式)。

$ ./main init
[0001]  INFO xsec checker: Init rules Done, total: 1313 rules, err: <nil>
  • 扫描

支持对系统中运行的所有进程以及指定的文件进行扫描。 * scan默认为对进程进行扫描 * -vv表示表不详细模式,可以看到扫描的过程 * --type表示显式特定扫描模式,可选参数为process与file,分别表示对进程与文件进行扫描 * --file表示对指这定的目录或文件进行扫描

  • 结果保存与查看

  • dump指定默认会将操作系统信息,进程、端口列表,autoruns、crontab、进程扫描结果等信息保存到当前目前的result.json文件中。

  • web指定表示启动一个Web server查看显示结果,暂时偷懒没有处理直接出了json(先在节前快速推出版本,以后再慢慢迭代)

编译说明

利用yara规则扫描的库为https://github.com/hillu/go-yara,是yara库的go语言绑定,在使用go-yara之前需要先编译yara,笔者使用的编译平台分别为centos 6.xubuntu 17.10, 可以在linux平台下编译出linux与windows平台的可执行版本。

  • 安装yara

笔者使用的yara版本为3.7.1

mkdir ~/softs/
cd ~/softs/
wget https://github.com/VirusTotal/yara/archive/v3.7.1.tar.gz
tar -zxvf v3.7.1.tar.gz
cd yara-3.7.1
export YARA_SRC=~/softs/yara-3.7.1
./bootstrap.sh
./configure --disable-shared --enable-static --without-crypto
make && make install
cp ./libyara/yara.pc /usr/local/lib/pkgconfig/yara.pc
  • 安装go-yara库

这一步不是必需的,但是可以测试能否编译通过,这里通过后,自己写的调go-yara库的程序也能编译通过。

go get github.com/hillu/go-yara
cd $GOPATH/src/github.com/hillu/go-yara
export YARA_SRC=/home/willem/src/yara-3.7.1
export CGO_CFLAGS="-I${YARA_SRC}/libyara/include"
export CGO_LDFLAGS="-L${YARA_SRC}/libyara/.libs -lyara -lm"
go build -tags yara_static -tags no_pkg_config --tags yara3.7 

编译linux版本的可执行程序

cd $GOPATH/src
git clone https://github.com/netxfly/sec_check
cd sec_check
  • Linux下编译出依赖libyara.so.3库的可执行文件,大小为12M,需要将库加到/etc/ld.so.conf中并用ldconfig -v刷新
go build --tags yara_static --tags no_pkg_config --tags yara3.7 main.go
  • Linux下编译出不依赖任何库的可执行文件,大小为13M
go build --ldflags '-extldflags "-static -lm"' --tags yara_static --tags no_pkg_config --tags yara3.7 main.go

注:

  1. 在编译的过程中,提示缺少go包时,直接按错误提示显示的包名,利用go get指令安装即可
  2. 如果提示cannot find -lpthreads,直接用yum install glibc-static 安装
  3. 上面第1条指令编译出来的可执行程序不带libyara.so.3,需要把libyara.so.3上传到目标服务器中,然后手工加入
  4. 上面第2条编译指令可以编译出不依赖任何包的可执行程序,但在centos 6.x与 centos 7.x要分别编译,否则6.x下编译出来的没法在7.x下运行,反之也一样

编译windows可执行程序

笔者的编译平台的ubuntu 17.10

  • 安装yara

    apt-get update
    apt-get install gcc-mingw-w64
    cd ${YARA_SRC} \
    && ./bootstrap.sh \
    && ./configure --host=x86_64-w64-mingw32 --disable-magic --disable-cuckoo --without-crypto --prefix=${YARA_SRC}/x86_64-w64-mingw32 \
    && make -C ${YARA_SRC} \
    && make -C ${YARA_SRC} install 
    
  • 编译windows下的可执行文件

    GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc \
    PKG_CONFIG_PATH=${YARA_SRC}/x86_64-w64-mingw32/lib/pkgconfig \
    go build -ldflags '-extldflags "-static"' --tags yara_static --tags no_pkg_config --tags yara3.7 main.go
    
8 31

应急响应浅谈

应急响应浅谈

应急响应及应急响应中心

应急响应是安全从业者最常见的工作之一(系统被黑后紧急救火,PDR模型-防护、检测、响应中的三大模块之一)。很多人可能认为应急响应就是发现服务器被黑之后,登录上去查后门的那段过程。 其实应急响应的完整定义为:组织为了应对突发/重大信息安全事件的发生所做的准备,以及在事件发生后所采取的措施

通俗地讲,应急响应不应该只包括救火,还应包括救火前的一系列准备。如果在工作中忽略了准备部分,可能会出现以下几种情况:

  1. 不具备基本的入侵检测能力,平时检测不到入侵事件,更谈不上应急响应了。有可能被入侵成功很久了却浑然不知,攻击者可能早就在达成目标后悄然离去了;
  2. 能检测到入侵事件,但没有专门的应急响应小组,资产管理系统也不完善,安全工程师花了很长时间才找到对应的负责人,因进入响应时间太晚,攻击者可能在达到目标并擦除痕迹后全身而退了,或者进一步把其他关联的系统一并拿下了;
  3. 平时无应急响应技能及入侵检测工具包的积累,接到事件的工程师登录到服务器上绞尽脑汁敲了几行命令后,最后得出『经排查安全的结论』给部门Leader与业务部门了,但真实情况是真被入侵并植入后门了。

现在各大厂商都成立了相应的安全应急响应中心(SRC),用来接收外部白帽子的提交的漏洞与威胁情报,虽然叫应急响应中心,但是这里提交过来的漏洞与情报不需要每次都启动应急响应,需要根据漏洞的类型、危害级别判断。

安全应急响应中心是对自己安全团队所做的安全保障工作的补充,如果SRC发现的漏洞与入侵事件比例很高,安全团队就该好好反思下安全工作为啥只治标不治本、频繁地被动救火了。

指导原则及方法论

应急响应是既紧急又重要的工作,对工程师的技术与意识都有一定的要求,比如很多安全工程师接到业务系统被黑的情报后,可能会联系业务负责人要到服务器账户,然后登录到服务器中检查被渗透的痕迹与后门。这段时间非常宝贵,反映太慢可能会使一些本来可以快速平息的安全小事件发酵成造成重大的损失安全事故。

  • 对于应急响应,首先要了解应急响应的指导原则与方法论,只关注技术的话,可能会本末倒置。

    因信息安全事件的种类和严重程度各有不同,应急响应的处理方式也各不相同,比如DDOS、业务系统被入侵、钓鱼邮件的应急响应方式与过程肯定是不同的,被业内广为接受的应急响应模型与方法论有PDCERF模型与ITIL中的事件管理问题管理模块。

  • 其次要求应急人员有较高的入侵检测能力,否则在排查被入侵的系统时,上去查了半天啥也发现不了,最后给出的结论是安全的。

    笔者在第一份工作时,部门老大要求在进行代码审计与应急响应等依赖人员技术和经验的工作时,必须采用双人Check机制,最后汇总对比结果,防止遗漏。 入侵检测需要检测的项目很多,最好能整理出相应的自动化检测工具自动给出报告,这样不但可以提高工作效率,还可以弱化对应急响应人员技术水平的依赖。

PDCERF模型

准备阶段

有条件的话,自上而下达成应急响应共识,建立应急响应流程与应急响应小组,由应急小组全权负责对紧急安全事件的处理、资源协调工作,应急小组的成员除了技术负责人外,还要有公关负责人,方便在必要的时候,根据安全团队的建议对外进行公关。

对于没有条件建立应急响应流程的安全部门来说,最基本的要做好以下准备:

  • 至少要有入侵检测的能力(入侵检测系统或SRC接收的高危漏漏洞或情报等)及具备相应技能的应急响应人员,否则登录上去也查不出啥,甚至给出错误的结论,最好能准备一套有效的入侵检测工具;
  • 维护一份各业务系统的资产列表,应急联系人列表,否则出事了后,安全工程师自下而上找一圈也找不到相应的负责人配合处理,会错过最佳处理时机。

检测阶段

检测的目的是确认入侵事件是否发生,如真发生了入侵事件,评估造成的危害、范围以及发展的速度,事件会不会进一步升级。然后根据评估结果通知相关的人员进入救火的流程。

遏制阶段

遏制的目的是控制事件影响的范围、损失与破坏的进一步扩大,避免事件的进一步升级。

比如是感染蠕虫事件,需要先在网络层面封掉其传播的端口,否则安全人员在本台机器中杀毒的时候,蠕虫又把其他一批服务器感染了; 对于被黑客攻陷的服务,可以选择第一时间利用ACL或防火墙将攻击者隔离出去、关闭服务、拔掉网线或关闭服务器等方式。如果应急人员第一时间只想到了查后门和入侵痕迹,在这个时间段内,攻击者可能早从这台机器转移到其他服务器中了。

具体的遏制方式需要应急响应人员根据对业务的影响以及遏制效果综合考虑,判断的标准是对业务的影响最小、遏制效果最佳。

根除阶段

根除是找到系统的漏洞并修复,清除掉攻击者的后门、webshell等,对于被装了rootkits的机器需要重装操作系统,防止查杀不彻底被黑客再度进入。

恢复阶段

恢复阶段是根除攻击源、修复系统后将其恢复上线,也叫恢复业务的连续性。然后去掉遏制阶段添加的一些临时策略。

跟踪总结阶段

在业务系统恢复后,需要整理一份详细的事件总结报告,包括事件发生及各部门介入处理的时间线,事件可能造成的损失。 复盘安全事件产生的根本原因,根据经验教训进一步优化安全策略。优化安全策略时,要从技术、人员、管理、工程等多个维度考虑,因为安全本身不是一个纯技术问题,光靠技术手段只能解决部分安全问题。

事件管理与问题管理

事件管理与问题管理是ITIL中的2大核心模块,对于应急响应同样也有重要的参考意义。

  • 事件管理的核心思想是快速解决问题,尽快恢复业务系统的可用性,毕竟关键业务系统中断的每一分钟都会给公司带来损失;
  • 问题管理的核心思想是从通过对一个或一类事件的处理,总结成其性,解出彻底的解决办法,从根本上杜绝该类事件的发生;
  • 事件管理与问题管理总是成对出现的,事件管理的输出可以作为问题管理的输入。
8 28

用Docker制作一个高交互ssh蜜罐

概述

实现一个高交互的SSH蜜罐有方式有多种:

  • 可以使用现成的开源系统,如kippocowrie等,
  • 可以利用一些SSH库做2次开发,如https://github.com/gliderlabs/ssh
  • 也可以用Docker定制

市面上已经有这么多开源的SSH蜜罐了,我为什么还要再造个轮子呢,理由如下:

  • 部署这些系统要安装一堆的依赖,运维部署成本较高
  • 想要的功能没法添加,不想要的功能也没法删减
  • 如果要支持多种高交互的服务,必须用一堆开源的系统拼凑出一堆服务来,每种系统的后端DB不同,数据结构也各不相同,无法统一处理
  • 自研的系统部署简单,服务可自由扩展,数据格式可自由定制和统一,方便运维与运营

技术架构

笔者在之前的文章《自制攻击欺骗防御系统》中介绍过完整的架构,整个系统由以下几个模块组成:

  • Agent端,部署于服务器中的Agent,用于实时获取用户的访问日志并传递到检测端Server中,如果是恶意攻击,则会将流量重定向到沙盒中。目前支持的服务有:

    • WEB
    • FTP
    • SSH
    • Rsync
    • Mysql
    • Redis
    • Mongodb
  • Server端,攻击检测服务器,实时检测Agent传递过来的日志并判断是否为攻击者,并为Agent动态、实时地维护了一份攻击者的来源IP策略

  • Mamager端,策略管理服务器,有为Agent和server提供策略、攻击log统计、查看的功能

  • 高交互蜜罐系统及守护进程,高交互蜜罐系统由docker封装的一些服务组成,守护进程负责把仿真系统中产生的LOG的数据格式化后再传给Server端进行攻击检测与入库

本文只讲SSH高交互蜜罐的实现。

SSH高交互蜜罐的Docker实现

docker中默认的openssh服务没有记录bash命令及ssh密码的功能,需要修改bash及openssh的源码并重新编译到Docker中,以下为Dockerfile的内容:

FROM debian:jessie

RUN export DEBIAN_FRONTEND='noninteractive' && \
    apt-get update -qq && \
    apt-get install -qqy --no-install-recommends openssh-server rsyslog wget patch make gcc curl libc6-dev net-tools vim && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* /tmp/* && \
    mkdir -p /softs/bash-4.3.30-active-syslog/ && mkdir -p /home/test

COPY softs/ /softs/

RUN chmod +x /softs/bash-4.3.30-active-syslog/install-bash-syslog.sh
RUN chmod +x /softs/install_ssh.sh

WORKDIR /softs/bash-4.3.30-active-syslog/
RUN ["/bin/bash", "./install-bash-syslog.sh"]

WORKDIR /softs/
RUN ["/bin/bash", "./install_ssh.sh"]

EXPOSE 22/tcp

COPY entrypoint.sh /etc/systemd/system/

COPY Shanghai /etc/localtime

RUN chmod +x /etc/systemd/system/entrypoint.sh

ENTRYPOINT ["/etc/systemd/system/entrypoint.sh"]
  • install-bash-syslog.sh为记录详细执行命令记录的bash安装脚本;
  • /install_ssh.sh为记录openssh密码的安装脚本。

完成后的Docker镜像封装脚本的地址为https://github.com/netxfly/docker_ssh_honeypot/blob/master/install.sh

执行sh -x ./install.sh后经过一段时间的等待后,会直接封装一个Openssh镜像并启动。

测试截图

openssh的密码破解记录如下:

bash的命令执行记录如下:

如果允许攻击者登录到蜜罐中,还需要修改蜜罐的IP地址和主机名,防止攻击者一登录成功就识别出来;其次要做好ACL,防止攻击者通过蜜罐作为跳板攻击内网中其他系统。

仿真系统的守护进程实现

仿真系统的守护进程的作用是实时监控Docker服务产生的数据,并格式化后发送到server端中进行检测,通过插件的形式,可以支持多种服务的日志格式化,然后将格式化的日志通过http协议发送到server端。

func main() {
    logs := make(map[string]string)
    logs["vsftpd-server"] = settings.VsftpLog
    logs["openssh-server"] = settings.SshLog
    logs["history"] = settings.HistLog
    logs["rsync"] = settings.RsyncLog
    logs["mysql-server"] = settings.MysqlLog
    logs["redis-server"] = settings.RedisLog
    logs["mongodb-server"] = settings.MongodbLog

    // logger.Log.Infoln("Log config info:", settings.APIURL, settings.KEY, settings.MODE)

    for tag, fileName := range logs {
        logger.Log.Printf("Tag: %v, path: %v, Truncate: %v", tag, fileName, os.Truncate(fileName, 0))

        if settings.MODE == "syslog" {
            // go util.MonitorLog(tag, fileName)
        } else {
            go util.CheckLog(tag, fileName)
        }
    }

    for {
        time.Sleep(3 * time.Second)
    }
}

SSH密码破解检测插件的实现如下:

  1. 通过正则匹配中破解密码的记录并格式化
  2. 确定为破解行为的记录,通过http接口传到server中

package plugins

import (
    "regexp"
    "time"
    "os"
    "net/http"
    "net/url"
    "encoding/json"

    "cloud-honeypot/sandbox_log/models"
    "cloud-honeypot/sandbox_log/settings"
    "cloud-honeypot/sandbox_log/misc"
    "cloud-honeypot/sandbox_log/logger"
)

var (
    RegexpSSH *regexp.Regexp
    err       error
)

func init() {
    RegexpSSH, err = regexp.Compile(`Honeypot: Username: (.+?) Password: (.+?), from: (.+?), result: (.+?)`)
}

func Check(tag, content string) (checkResult models.CheckResult, result bool) {
    switch tag {
    case "openssh-server":
        checkResult, result = CheckSSH(content, tag)
    }
    if result {
        logger.Log.Infof("from ip: %v, user: %v, password: %v, result: %v", checkResult.Ip,
            checkResult.Username, checkResult.Password, checkResult.Status)
    }
    return checkResult, result
}

func SaveResult(checkResult models.CheckResult, result bool) {
    if result {
        content, _ := json.Marshal(checkResult)
        t := time.Now().Format("2006-01-02 15:04:05")
        apiData := models.APIDATA{}
        apiData.Tag = checkResult.Tag
        apiData.Content = string(content)
        apiData.Hostname, _ = os.Hostname()
        data, err := json.Marshal(apiData)
        if err == nil {
            _, err = http.PostForm(settings.APIURL, url.Values{"timestamp": {t},
                "secureKey": {misc.MakeSign(t, settings.KEY)}, "data": {string(data)}})
        }
    }
}

server端接到数据后做相应的处理后入库,并在管理端中展示,例如:

5 17

「技术随笔」iptables报too many ports specified的解决

背景

笔者写的蜜罐的agent底层依赖iptables,在设置高交互蜜罐的端口转发规则时会用到iptables的multiport --dports指令,但是超过--dports超过15个的话,会报too many ports specified错误:

iptables -A INPUT -p tcp -m multiport --dports 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
iptables -A INPUT -p tcp -m multiport --dports 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
iptables v1.4.21: too many ports specified
Try `iptables -h' or 'iptables --help' for more information.

关于蜜罐与攻击欺骗防御系统的设计与实现,可以参考笔者之前写过的文章。

  1. 设计灵敏的蜜罐传感器
  2. 自制攻击欺骗防御系统
  3. 自制蜜罐之前端部分

解决方案

投石问路

蜜罐的规则在运营过程是肯定会超过15个,不可能为了规避iptables的这个特性就缩小规则列表。 IPTABLES报这个错误的根本原因是iptables的源码中include/linux/netfilter/xt_multiport.h的宏XT_MULTI_PORTS指定了参数个数为15个,如下所示:

#ifndef _XT_MULTIPORT_H
#define _XT_MULTIPORT_H

#include <linux/types.h>c

enum xt_multiport_flags {
    XT_MULTIPORT_SOURCE,
    XT_MULTIPORT_DESTINATION,
    XT_MULTIPORT_EITHER
};

#define XT_MULTI_PORTS    15

很傻很天真的我最初认为把这个将XT_MULTI_PORTS的值改大重新编译iptables就可以了,事实证明我还是太年青了。等编译完后一执行又报错了,提示让看dmesg,发现如下错误:

[ 1379.325905] x_tables: ip_tables: multiport.1 match: invalid size 48 (kernel) != (user) 456
[ 1650.126296] x_tables: ip_tables: multiport.1 match: invalid size 48 (kernel) != (user) 304

以上2条LOG分别是将XT_MULTI_PORTS改为150和100产生的。为什么捏?

通过观察include/linux/netfilter/xt_multiport.h的代码片断,确定为正好是以下struct中XT_MULTI_PORTS分别为150和100的size。

struct xt_multiport_v1 {
    __u8 flags;                /* Type of comparison */
    __u8 count;                /* Number of ports */
    __u16 ports[XT_MULTI_PORTS];    /* Ports */
    __u8 pflags[XT_MULTI_PORTS];    /* Port flags */
    __u8 invert;            /* Invert flag */
};

这个时候我才恍然大悟,本来iptables就是netfilter的用户接口,最终的操作结果是传到内核级模块netfilter中的,还需要修内核中netfilter模块相对应的代码部分,经确定在以下文件中include/uapi/linux/netfilter/xt_multiport.h,修改完还要重新编译内核。这个方案比较麻烦,先PASS了,还是在agent中实现吧。

柳暗花明

如果一条策略中的端口超过了15个,那我们将策略分成多条即可。先写一个端口数量分割的工具函数:

func SplitWhitePorts(ports []string) (map[int][]string) {
    result := make(map[int][]string)
    total := len(ports)
    batch := 0
    if total%15 == 0 {
        batch = total / 15
        for i := 0; i < batch; i++ {
            result[i] = ports[i*15 : (i+1)*15]
        }
    } else {
        batch = total / 15
        for i := 0; i < batch; i++ {
            result[i] = ports[i*15 : (i+1)*15]
        }
        result[batch] = ports[batch*15 : total]
    }

    return result
}

测试结果满足预期:

[ `go run csrf.go` | done: 561.973248ms ]
    map[0:[1 2 3 4 5 6]]
    map[0:[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]]
    map[0:[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15] 1:[16 17 18 19 20]]

然后在刷新策略部分应用之:

if strings.ToLower(mode) == "honeypot" {
        whiteIpPolicy := vars.HoneypotPolicy.WhiteIp
        // set white policy
        for _, whiteIp := range whiteIpPolicy {
            logger.Log.Println("/sbin/iptables", "-t", "filter", "-A", "WHITELIST", "-i", setting.Interface, "-s", whiteIp, "-j", "DROP")
            exec.Command("/sbin/iptables", "-t", "filter", "-A", "WHITELIST", "-i", setting.Interface, "-s",
                whiteIp, "-j", "DROP").Output()
        }

        for _, ports := range util.SplitWhitePorts(vars.HoneypotPolicy.WhitePort) {
            logger.Log.Println("/sbin/iptables", "-t", "nat", "-A", "HONEYPOT", "-i", setting.Interface,
                "-p", "tcp", "-m", "multiport", "!", "--dports", strings.Join(ports, ","),
                "-j", "DNAT", "--to-destination", vars.HoneypotPolicy.Backend)

            ret, err := exec.Command("/sbin/iptables", "-t", "nat", "-A", "HONEYPOT", "-i", setting.Interface,
                "-p", "tcp", "-m", "multiport", "!", "--dports", strings.Join(ports, ","), "-j",
                "DNAT", "--to-destination", vars.HoneypotPolicy.Backend).Output()
            logger.Log.Println(ret, err)
        }
    } 
Next