SlideShare a Scribd company logo
Wiresharkの 
解析プラグインを作る 
@unkn0wnbit 
2014/9/29 #ssmjp 2014/09
Agenda 
 Wiresharkとは 
 解析プラグインを作るには 
 解析対象プロトコルを定義 
 解析スクリプトの作成 
 既存の解析プラグインの拡張 
 ビット演算 
 おまけ 
2
01. WIRESHARKとは 
3
4 
Wiresharkとは 
 パケットキャプチャツール 
 標準で多彩なプロトコルを解析できるプラ 
グインが付属 
 独自のプロトコルは解析できない 
 独自のプロトコルを解析する場合 
1. 人間デコーダになる 
2. 解析用のプラグインを書く
5 
Wiresharkのパケット処理の流れ 
0100111010101010101110 ネットワーク上を流れるパケット 
キャプチャフィルタ 
解析プラグイン 
ディスプレイフィルタ 
Wireshark画面出力 
キャプチャするパケットをフィルタリング 
パケットを解析 
表示するパケットをフィルタリング 
解析した結果を表示
02. 解析プラグインを作るには 
6
7 
解析プラグインを作るには 
 方法は2つ 
 C/C++言語で作成 
 Wiresharkに組み込まれたLuaスクリプト言 
語で作成 
 今回はLuaで作成します 
面倒そう… 
きっとお手軽
8 
Luaを使う準備(1/2) 
 WiresharkでLuaが有効か確認 
 コンパイル時にLuaの使用を指定 
 公式版Win/Macバイナリともにデフォルトで有効 
 Linuxはディストリビューションによるかも 
http://wiki.wireshark.org/Lua より
9 
Luaを使う準備(2/2) 
 最新バージョン(1.12.1)はデフォルトで使用可能 
 古い設定ファイルを使い回している場合は確認 
 init.lua 内の以下の行を確認 
 disable_lua = true; の行をfalse に変更 
 Windows 
 C:Program FilesWiresharkinit.lua 
 Mac 
 /Applications/Wireshark.app/Contents/Resources/share/wire 
shark/init.lua 
 Linux (Debian 7) 
 /usr/share/wireshark/init.lua
10 
動作確認(1/2) 
 Tools – Lua – Evaluate 
 Evaluate Luaダイアログ
11 
動作確認(2/2) 
 ダイアログにプログラム入力 
local tw = TextWindow.new("Test Program"); 
tw:set("Hello World!") 
 Evaluateボタンを押すと…
12 
Luaスクリプト使用方法(1/2) 
 通常はスクリプトをファイルに保存して、 
Wiresharkの起動時に読み込ませる。 
wireshark.exe -X lua_script:C:/wireshark_plugins/hoge.lua 
 -X オプションは複数回指定可能 
 ディレクトリのデリミタは“” or “/” 
 tsharkも同様(GUIのAPIは使えない) 
 tshark版Hello World 
print("Hello World!")
13 
Luaスクリプト使用方法(2/2) 
 毎回同じスクリプトを使う場合 
 init.luaに以下を追記 
 dofile(”C:/wireshark_plugins/hoge.lua”) 
 Global configuration 
 C:Program FilesWiresharkinit.lua 
 Personal configuration 
 C:Users<user_name>AppDataRoamingWiresharki 
nit.lua 
 各フォルダの確認方法 
 Help – About Wireshark – Folders
03. 解析対象プロトコルを定義 
14
15 
解析対象プロトコルを定義(1/4) 
 解析対象とする簡単なプロトコルを定義 
 乱数文字列生成プロトコル 
 クライアントはサーバに任意の長さの乱数を要 
求する 
 サーバは指定された長さの乱数を文字列として、 
クライアントに返す
16 
解析対象プロトコルを定義(2/4) 
 パケットフォーマット 
 Command Code 
 データ長:1バイト 
 Request or Response 
 Data Length 
 データ長:2バイト 
 Request時:要求するデータ長を指定 
 Response時:Data部の長さを指定 
 Data 
 データ長:Data Lengthで指定されたバイト数 
 Request時:存在しない 
 Response時:応答する実データ 
 データの並びはビッグエンディアン 
bits 
8 1 
Command Code 
Data Length 
Data
17 
解析対象プロトコルを定義(3/4) 
 Command Code 
 Request 
 0x01 
 Response 
 0x51 
 不明なCommand Codeが要求されたとき 
 0xFFを返す
18 
解析対象プロトコルを定義(4/4) 
 UDP版およびTCP版を実装 
 MTUを超えるデータをやりとりする場合、 
TCPの使用を想定。 
 使用ポート番号:10000
04. 解析スクリプトの作成 
19
20 
Wiresharkで見てみる(UDP版) 
Response 
Packet List 
Packet Details 
Packet Bytes
宣言したプロトコルで使用 
するフィールドを定義 
21 
解析スクリプト(UDP版) 
do 
udp_rngp_proto = Proto("RNGP_UDP", "Random Number Generater Protocol (UDP)") 
command_prtf = ProtoField.new("RNGP command", "rngp_udp.command", ftypes.UINT8) 
length_prtf = ProtoField.new("RNGP length", "rngp_udp.length", ftypes.UINT16) 
random_prtf = ProtoField.new("RNGP Random Numbers", "rngp_udp.random", ftypes.STRING) 
udp_rngp_proto.fields = {command_prtf, length_prtf, random_prtf} 
function udp_rngp_proto.dissector(buffer, pinfo, tree) 
local command_names = { 
[0x01] = "Request Random Numbers", 
[0x51] = "Response Random Numbers", 
[0xFF] = "Unknown Request/Response Command", 
} 
local command = buffer(0,1):uint() 
local length = buffer(1,2):uint() 
local subtree = tree:add(udp_rngp_proto, "Random Number Generater Protocol Data") 
subtree:add_packet_field(command_prtf, buffer:range(0,1), ENC_ASCII, "Command:", string.format("0x%02x", command), command_names[command]) 
subtree:add_packet_field(length_prtf, buffer(1,2), ENC_ASCII, "Length:", length) 
if command >= 0x51 and command ~= 0xFF then 
disp_data(command, buffer(3, length):tvb(), subtree) 
end 
pinfo.cols.protocol = "RNGP(UDP)" 
if command_names[command] == nil then 
pinfo.cols.info = "Malformed Request/Response Command" 
else 
pinfo.cols.info = command_names[command] 
end 
end 
udp_table = DissectorTable.get("udp.port") 
udp_table:add(10000, udp_rngp_proto) 
end 
function disp_data(command, buffer, tree) 
if command == 0x51 then 
tree:add_packet_field(random_prtf, buffer(0), ENC_ASCII) 
end 
end 
新しいプロトコルを宣言 
定義したdissectorを 
10000/udpに登録 
buffer : Wiresharkから渡されるパケットのバッファ(tvb) 
pinfo : Packet List情報 
tree : Packet Details内ツリー情報 
buffer(X, Y):uint() 
bufferのXバイト目からYバイトを 
unsigned intとして切り出す 
tree:add(), add_packet_field() 
Packet Details内のツリーに 
アイテムを追加 
Packet ListのProtocolカラムと 
Infoカラムの内容を設定 
dissector(パケットを解析する関数)を定義 
(パケットを受け取るたびに呼び出される)
22 
解析スクリプト(UDP版) 
Response
23 
Wiresharkで見てみる(TCP版) 
Response
宣言したプロトコルで使用 
するフィールドを定義 
24 
解析スクリプト(TCP版) 
do 
tcp_rngp_proto = Proto("RNGP_TCP", "Random Number Generater Protocol (TCP)") 
command_prtf = ProtoField.new("RNGP command", "rngp_tcp.command", ftypes.UINT8) 
length_prtf = ProtoField.new("RNGP length", "rngp_tcp.length", ftypes.UINT16) 
random_prtf = ProtoField.new("RNGP Random Numbers", "rngp_tcp.random", ftypes.STRING) 
tcp_rngp_proto.fields = {command_prtf, length_prtf, random_prtf} 
function tcp_rngp_proto.dissector(buffer, pinfo, tree) 
local command_names = { 
[0x01] = "Request Random Numbers", 
[0x51] = "Response Random Numbers", 
[0xFF] = "Unknown Request/Response Command", 
} 
local command = buffer(0,1):uint() 
local length = buffer(1,2):uint() 
if command == 0x51 and buffer:len() < (3 + length) then 
pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT 
return buffer:len() - (3 + length) 
end 
local subtree = tree:add(tcp_rngp_proto, "Random Number Generater Protocol Data") 
subtree:add_packet_field(command_prtf, buffer:range(0,1), ENC_ASCII, "Command:", string.format("0x%02x", command), command_names[command]) 
subtree:add_packet_field(length_prtf, buffer(1,2), ENC_ASCII, "Length:", length) 
if command >= 0x51 and command ~= 0xFF then 
disp_data(command, buffer(3, length):tvb(), subtree) 
end 
pinfo.cols.protocol = "RNGP(TCP)" 
if command_names[command] == nil then 
pinfo.cols.info = "Malformed Request/Response Command" 
else 
pinfo.cols.info = command_names[command] 
end 
return 3 + length 
end 
tcp_table = DissectorTable.get("tcp.port") 
tcp_table:add(10000, tcp_rngp_proto) 
End 
function disp_data(command, buffer, tree) 
if command == 0x51 then 
tree:add_packet_field(random_prtf, buffer(0), ENC_ASCII) 
end 
end 
新しいプロトコルを宣言 
dissectorを定義 
定義したdissectorを 
10000/tcpに登録 
bufferのデータ長がプロトコルで指定された長 
さよりも短い場合、必要なデータ長になるまで 
処理を行わない。 
次にdissectorが呼び出される際、bufferに後 
続のパケットのペイロードがアペンドされる。 
TCPセグメント再構築
25 
解析スクリプト(TCP版) 
 TCPセグメント再構築イメージ 
