本ブログ記事では、ntop製品の1つ高速ネットワークトラフィック分析ツールntopngの最新バージョン4で実装されたプラグインの追加機能をgithub上のチュートリアルを参考にし、開発方法をご紹介します。
文:ジュピターテクノロジー よしひろ
前提知識
ntopngユーザーは、Luaスクリプトを使ってntopngの機能拡張をすることができます。
ntopngにデフォルトで含まれるプラグインは、図1の通り開発者メニューからプラグインリンクを押すことで確認することができます。
右列の対応ライセンスがプラグインを利用するために必要なライセンスを表し、Community、Pro、Enterpriseの3種類があります。Enterpriseライセンスならすべてのプラグインを利用できます。
今回作成するプラグインは、Communityに分類されます。
図1 プラグイン一覧
プラグインディレクトリとファイル構造
ntopngのプラグインを開発する上で重要となるのがフォルダとファイル構造です。
今回追加するのはチュートリアルの通り、exeファイルをHTTPでダウンロードした場合にアラートを発報するプラグインEXEs Downloadです。
図2に従いフォルダとファイルを作成してください。
/usr/share/ntopng/scripts/plugins プラグインディレクトリ
../plugins ※上記PATH
|_ /exes_download -- 今回追加するプラグインフォルダ
|_ /manifest.lua -- マニュフェストファイル
|_ /exes_download/user_scripts/flow/exes_download.lua -- プラグイン本体
|_ /exes_download/status_definitions/status_exe_download.lua -- ステータス定義
|_ /exes_download/alert_definitions/alert_exe_download.lua -- アラート定義
../plugins ※上記PATH
|_ /exes_download -- 今回追加するプラグインフォルダ
|_ /manifest.lua -- マニュフェストファイル
|_ /exes_download/user_scripts/flow/exes_download.lua -- プラグイン本体
|_ /exes_download/status_definitions/status_exe_download.lua -- ステータス定義
|_ /exes_download/alert_definitions/alert_exe_download.lua -- アラート定義
図2 プラグインツリー構造
manifest.lua
マニュフェストファイルです。
プラグイン名、説明を定義します。
vi等のテキストエディタで図3の通りファイルを編集してください。
--
-- (C) 2019-20 - ntop.org
--
return {
title = "EXEs Download",
description = "Detects .exe downloaded via HTTP",
author = "ntop",
dependencies = {},
}
-- (C) 2019-20 - ntop.org
--
return {
title = "EXEs Download",
description = "Detects .exe downloaded via HTTP",
author = "ntop",
dependencies = {},
}
図3 マニュフェスト
exes_download.lua
プラグインの本体です。
hooksは、L7アプリケーションを検知した際に実行されるコールバック関数protocolDetected()に対応しています。
--
-- (C) 2019-20 - ntop.org
--
local user_scripts = require("user_scripts")
local flow_consts = require("flow_consts")
local script = {
-- Script category
category = user_scripts.script_categories.security,
-- This module is disabled by default
default_enabled = true,
-- See below
hooks = {},
-- Allow user script configuration from the GUI
gui = {
-- Localization strings, from "locales" directory of the plugin
i18n_title = "EXEs Download",
i18n_description = "Detects .exe downloaded via HTTP",
}
}
-- #################################################################
-- Define an hook which is executed every time a protocol of a flow is detected
-- if the flow is HTTP and it contains a last_url...
function script.hooks.protocolDetected(now)
local http_info = flow.getHTTPInfo()
-- if the flow is HTTP and it contains a last_url...
if http_info and http_info["protos.http.last_url"] then
local line_url = string.format("last_url: %s", http_info["protos.http.last_url"])
local line_method = string.format("last_method: %s", http_info["protos.http.last_method"])
io.write(line_method.." "..line_url.."\n")
-- if an .exe is found in the URL...
if http_info["protos.http.last_url"]:match("%.exe") then
flow.triggerStatus(
flow_consts.status_types.status_exe_download.create(
flow_consts.status_types.status_exe_download.alert_severity,
http_info
),
100 --[[ flow_score --]],
100 --[[ cli_score ]],
10 --[[ srv_score]])
end
end
end
-- #################################################################
return script
-- (C) 2019-20 - ntop.org
--
local user_scripts = require("user_scripts")
local flow_consts = require("flow_consts")
local script = {
-- Script category
category = user_scripts.script_categories.security,
-- This module is disabled by default
default_enabled = true,
-- See below
hooks = {},
-- Allow user script configuration from the GUI
gui = {
-- Localization strings, from "locales" directory of the plugin
i18n_title = "EXEs Download",
i18n_description = "Detects .exe downloaded via HTTP",
}
}
-- #################################################################
-- Define an hook which is executed every time a protocol of a flow is detected
-- if the flow is HTTP and it contains a last_url...
function script.hooks.protocolDetected(now)
local http_info = flow.getHTTPInfo()
-- if the flow is HTTP and it contains a last_url...
if http_info and http_info["protos.http.last_url"] then
local line_url = string.format("last_url: %s", http_info["protos.http.last_url"])
local line_method = string.format("last_method: %s", http_info["protos.http.last_method"])
io.write(line_method.." "..line_url.."\n")
-- if an .exe is found in the URL...
if http_info["protos.http.last_url"]:match("%.exe") then
flow.triggerStatus(
flow_consts.status_types.status_exe_download.create(
flow_consts.status_types.status_exe_download.alert_severity,
http_info
),
100 --[[ flow_score --]],
100 --[[ cli_score ]],
10 --[[ srv_score]])
end
end
end
-- #################################################################
return script
図4 EXEs Downloadプログラム本体
"if http_info and http_info["protos.http.last_url"] then"で、検出したアプリケーションがhttpであるか?、URL最後の存在確認を実施しています。
"if http_info["protos.http.last_url"]:match("%.exe") then"で、URL最後の文字列がexeに一致するかを判別し、trueの場合アラートをステータス定義とアラート定義に従い発報します。
最後の100,100,10は、ntopngがカウントするスコア値を設定します。
alert_exe_download.lua
アラート定義です。
アラート名やGUIに表示するアイコンを定義します。
アラートキーは一意に設定する必要があります。
createExeDownload()はHTTPの中身をjson形式でntopng GUIに渡します。
---
-- (C) 2019-20 - ntop.org
--
local alert_keys = require "alert_keys"
-- #######################################################
-- @brief Prepare an alert table used to generate the alert
-- @param alert_severity A severity as defined in `alert_consts.alert_severities`
-- @param tls_info A lua table with HTTP info gererated calling `flow.getHTTPInfo()`
-- @return A table with the alert built
local function createExeDownload(alert_severity, http_info)
local built = {
alert_severity = alert_severity,
alert_type_params = http_info -- This info will go into the alert JSON
}
return built
end
-- #######################################################
return {
alert_key = alert_keys.user.alert_user_01,
-- equivalent
-- alert_key = {0, alert_keys.user.alert_user_01},
-- custom pens
-- alert_key = {312 -- PEN -- , 513 --alert id --]]},
i18n_title = "EXE download",
icon = "fas fa-exclamation",
creator = createExeDownload,
}
-- (C) 2019-20 - ntop.org
--
local alert_keys = require "alert_keys"
-- #######################################################
-- @brief Prepare an alert table used to generate the alert
-- @param alert_severity A severity as defined in `alert_consts.alert_severities`
-- @param tls_info A lua table with HTTP info gererated calling `flow.getHTTPInfo()`
-- @return A table with the alert built
local function createExeDownload(alert_severity, http_info)
local built = {
alert_severity = alert_severity,
alert_type_params = http_info -- This info will go into the alert JSON
}
return built
end
-- #######################################################
return {
alert_key = alert_keys.user.alert_user_01,
-- equivalent
-- alert_key = {0, alert_keys.user.alert_user_01},
-- custom pens
-- alert_key = {312 -- PEN -- , 513 --alert id --]]},
i18n_title = "EXE download",
icon = "fas fa-exclamation",
creator = createExeDownload,
}
図5 アラート定義
status_exe_download.lua
スタータス定義です。
アラートのServerityをErrorに設定しています。また、status_keyに一意のキーを設定する必要があります。
---
--- (C) 2019-20 - ntop.org
--
local alert_consts = require("alert_consts")
local status_keys = require "flow_keys"
return {
status_key = status_keys.user.status_user_01,
alert_severity = alert_consts.alert_severities.error,
alert_type = alert_consts.alert_types.alert_exe_download,
i18n_title = "EXE download",
i18n_description = "Flow has downloaded an executable file",
}
--- (C) 2019-20 - ntop.org
--
local alert_consts = require("alert_consts")
local status_keys = require "flow_keys"
return {
status_key = status_keys.user.status_user_01,
alert_severity = alert_consts.alert_severities.error,
alert_type = alert_consts.alert_types.alert_exe_download,
i18n_title = "EXE download",
i18n_description = "Flow has downloaded an executable file",
}
図6 ステータス定義
実行テスト
全てのファイルを配置したら、先ずntopngを停止してください。
exe_download.luaの動作を確認するために手動でntopngを起動します。
以下の様にlast_method: GET last_url: xxxxと表示されれば、追加したプラグインEXEs Downloadは動作しています。
停止及び手動起動例:
$ sudo systemctl stop ntopng
$ sudo ntopng -i br0 -w 3000 --https-port 443
~snip~
last_method: GET last_url: speedtest.keff.org/speedtest/random1500x1500.jpg
last_method: POST last_url: speedtest.keff.org/speedtest/upload.php
last_method: POST last_url: speedtest.keff.org/speedtest/upload.php
last_method: GET last_url: ncc.avast.com/ncc.txt
last_method: GET last_url: ncc.avast.com/ncc.txt
last_method: GET last_url: ncc.avast.com/ncc.txt
$ sudo systemctl stop ntopng
$ sudo ntopng -i br0 -w 3000 --https-port 443
~snip~
last_method: GET last_url: speedtest.keff.org/speedtest/random1500x1500.jpg
last_method: POST last_url: speedtest.keff.org/speedtest/upload.php
last_method: POST last_url: speedtest.keff.org/speedtest/upload.php
last_method: GET last_url: ncc.avast.com/ncc.txt
last_method: GET last_url: ncc.avast.com/ncc.txt
last_method: GET last_url: ncc.avast.com/ncc.txt
図7 ntopng手動実行
アラートのテスト
最後に正しくアラートが発報されるかを確認しましょう。
ここで注意ですが、HTTPかつ拡張子.exeのURLにアクセスする必要があります。
Webクライアントによって、HTTPで接続したつもりがTLSにリダイレクトされることがありますので、テストにはcurlを使ってください。ntopngをインストールしたUbuntuに別ターミナルでログインし、以下を実行してください。
$curl http://github.com/notepad-plus-plus/notepad-plus-plus/releases/download/v7.8.5/npp.7.8.5.Installer.exe
図8 curl手動実行
curlを実行すると、標準出力に図9の内容が表示されます。
last_method: GET last_url: github.com/notepad-plus-plus/notepad-plus-plus/releases/download/v7.8.5/npp.7.8.5.Installer.exe
図9 ntopng標準出力
last_urlが.exeを含んだURLとなっています。
正しくアラートが発報されていこることをntopngのアラート画面で確認してください。
図10 EXEs Downloadのアラート発報
アラート定義やステータス定義で設定した内容が、ntopngのGUIに出力されているのが確認できました。
一度プラグインの開発ステップを覚えれば、比較的簡単に独自のプラグインが作成できます。