1パケット目2パケット目 
1パケット目でdissectorに渡されるbuffer内容 
必要なデータ長に満たないので、pinfo.desegment_lenに 
DESEGMENT_ONE_MORE_SEGMENTをセットして、 
dissectorからreturnする。 
サーバが返すデータ 
2パケット目でdissectorに渡されるbuffer内容 
WiresharkはDESEGMENT_ONE_MORE_SEGMENTがセットされている場合、 
次のパケットのペイロードをbufferにアペンドしてdissectorに渡す。 
必要なデータ長か否かはdissectorが判断する。
26 
解析スクリプト(TCP版) 
Response
05. 既存の解析プラグインの拡張 
27
28 
ところで… 
 独自のプロトコルの解析より、既存の解 
析プラグインを拡張したい、と思うことの 
方が多いかもしれません。 
 この機能が使えます。 
 postdissector 
 chained dissector 
 TAP
29 
postdissector 
 postdissectorとは 
 dissectorが呼び出された後に呼び出される 
dissector 
 同じパケットを複数のdissectorで処理する。 
 種類に関係なく、全てのパケットに対して呼び出 
される。 
 通常のdissectorと同様にパケットの情報へ 
のアクセスやPacket Detailsのツリーにアイ 
テムを追加できる
30 
postdissectorのイメージ 
dissector 
ARP IP 
TCP UDP 
postdissector 
… 
… 
25 80 53 68 … 
各dissectorで処理が行われた後に 
必ず呼び出されるdissector
31 
postdissector例 
TCPの場合に送信元/先IPアドレス 
とポートの組み合わせをPacket 
Detailsに追加。 
http://wiki.wireshark.org/Lua/Dissectors より 
-- trivial postdissector example 
-- declare some Fields to be read 
ip_src_f = Field.new("ip.src") 
ip_dst_f = Field.new("ip.dst") 
tcp_src_f = Field.new("tcp.srcport") 
tcp_dst_f = Field.new("tcp.dstport") 
-- declare our (pseudo) protocol 
trivial_proto = Proto("trivial","Trivial Postdissector") 
-- create the fields for our "protocol" 
src_F = ProtoField.string("trivial.src","Source") 
dst_F = ProtoField.string("trivial.dst","Destination") 
conv_F = ProtoField.string("trivial.conv","Conversation","A Conversation") 
-- add the field to the protocol 
trivial_proto.fields = {src_F, dst_F, conv_F} 
-- create a function to "postdissect" each frame 
function trivial_proto.dissector(buffer,pinfo,tree) 
-- obtain the current values the protocol fields 
local tcp_src = tcp_src_f() 
local tcp_dst = tcp_dst_f() 
local ip_src = ip_src_f() 
local ip_dst = ip_dst_f() 
if tcp_src then 
local subtree = tree:add(trivial_proto,"Trivial Protocol Data") 
local src = tostring(ip_src) .. ":" .. tostring(tcp_src) 
local dst = tostring(ip_dst) .. ":" .. tostring(tcp_dst) 
local conv = src .. "->" .. dst 
subtree:add(src_F,src) 
subtree:add(dst_F,dst) 
subtree:add(conv_F,conv) 
end 
end 
-- register our protocol as a postdissector 
register_postdissector(trivial_proto) 
パケット内で読み取るフィー 
ルドを宣言 
新しいプロトコルを宣言 
宣言したプロトコルで使用 
するフィールドを定義 
postdissectorを定義 
postdissectorを登録
32 
postdissector例実行結果 
定義したプロトコルやフィールドはディス 
プレイフィルタとして指定できる。 
Packet Detailsにも情報を追加できる。 
この例では、TCPの場合のみTrivial 
Protocol Dataツリーが追加される。
33 
chained dissector 
 chained dissectorとは 
 あるdissectorが呼び出された後に続けて呼 
び出されるdissector 
 同じパケットを複数のdissectorで処理する 
 特定のプロトコルに関してのみ呼び出される 
 通常のdissectorと同様にパケットの情報へ 
のアクセスやPacket Detailsのツリーにアイ 
テムを追加できる
34 
chained dissectorのイメージ 
dissector 
ARP IP 
TCP UDP 
chained 
dissector 
… 
… 
25 80 53 68 … 
特定のdissectorに紐付けられて 
呼び出されるdissector
35 
chained dissector例 
do 
local http_suspicious_proto = Proto("http_suspicious", "Suspicious HTTP Traffic") 
local F_suspicious_uri = ProtoField.string("http.suspicious_uri", "Suspicious Request URI") 
local F_suspicious_host = ProtoField.string("http.suspicious_host", "Suspicious Host Header") 
http_suspicious_proto.fields = {F_suspicious_uri, F_suspicious_host} 
local f_request_uri = Field.new("http.request.uri") 
local f_host = Field.new("http.host") 
local original_http_dissector 
function http_suspicious_proto.dissector(buffer, pinfo, tree) 
original_http_dissector:call(buffer, pinfo, tree) 
if f_request_uri() then 
local uri = tostring(f_request_uri()) 
local host = tostring(f_host()) 
chained dissectorの処理を行う前に、 
オリジナルのdissectorで処理を行う。 
if string.match(uri, "%.exe") and string.match(host, "[^j][^p]:%d+") then 
local subtree = tree:add(http_suspicious_proto, buffer) 
subtree:add(F_suspicious_uri, buffer(), uri) 
:set_text("URI : " .. uri) 
subtree:add(F_suspicious_host, buffer(), host) 
:set_text("Host : " .. host) 
end 
end 
end 
local tcp_dissector_table = DissectorTable.get("tcp.port") 
original_http_dissector = tcp_dissector_table:get_dissector(8080) 
tcp_dissector_table:add(8080, http_suspicious_proto) 
end 
新しいプロトコルを宣言 
宣言したプロトコルで使用 
するフィールドを定義 
パケット内で読み取るフィー 
ルドを宣言 
chained dissectorを定義 
リクエストされているURIとHostヘッダ 
から疑わしいか判断。 
chained dissectorを登録 
8080/tcpに登録されているオリジナルの 
dissectorをバックアップ。
36 
chained dissector例実行結果 
定義したプロトコルやフィールドはディス 
プレイフィルタとして指定できる。 
Packet Detailsにも情報を追加できる。 
この例では、疑わしいHTTPのリクエストに 
Suspicious HTTP Trafficツリーが追加さ 
れる。
37 
TAP 
 TAPとは 
 主に統計情報収集用として使用される。 
 全てのパケットに対して呼び出される。 
 フィルタを設定して、該当するパケットのみを処 
理することも可能。 
 キャプチャフィルタの影響は受ける。 
 ディスプレイフィルタの影響は受けない。 
 dissectorとは異なり、Packet Detailsのツ 
リーにアイテムは追加できない。
38 
TAPのイメージ 
0100111010101010101110 
キャプチャフィルタ 
解析プラグイン 
ディスプレイフィルタ 
Wireshark画面出力 
TAP 
dissectorとは独立して 
パケットを解析。
39 
TAP例 
do 
local function menuable_tap() 
-- Declare the window we will use 
local tw = TextWindow.new("Address Counter") 
-- This will contain a hash of counters of appearances of a certain address 
local ips = {} 
-- this is our tap 
local tap = Listener.new(); 
function remove() 
-- this way we remove the listener than otherwise will remain running indifinitelly 
tap:remove(); 
end 
-- we tell the window to call the remove() function when closed 
tw:set_atclose(remove) 
-- this function will be called once for each packet 
function tap.packet(pinfo,tvb) 
local src = ips[tostring(pinfo.src)] or 0 
local dst = ips[tostring(pinfo.dst)] or 0 
ips[tostring(pinfo.src)] = src + 1 
ips[tostring(pinfo.dst)] = dst + 1 
end 
-- this function will be called once every few seconds to update our window 
function tap.draw(t) 
tw:clear() 
for ip,num in pairs(ips) do 
tw:append(ip .. "t" .. num .. "n"); 
end 
end 
-- this function will be called whenever a reset is needed 
-- e.g. when reloading the capture file 
function tap.reset() 
tw:clear() 
ips = {} 
end 
end 
-- using this function we register our fuction 
-- to be called when the user selects the Tools->Test->Packets menu 
register_menu("Test/Packets", menuable_tap, MENU_TOOLS_UNSORTED) 
end 
Listener.new(“frame”, “ip.addr == 10.0.0.0/8”) 
のようにフィルタリングをすることも可能。 
TAPを生成 
送信元または送信先ごとにパケット数をカウント 
パケットを受け取るたびに 
呼び出される関数 
テキストウィンドウに 
結果を表示 
Toolsメニューにスクリプトを 
実行するメニューを追加 
http://www.wireshark.org/docs/wsug_html_chunked/wslua_tap_example.html より
40 
TAP例実行結果 
Tools – Test – Packetsが追加される。 
メニューを実行して、パケットキャプチャを 
行うと、送信元または送信先ごとのパケット 
数がウィンドウに表示される。 
Wiresharkの名前解決を有効にすると、ドメ 
イン名などが解決された結果で集計される。
06. ビット演算 
41
42 
Luaのビット演算 
 Lua 5.2でビット演算がサポート 
 公式版WindowsバイナリはLua 5.2組み込み 
 公式版MacバイナリはLua 5.1組み込み 
 いずれも、Wireshark 1.12.1で確認 
 Linuxはディストリビューションによるかも 
 Debian 7では、Wireshark 1.8.2のパッケージ(Lua 5.1) 
 Lua 5.1では外部ライブラリを使えば可能 
 bitop : http://bitop.luajit.org/ 
 Lua 5.1/5.2用 
 使うならばこちらがお勧めだが、Lua 5.2とAPIが異なる 
 Debian 7ではパッケージが用意されている(lua-bitop) 
 bitlib : https://github.com/LuaDist/bitlib 
 Lua 5.1用 
 もうメンテナンスされていないっぽい
Luaビット演算 
 API 
 bit32.arshift, bit32.band, bit32.bnot, bit32.bor, bit32.btest, 
bit32.bxor, bit32.bextract, bit32.lrotate, bit32.lshift, 
bit32.replace, bit32.rrotate, bit32.rshift 
 詳細:http://www.lua.org/manual/5.2/manual.html#6.7 
 “0x1234” と“0xFF00” のANDの動作確認 
 Tools – Lua – Evaluate で以下を入力 
43 
local tw = TextWindow.new("BitOp Test Program"); 
band_val = bit32.band(0x1234, 0xFF00) 
tw:set("lua version: " .. _VERSION .."n" .. band_val )
44 
まとめ 
 パケット単位の解析 
 今まさにキャプチャしたパケットのみが解析対象 
 過去のパケットの情報は取得できない 
 1つのプロトコルにつき、1つのdissector 
 単一のdissectorでRequestとResponseを解析 
 chained dissectorなどで既存のdissectorの拡張は可能 
 WiresharkでLuaを使うにはコンパイル時に指定する必要あり 
 公式配布バイナリ(Win/Mac)版は標準で組み込み済み 
 Windowsバイナリ:Lua 5.2 
 Macバイナリ:Lua 5.1 
 Linux版はディストリビューションによって異なる可能性あり 
 Lua 5.2未満の場合はビット演算ができない 
 外部ライブラリ(bitop)を使えば可能 
 ただし、本家LuaとAPIが異なる
45 
参考 
 Wireshark 
 Wireshark User’s Guide 
 https://www.wireshark.org/docs/wsug_html_chunked/wsluarm.html 
 https://www.wireshark.org/docs/wsug_html_chunked/lua_module_Proto.html#lua_class_ProtoField 
 https://www.wireshark.org/docs/wsug_html_chunked/lua_module_Tree.html 
 The Wireshark Wiki 
 http://wiki.wireshark.org/Lua 
 http://wiki.wireshark.org/Lua/Dissectors 
 http://wiki.wireshark.org/Lua/Examples 
 http://wiki.wireshark.org/Lua/Taps 
 Wireshark 1.2.9 ソースコードアーカイブ内 
 README.developer 
 README.tapping 
 Lua 
 http://www.lua.org/manual/5.2/manual.html#6.7 
 その他 
 Googleブックス(http://books.google.co.jp/books) 
 Wireshark and Ethereal network protocol analyzer toolkit 
 実践パケット解析: Wiresharkを使ったトラブルシューティング 
 http://www.lua.org/ 
 http://bitop.luajit.org/ 
 http://luaforge.net/projects/bitlib/
46 
Q & A
おまけ 
 Lua以外のバインディング言語 
 SSL復号 
 サーバの証明書を使う 
 ブラウザの暗号鍵を使う 
47 
今回やりません。 
ググって!
Lua以外のバインディング 
おまけ1 
48
Lua以外のバインディング言語 
 Aboutダイアログをよくみると… 
49
Pythonバインディングの実際のところ 
 withoutなのでWireshark wikiを見てみる 
http://wiki.wireshark.org/Python より 
50
pyresharkについて 
 LuaのようにTCPやUDPのポート毎に 
dissectorを登録するようなAPIが用意さ 
れていない。 
 tcp_table = DissectorTable.get("tcp.port") 
 tcp_table:add(10000, tcp_rngp_proto) 
 TCP/IPヘッダを自力でゴリゴリ解析する 
必要がありそう。 
 面倒そうなので試すのをやめました…。 
51
ブラウザ側の暗号鍵を使ったSSL復号 
おまけ2 
52
WiresharkでSSL復号 
 よく見かける方法として、サーバのSSL秘密鍵を 
Wiresharkに設定して、パケットキャプチャの解析を行う 
手順が解説されている。 
 自分がSSL秘密鍵を持っていない場合、通信内容が分 
からない! 
 外部のサービスを使う場合とか 
 Fiddlerとか使えば見えますが 
 しかし、SSL秘密鍵がなくても、ブラウザ側が持ってい 
る暗号鍵でSSL復号を行うことができる。 
53
ブラウザの暗号鍵で復号 
 SSLKEYLOGFILE環境変数を設定する 
 SSLKEYLOGFILE=/path/to/sslkeylog.txt 
 Wiresharkで以下を設定 
 Edit – Preferences – Protocols – SSL – (Pre)-Master- 
Secret log filename 
 display filter で“ssl” を設定 
 適当なパケットを選択して、Follow SSL Stream 
 Packet BytesのDecrypted SSL dataタブ等 
 鍵交換プロトコルがRSAでもECDHE(Perfect Forward 
Secrecy)でも復号可能 
 PFSだとサーバのSSL秘密鍵を持っていても復号できない 
54
SSLKEYLOGFILEフォーマット 
 CLIENT_RANDOM <space> <64 bytes of hex encoded 
client_random> <space> <96 bytes of hex encoded master secret> 
 RSA <space> <16 bytes of hex encoded encrypted pre master 
secret> <space> <96 bytes of hex encoded pre master secret> 
55
使用ブラウザの制限 
 SSLKEYLOGFILE環境変数を見てログファイルを作る 
のは、NSS(Network Security Services)ライブラリであ 
るため、同様の手順が取れるのは同ライブラリを使用 
するブラウザ、ツールのみ。 
 NSSを使用する主なブラウザは、Firefox, PC版 
Chrome(Win/Mac/Linux版含む)のみ。 
 Android版ChromeはOpenSSLを使用 
 PC版ChromeもBoringSSLを使い始めた場合は使えなくない 
 他のブラウザの場合はメモリダンプするくらいしか手が 
ないんじゃ…。 
56
参考 
 pyreshark 
 https://github.com/ashdnazg/pyreshark 
 Psst. Your Browser Knows All Your Secrets. 
 https://isc.sans.edu/diary/Psst.+Your+Browser+Knows+All+Your+Secrets./16415 
 NSS Key Log Format 
 https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format 
 Chrome: From NSS to OpenSSL 
 https://docs.google.com/document/d/1ML11ZyyMpnAr6clIAwWrXD53pQgNR-DppMYwt9XvE6s/ 
edit?pli=1#heading=h.n30fi956cpfk 
 SSL/TLS & Perfect Forward Secrecy 
 http://vincent.bernat.im/en/blog/2011-ssl-perfect-forward-secrecy.html 
 ディフィー・ヘルマン鍵共有 
 http://ja.wikipedia.org/wiki/%E3%83%87%E3%82%A3%E3%83%95%E3%82%A3%E3%83%BC 
%E3%83%BB%E3%83%98%E3%83%AB%E3%83%9E%E3%83%B3%E9%8D%B5%E5%85%B 
1%E6%9C%89 
 Diffie–Hellman key exchange 
 http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange 
57
58 
Q & A

More Related Content

PDF
その ionice、ほんとに効いてますか?
Narimichi Takamura
 
PDF
Onieで遊んでみようとした話
Masaru Oki
 
PPTX
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
NTT DATA Technology & Innovation
 
PPTX
ネットワーク機器のAPIあれこれ入門 (NetOpsCoding#2)
Kentaro Ebisawa
 
PDF
コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)
NTT DATA Technology & Innovation
 
PDF
より速く より運用しやすく 進化し続けるJVM(Java Developers Summit Online 2023 発表資料)
NTT DATA Technology & Innovation
 
PPTX
コンテナネットワーキング(CNI)最前線
Motonori Shindo
 
PDF
ネットワークOS野郎 ~ インフラ野郎Night 20160414
Kentaro Ebisawa
 
その ionice、ほんとに効いてますか?
Narimichi Takamura
 
Onieで遊んでみようとした話
Masaru Oki
 
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
NTT DATA Technology & Innovation
 
ネットワーク機器のAPIあれこれ入門 (NetOpsCoding#2)
Kentaro Ebisawa
 
コンテナセキュリティにおける権限制御(OCHaCafe5 #3 Kubernetes のセキュリティ 発表資料)
NTT DATA Technology & Innovation
 
より速く より運用しやすく 進化し続けるJVM(Java Developers Summit Online 2023 発表資料)
NTT DATA Technology & Innovation
 
コンテナネットワーキング(CNI)最前線
Motonori Shindo
 
ネットワークOS野郎 ~ インフラ野郎Night 20160414
Kentaro Ebisawa
 

What's hot (20)

PDF
NETCONFとYANGの話
Masakazu Asama
 
PDF
KubeCon + CloudNativeCon Europe 2022 Recap - Batch/HPCの潮流とScheduler拡張事例 / Kub...
Preferred Networks
 
PDF
DockerとKubernetesをかけめぐる
Kohei Tokunaga
 
PPTX
Docker Tokyo
cyberblack28 Ichikawa
 
PDF
"SRv6の現状と展望" ENOG53@上越
Kentaro Ebisawa
 
PDF
ネットワークコンフィグ分析ツール Batfish との付き合い方
akira6592
 
PDF
雑なMySQLパフォーマンスチューニング
yoku0825
 
PDF
Scapyで作る・解析するパケット
Takaaki Hoyo
 
PDF
Kotlinアンチパターン
Recruit Lifestyle Co., Ltd.
 
PDF
コンテナの作り方「Dockerは裏方で何をしているのか?」
Masahito Zembutsu
 
PDF
DockerとPodmanの比較
Akihiro Suda
 
PPTX
FD.io VPP事始め
tetsusat
 
PDF
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
NTT DATA Technology & Innovation
 
PDF
【Interop Tokyo 2018】 Telemetryの匠が解説~オープン技術を用いたマイクロバースト検知の最前線~
Juniper Networks (日本)
 
PDF
例外設計における大罪
Takuto Wada
 
PDF
オンラインゲームの仕組みと工夫
Yuta Imai
 
PPTX
Effective Modern C++ 勉強会 Item 22
Keisuke Fukuda
 
PPTX
Dockerからcontainerdへの移行
Akihiro Suda
 
PDF
DPDKによる高速コンテナネットワーキング
Tomoya Hibi
 
PDF
Dockerイメージ管理の内部構造
Etsuji Nakai
 
NETCONFとYANGの話
Masakazu Asama
 
KubeCon + CloudNativeCon Europe 2022 Recap - Batch/HPCの潮流とScheduler拡張事例 / Kub...
Preferred Networks
 
DockerとKubernetesをかけめぐる
Kohei Tokunaga
 
Docker Tokyo
cyberblack28 Ichikawa
 
"SRv6の現状と展望" ENOG53@上越
Kentaro Ebisawa
 
ネットワークコンフィグ分析ツール Batfish との付き合い方
akira6592
 
雑なMySQLパフォーマンスチューニング
yoku0825
 
Scapyで作る・解析するパケット
Takaaki Hoyo
 
Kotlinアンチパターン
Recruit Lifestyle Co., Ltd.
 
コンテナの作り方「Dockerは裏方で何をしているのか?」
Masahito Zembutsu
 
DockerとPodmanの比較
Akihiro Suda
 
FD.io VPP事始め
tetsusat
 
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
NTT DATA Technology & Innovation
 
【Interop Tokyo 2018】 Telemetryの匠が解説~オープン技術を用いたマイクロバースト検知の最前線~
Juniper Networks (日本)
 
例外設計における大罪
Takuto Wada
 
オンラインゲームの仕組みと工夫
Yuta Imai
 
Effective Modern C++ 勉強会 Item 22
Keisuke Fukuda
 
Dockerからcontainerdへの移行
Akihiro Suda
 
DPDKによる高速コンテナネットワーキング
Tomoya Hibi
 
Dockerイメージ管理の内部構造
Etsuji Nakai
 
Ad

Similar to Wiresharkの解析プラグインを作る ssmjp 201409 (20)

PDF
Hokkaido.cap#2 一般的なプロトコルのパケットを覗いてみよう
Panda Yamaki
 
PDF
Hokkaido.cap #osc11do Wiresharkを使いこなそう!
Panda Yamaki
 
PDF
Windowsのパケットモニタ作成
Shinichi Hirauchi
 
PPTX
Apache Camel Netty component
ssogabe
 
PDF
Hokkaido.cap#1 Wiresharkの使い方(基礎編)
Panda Yamaki
 
PDF
debugging server with strace
Yoshinari Takaoka
 
PDF
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
de:code 2017
 
PPTX
システムパフォーマンス勉強会#8
shingo suzuki
 
PDF
Trema day 1
ykuga
 
PPTX
Prosym2012
MITSUNARI Shigeo
 
PDF
ラズパイでデバイスドライバを作ってみた。
Kazuki Onishi
 
PDF
Boost Tour 1.50.0 All
Akira Takahashi
 
PPTX
Polyphony の行く末(2018/3/3)
ryos36
 
KEY
P2Pって何?
Junya Yamaguchi
 
PDF
RouterBOARD with OpenFlow
Toshiki Tsuboi
 
PDF
Scapy presentation
ashigirl ZareGoto
 
PPTX
VPP事始め
npsg
 
PDF
Inside winnyp
FFRI, Inc.
 
PDF
実践 WebRTC 〜最新事例と開発ノウハウの紹介〜
Yusuke Naka
 
PDF
Netty & Apache Camel
ssogabe
 
Hokkaido.cap#2 一般的なプロトコルのパケットを覗いてみよう
Panda Yamaki
 
Hokkaido.cap #osc11do Wiresharkを使いこなそう!
Panda Yamaki
 
Windowsのパケットモニタ作成
Shinichi Hirauchi
 
Apache Camel Netty component
ssogabe
 
Hokkaido.cap#1 Wiresharkの使い方(基礎編)
Panda Yamaki
 
debugging server with strace
Yoshinari Takaoka
 
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
de:code 2017
 
システムパフォーマンス勉強会#8
shingo suzuki
 
Trema day 1
ykuga
 
Prosym2012
MITSUNARI Shigeo
 
ラズパイでデバイスドライバを作ってみた。
Kazuki Onishi
 
Boost Tour 1.50.0 All
Akira Takahashi
 
Polyphony の行く末(2018/3/3)
ryos36
 
P2Pって何?
Junya Yamaguchi
 
RouterBOARD with OpenFlow
Toshiki Tsuboi
 
Scapy presentation
ashigirl ZareGoto
 
VPP事始め
npsg
 
Inside winnyp
FFRI, Inc.
 
実践 WebRTC 〜最新事例と開発ノウハウの紹介〜
Yusuke Naka
 
Netty & Apache Camel
ssogabe
 
Ad

Wiresharkの解析プラグインを作る ssmjp 201409

  • 2. Agenda  Wiresharkとは  解析プラグインを作るには  解析対象プロトコルを定義  解析スクリプトの作成  既存の解析プラグインの拡張  ビット演算  おまけ 2
  • 4. 4 Wiresharkとは  パケットキャプチャツール  標準で多彩なプロトコルを解析できるプラ グインが付属  独自のプロトコルは解析できない  独自のプロトコルを解析する場合 1. 人間デコーダになる 2. 解析用のプラグインを書く
  • 5. 5 Wiresharkのパケット処理の流れ 0100111010101010101110 ネットワーク上を流れるパケット キャプチャフィルタ 解析プラグイン ディスプレイフィルタ Wireshark画面出力 キャプチャするパケットをフィルタリング パケットを解析 表示するパケットをフィルタリング 解析した結果を表示
  • 7. 7 解析プラグインを作るには  方法は2つ  C/C++言語で作成  Wiresharkに組み込まれたLuaスクリプト言 語で作成  今回はLuaで作成します 面倒そう… きっとお手軽
  • 8. 8 Luaを使う準備(1/2)  WiresharkでLuaが有効か確認  コンパイル時にLuaの使用を指定  公式版Win/Macバイナリともにデフォルトで有効  Linuxはディストリビューションによるかも http://wiki.wireshark.org/Lua より
  • 9. 9 Luaを使う準備(2/2)  最新バージョン(1.12.1)はデフォルトで使用可能  古い設定ファイルを使い回している場合は確認  init.lua 内の以下の行を確認  disable_lua = true; の行をfalse に変更  Windows  C:Program FilesWiresharkinit.lua  Mac  /Applications/Wireshark.app/Contents/Resources/share/wire shark/init.lua  Linux (Debian 7)  /usr/share/wireshark/init.lua
  • 10. 10 動作確認(1/2)  Tools – Lua – Evaluate  Evaluate Luaダイアログ
  • 11. 11 動作確認(2/2)  ダイアログにプログラム入力 local tw = TextWindow.new("Test Program"); tw:set("Hello World!")  Evaluateボタンを押すと…
  • 12. 12 Luaスクリプト使用方法(1/2)  通常はスクリプトをファイルに保存して、 Wiresharkの起動時に読み込ませる。 wireshark.exe -X lua_script:C:/wireshark_plugins/hoge.lua  -X オプションは複数回指定可能  ディレクトリのデリミタは“” or “/”  tsharkも同様(GUIのAPIは使えない)  tshark版Hello World print("Hello World!")
  • 13. 13 Luaスクリプト使用方法(2/2)  毎回同じスクリプトを使う場合  init.luaに以下を追記  dofile(”C:/wireshark_plugins/hoge.lua”)  Global configuration  C:Program FilesWiresharkinit.lua  Personal configuration  C:Users<user_name>AppDataRoamingWiresharki nit.lua  各フォルダの確認方法  Help – About Wireshark – Folders
  • 15. 15 解析対象プロトコルを定義(1/4)  解析対象とする簡単なプロトコルを定義  乱数文字列生成プロトコル  クライアントはサーバに任意の長さの乱数を要 求する  サーバは指定された長さの乱数を文字列として、 クライアントに返す
  • 16. 16 解析対象プロトコルを定義(2/4)  パケットフォーマット  Command Code  データ長:1バイト  Request or Response  Data Length  データ長:2バイト  Request時:要求するデータ長を指定  Response時:Data部の長さを指定  Data  データ長:Data Lengthで指定されたバイト数  Request時:存在しない  Response時:応答する実データ  データの並びはビッグエンディアン bits 8 1 Command Code Data Length Data
  • 17. 17 解析対象プロトコルを定義(3/4)  Command Code  Request  0x01  Response  0x51  不明なCommand Codeが要求されたとき  0xFFを返す
  • 18. 18 解析対象プロトコルを定義(4/4)  UDP版およびTCP版を実装  MTUを超えるデータをやりとりする場合、 TCPの使用を想定。  使用ポート番号:10000
  • 20. 20 Wiresharkで見てみる(UDP版) Response Packet List Packet Details Packet Bytes
  • 21. 宣言したプロトコルで使用 するフィールドを定義 21 解析スクリプト(UDP版) do udp_rngp_proto = Proto("RNGP_UDP", "Random Number Generater Protocol (UDP)") command_prtf = ProtoField.new("RNGP command", "rngp_udp.command", ftypes.UINT8) length_prtf = ProtoField.new("RNGP length", "rngp_udp.length", ftypes.UINT16) random_prtf = ProtoField.new("RNGP Random Numbers", "rngp_udp.random", ftypes.STRING) udp_rngp_proto.fields = {command_prtf, length_prtf, random_prtf} function udp_rngp_proto.dissector(buffer, pinfo, tree) local command_names = { [0x01] = "Request Random Numbers", [0x51] = "Response Random Numbers", [0xFF] = "Unknown Request/Response Command", } local command = buffer(0,1):uint() local length = buffer(1,2):uint() local subtree = tree:add(udp_rngp_proto, "Random Number Generater Protocol Data") subtree:add_packet_field(command_prtf, buffer:range(0,1), ENC_ASCII, "Command:", string.format("0x%02x", command), command_names[command]) subtree:add_packet_field(length_prtf, buffer(1,2), ENC_ASCII, "Length:", length) if command >= 0x51 and command ~= 0xFF then disp_data(command, buffer(3, length):tvb(), subtree) end pinfo.cols.protocol = "RNGP(UDP)" if command_names[command] == nil then pinfo.cols.info = "Malformed Request/Response Command" else pinfo.cols.info = command_names[command] end end udp_table = DissectorTable.get("udp.port") udp_table:add(10000, udp_rngp_proto) end function disp_data(command, buffer, tree) if command == 0x51 then tree:add_packet_field(random_prtf, buffer(0), ENC_ASCII) end end 新しいプロトコルを宣言 定義したdissectorを 10000/udpに登録 buffer : Wiresharkから渡されるパケットのバッファ(tvb) pinfo : Packet List情報 tree : Packet Details内ツリー情報 buffer(X, Y):uint() bufferのXバイト目からYバイトを unsigned intとして切り出す tree:add(), add_packet_field() Packet Details内のツリーに アイテムを追加 Packet ListのProtocolカラムと Infoカラムの内容を設定 dissector(パケットを解析する関数)を定義 (パケットを受け取るたびに呼び出される)
  • 24. 宣言したプロトコルで使用 するフィールドを定義 24 解析スクリプト(TCP版) do tcp_rngp_proto = Proto("RNGP_TCP", "Random Number Generater Protocol (TCP)") command_prtf = ProtoField.new("RNGP command", "rngp_tcp.command", ftypes.UINT8) length_prtf = ProtoField.new("RNGP length", "rngp_tcp.length", ftypes.UINT16) random_prtf = ProtoField.new("RNGP Random Numbers", "rngp_tcp.random", ftypes.STRING) tcp_rngp_proto.fields = {command_prtf, length_prtf, random_prtf} function tcp_rngp_proto.dissector(buffer, pinfo, tree) local command_names = { [0x01] = "Request Random Numbers", [0x51] = "Response Random Numbers", [0xFF] = "Unknown Request/Response Command", } local command = buffer(0,1):uint() local length = buffer(1,2):uint() if command == 0x51 and buffer:len() < (3 + length) then pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT return buffer:len() - (3 + length) end local subtree = tree:add(tcp_rngp_proto, "Random Number Generater Protocol Data") subtree:add_packet_field(command_prtf, buffer:range(0,1), ENC_ASCII, "Command:", string.format("0x%02x", command), command_names[command]) subtree:add_packet_field(length_prtf, buffer(1,2), ENC_ASCII, "Length:", length) if command >= 0x51 and command ~= 0xFF then disp_data(command, buffer(3, length):tvb(), subtree) end pinfo.cols.protocol = "RNGP(TCP)" if command_names[command] == nil then pinfo.cols.info = "Malformed Request/Response Command" else pinfo.cols.info = command_names[command] end return 3 + length end tcp_table = DissectorTable.get("tcp.port") tcp_table:add(10000, tcp_rngp_proto) End function disp_data(command, buffer, tree) if command == 0x51 then tree:add_packet_field(random_prtf, buffer(0), ENC_ASCII) end end 新しいプロトコルを宣言 dissectorを定義 定義したdissectorを 10000/tcpに登録 bufferのデータ長がプロトコルで指定された長 さよりも短い場合、必要なデータ長になるまで 処理を行わない。 次にdissectorが呼び出される際、bufferに後 続のパケットのペイロードがアペンドされる。 TCPセグメント再構築
  • 25. 25 解析スクリプト(TCP版)  TCPセグメント再構築イメージ 1パケット目2パケット目 1パケット目でdissectorに渡されるbuffer内容 必要なデータ長に満たないので、pinfo.desegment_lenに DESEGMENT_ONE_MORE_SEGMENTをセットして、 dissectorからreturnする。 サーバが返すデータ 2パケット目でdissectorに渡されるbuffer内容 WiresharkはDESEGMENT_ONE_MORE_SEGMENTがセットされている場合、 次のパケットのペイロードをbufferにアペンドしてdissectorに渡す。 必要なデータ長か否かはdissectorが判断する。
  • 28. 28 ところで…  独自のプロトコルの解析より、既存の解 析プラグインを拡張したい、と思うことの 方が多いかもしれません。  この機能が使えます。  postdissector  chained dissector  TAP
  • 29. 29 postdissector  postdissectorとは  dissectorが呼び出された後に呼び出される dissector  同じパケットを複数のdissectorで処理する。  種類に関係なく、全てのパケットに対して呼び出 される。  通常のdissectorと同様にパケットの情報へ のアクセスやPacket Detailsのツリーにアイ テムを追加できる
  • 30. 30 postdissectorのイメージ dissector ARP IP TCP UDP postdissector … … 25 80 53 68 … 各dissectorで処理が行われた後に 必ず呼び出されるdissector
  • 31. 31 postdissector例 TCPの場合に送信元/先IPアドレス とポートの組み合わせをPacket Detailsに追加。 http://wiki.wireshark.org/Lua/Dissectors より -- trivial postdissector example -- declare some Fields to be read ip_src_f = Field.new("ip.src") ip_dst_f = Field.new("ip.dst") tcp_src_f = Field.new("tcp.srcport") tcp_dst_f = Field.new("tcp.dstport") -- declare our (pseudo) protocol trivial_proto = Proto("trivial","Trivial Postdissector") -- create the fields for our "protocol" src_F = ProtoField.string("trivial.src","Source") dst_F = ProtoField.string("trivial.dst","Destination") conv_F = ProtoField.string("trivial.conv","Conversation","A Conversation") -- add the field to the protocol trivial_proto.fields = {src_F, dst_F, conv_F} -- create a function to "postdissect" each frame function trivial_proto.dissector(buffer,pinfo,tree) -- obtain the current values the protocol fields local tcp_src = tcp_src_f() local tcp_dst = tcp_dst_f() local ip_src = ip_src_f() local ip_dst = ip_dst_f() if tcp_src then local subtree = tree:add(trivial_proto,"Trivial Protocol Data") local src = tostring(ip_src) .. ":" .. tostring(tcp_src) local dst = tostring(ip_dst) .. ":" .. tostring(tcp_dst) local conv = src .. "->" .. dst subtree:add(src_F,src) subtree:add(dst_F,dst) subtree:add(conv_F,conv) end end -- register our protocol as a postdissector register_postdissector(trivial_proto) パケット内で読み取るフィー ルドを宣言 新しいプロトコルを宣言 宣言したプロトコルで使用 するフィールドを定義 postdissectorを定義 postdissectorを登録
  • 32. 32 postdissector例実行結果 定義したプロトコルやフィールドはディス プレイフィルタとして指定できる。 Packet Detailsにも情報を追加できる。 この例では、TCPの場合のみTrivial Protocol Dataツリーが追加される。
  • 33. 33 chained dissector  chained dissectorとは  あるdissectorが呼び出された後に続けて呼 び出されるdissector  同じパケットを複数のdissectorで処理する  特定のプロトコルに関してのみ呼び出される  通常のdissectorと同様にパケットの情報へ のアクセスやPacket Detailsのツリーにアイ テムを追加できる
  • 34. 34 chained dissectorのイメージ dissector ARP IP TCP UDP chained dissector … … 25 80 53 68 … 特定のdissectorに紐付けられて 呼び出されるdissector
  • 35. 35 chained dissector例 do local http_suspicious_proto = Proto("http_suspicious", "Suspicious HTTP Traffic") local F_suspicious_uri = ProtoField.string("http.suspicious_uri", "Suspicious Request URI") local F_suspicious_host = ProtoField.string("http.suspicious_host", "Suspicious Host Header") http_suspicious_proto.fields = {F_suspicious_uri, F_suspicious_host} local f_request_uri = Field.new("http.request.uri") local f_host = Field.new("http.host") local original_http_dissector function http_suspicious_proto.dissector(buffer, pinfo, tree) original_http_dissector:call(buffer, pinfo, tree) if f_request_uri() then local uri = tostring(f_request_uri()) local host = tostring(f_host()) chained dissectorの処理を行う前に、 オリジナルのdissectorで処理を行う。 if string.match(uri, "%.exe") and string.match(host, "[^j][^p]:%d+") then local subtree = tree:add(http_suspicious_proto, buffer) subtree:add(F_suspicious_uri, buffer(), uri) :set_text("URI : " .. uri) subtree:add(F_suspicious_host, buffer(), host) :set_text("Host : " .. host) end end end local tcp_dissector_table = DissectorTable.get("tcp.port") original_http_dissector = tcp_dissector_table:get_dissector(8080) tcp_dissector_table:add(8080, http_suspicious_proto) end 新しいプロトコルを宣言 宣言したプロトコルで使用 するフィールドを定義 パケット内で読み取るフィー ルドを宣言 chained dissectorを定義 リクエストされているURIとHostヘッダ から疑わしいか判断。 chained dissectorを登録 8080/tcpに登録されているオリジナルの dissectorをバックアップ。
  • 36. 36 chained dissector例実行結果 定義したプロトコルやフィールドはディス プレイフィルタとして指定できる。 Packet Detailsにも情報を追加できる。 この例では、疑わしいHTTPのリクエストに Suspicious HTTP Trafficツリーが追加さ れる。
  • 37. 37 TAP  TAPとは  主に統計情報収集用として使用される。  全てのパケットに対して呼び出される。  フィルタを設定して、該当するパケットのみを処 理することも可能。  キャプチャフィルタの影響は受ける。  ディスプレイフィルタの影響は受けない。  dissectorとは異なり、Packet Detailsのツ リーにアイテムは追加できない。
  • 38. 38 TAPのイメージ 0100111010101010101110 キャプチャフィルタ 解析プラグイン ディスプレイフィルタ Wireshark画面出力 TAP dissectorとは独立して パケットを解析。
  • 39. 39 TAP例 do local function menuable_tap() -- Declare the window we will use local tw = TextWindow.new("Address Counter") -- This will contain a hash of counters of appearances of a certain address local ips = {} -- this is our tap local tap = Listener.new(); function remove() -- this way we remove the listener than otherwise will remain running indifinitelly tap:remove(); end -- we tell the window to call the remove() function when closed tw:set_atclose(remove) -- this function will be called once for each packet function tap.packet(pinfo,tvb) local src = ips[tostring(pinfo.src)] or 0 local dst = ips[tostring(pinfo.dst)] or 0 ips[tostring(pinfo.src)] = src + 1 ips[tostring(pinfo.dst)] = dst + 1 end -- this function will be called once every few seconds to update our window function tap.draw(t) tw:clear() for ip,num in pairs(ips) do tw:append(ip .. "t" .. num .. "n"); end end -- this function will be called whenever a reset is needed -- e.g. when reloading the capture file function tap.reset() tw:clear() ips = {} end end -- using this function we register our fuction -- to be called when the user selects the Tools->Test->Packets menu register_menu("Test/Packets", menuable_tap, MENU_TOOLS_UNSORTED) end Listener.new(“frame”, “ip.addr == 10.0.0.0/8”) のようにフィルタリングをすることも可能。 TAPを生成 送信元または送信先ごとにパケット数をカウント パケットを受け取るたびに 呼び出される関数 テキストウィンドウに 結果を表示 Toolsメニューにスクリプトを 実行するメニューを追加 http://www.wireshark.org/docs/wsug_html_chunked/wslua_tap_example.html より
  • 40. 40 TAP例実行結果 Tools – Test – Packetsが追加される。 メニューを実行して、パケットキャプチャを 行うと、送信元または送信先ごとのパケット 数がウィンドウに表示される。 Wiresharkの名前解決を有効にすると、ドメ イン名などが解決された結果で集計される。
  • 42. 42 Luaのビット演算  Lua 5.2でビット演算がサポート  公式版WindowsバイナリはLua 5.2組み込み  公式版MacバイナリはLua 5.1組み込み  いずれも、Wireshark 1.12.1で確認  Linuxはディストリビューションによるかも  Debian 7では、Wireshark 1.8.2のパッケージ(Lua 5.1)  Lua 5.1では外部ライブラリを使えば可能  bitop : http://bitop.luajit.org/  Lua 5.1/5.2用  使うならばこちらがお勧めだが、Lua 5.2とAPIが異なる  Debian 7ではパッケージが用意されている(lua-bitop)  bitlib : https://github.com/LuaDist/bitlib  Lua 5.1用  もうメンテナンスされていないっぽい
  • 43. Luaビット演算  API  bit32.arshift, bit32.band, bit32.bnot, bit32.bor, bit32.btest, bit32.bxor, bit32.bextract, bit32.lrotate, bit32.lshift, bit32.replace, bit32.rrotate, bit32.rshift  詳細:http://www.lua.org/manual/5.2/manual.html#6.7  “0x1234” と“0xFF00” のANDの動作確認  Tools – Lua – Evaluate で以下を入力 43 local tw = TextWindow.new("BitOp Test Program"); band_val = bit32.band(0x1234, 0xFF00) tw:set("lua version: " .. _VERSION .."n" .. band_val )
  • 44. 44 まとめ  パケット単位の解析  今まさにキャプチャしたパケットのみが解析対象  過去のパケットの情報は取得できない  1つのプロトコルにつき、1つのdissector  単一のdissectorでRequestとResponseを解析  chained dissectorなどで既存のdissectorの拡張は可能  WiresharkでLuaを使うにはコンパイル時に指定する必要あり  公式配布バイナリ(Win/Mac)版は標準で組み込み済み  Windowsバイナリ:Lua 5.2  Macバイナリ:Lua 5.1  Linux版はディストリビューションによって異なる可能性あり  Lua 5.2未満の場合はビット演算ができない  外部ライブラリ(bitop)を使えば可能  ただし、本家LuaとAPIが異なる
  • 45. 45 参考  Wireshark  Wireshark User’s Guide  https://www.wireshark.org/docs/wsug_html_chunked/wsluarm.html  https://www.wireshark.org/docs/wsug_html_chunked/lua_module_Proto.html#lua_class_ProtoField  https://www.wireshark.org/docs/wsug_html_chunked/lua_module_Tree.html  The Wireshark Wiki  http://wiki.wireshark.org/Lua  http://wiki.wireshark.org/Lua/Dissectors  http://wiki.wireshark.org/Lua/Examples  http://wiki.wireshark.org/Lua/Taps  Wireshark 1.2.9 ソースコードアーカイブ内  README.developer  README.tapping  Lua  http://www.lua.org/manual/5.2/manual.html#6.7  その他  Googleブックス(http://books.google.co.jp/books)  Wireshark and Ethereal network protocol analyzer toolkit  実践パケット解析: Wiresharkを使ったトラブルシューティング  http://www.lua.org/  http://bitop.luajit.org/  http://luaforge.net/projects/bitlib/
  • 46. 46 Q & A
  • 47. おまけ  Lua以外のバインディング言語  SSL復号  サーバの証明書を使う  ブラウザの暗号鍵を使う 47 今回やりません。 ググって!
  • 50. Pythonバインディングの実際のところ  withoutなのでWireshark wikiを見てみる http://wiki.wireshark.org/Python より 50
  • 51. pyresharkについて  LuaのようにTCPやUDPのポート毎に dissectorを登録するようなAPIが用意さ れていない。  tcp_table = DissectorTable.get("tcp.port")  tcp_table:add(10000, tcp_rngp_proto)  TCP/IPヘッダを自力でゴリゴリ解析する 必要がありそう。  面倒そうなので試すのをやめました…。 51
  • 53. WiresharkでSSL復号  よく見かける方法として、サーバのSSL秘密鍵を Wiresharkに設定して、パケットキャプチャの解析を行う 手順が解説されている。  自分がSSL秘密鍵を持っていない場合、通信内容が分 からない!  外部のサービスを使う場合とか  Fiddlerとか使えば見えますが  しかし、SSL秘密鍵がなくても、ブラウザ側が持ってい る暗号鍵でSSL復号を行うことができる。 53
  • 54. ブラウザの暗号鍵で復号  SSLKEYLOGFILE環境変数を設定する  SSLKEYLOGFILE=/path/to/sslkeylog.txt  Wiresharkで以下を設定  Edit – Preferences – Protocols – SSL – (Pre)-Master- Secret log filename  display filter で“ssl” を設定  適当なパケットを選択して、Follow SSL Stream  Packet BytesのDecrypted SSL dataタブ等  鍵交換プロトコルがRSAでもECDHE(Perfect Forward Secrecy)でも復号可能  PFSだとサーバのSSL秘密鍵を持っていても復号できない 54
  • 55. SSLKEYLOGFILEフォーマット  CLIENT_RANDOM <space> <64 bytes of hex encoded client_random> <space> <96 bytes of hex encoded master secret>  RSA <space> <16 bytes of hex encoded encrypted pre master secret> <space> <96 bytes of hex encoded pre master secret> 55
  • 56. 使用ブラウザの制限  SSLKEYLOGFILE環境変数を見てログファイルを作る のは、NSS(Network Security Services)ライブラリであ るため、同様の手順が取れるのは同ライブラリを使用 するブラウザ、ツールのみ。  NSSを使用する主なブラウザは、Firefox, PC版 Chrome(Win/Mac/Linux版含む)のみ。  Android版ChromeはOpenSSLを使用  PC版ChromeもBoringSSLを使い始めた場合は使えなくない  他のブラウザの場合はメモリダンプするくらいしか手が ないんじゃ…。 56
  • 57. 参考  pyreshark  https://github.com/ashdnazg/pyreshark  Psst. Your Browser Knows All Your Secrets.  https://isc.sans.edu/diary/Psst.+Your+Browser+Knows+All+Your+Secrets./16415  NSS Key Log Format  https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format  Chrome: From NSS to OpenSSL  https://docs.google.com/document/d/1ML11ZyyMpnAr6clIAwWrXD53pQgNR-DppMYwt9XvE6s/ edit?pli=1#heading=h.n30fi956cpfk  SSL/TLS & Perfect Forward Secrecy  http://vincent.bernat.im/en/blog/2011-ssl-perfect-forward-secrecy.html  ディフィー・ヘルマン鍵共有  http://ja.wikipedia.org/wiki/%E3%83%87%E3%82%A3%E3%83%95%E3%82%A3%E3%83%BC %E3%83%BB%E3%83%98%E3%83%AB%E3%83%9E%E3%83%B3%E9%8D%B5%E5%85%B 1%E6%9C%89  Diffie–Hellman key exchange  http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange 57
  • 58. 58 Q & A