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
外部キー制約に伴うロックの小話
PDF
例外設計における大罪
PDF
macOSの仮想化技術について ~Virtualization-rs Rust bindings for virtualization.framework ~
PPTX
非同期処理の基礎
PDF
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
PPTX
分散システムについて語らせてくれ
PPT
Glibc malloc internal
PDF
Hokkaido.cap #osc11do Wiresharkを使いこなそう!
外部キー制約に伴うロックの小話
例外設計における大罪
macOSの仮想化技術について ~Virtualization-rs Rust bindings for virtualization.framework ~
非同期処理の基礎
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
分散システムについて語らせてくれ
Glibc malloc internal
Hokkaido.cap #osc11do Wiresharkを使いこなそう!

What's hot (20)

PDF
Form認証で学ぶSpring Security入門
PDF
ELFの動的リンク
PDF
テスト文字列に「うんこ」と入れるな
PPTX
GraphQLのsubscriptionで出来ること
PPTX
C#で速度を極めるいろは
PDF
コンテナの作り方「Dockerは裏方で何をしているのか?」
PDF
目grep入門 +解説
PDF
ARM Trusted FirmwareのBL31を単体で使う!
PDF
いつやるの?Git入門 v1.1.0
PDF
Constexpr 中3女子テクニック
PDF
LLVM最適化のこつ
PDF
できる!並列・並行プログラミング
PDF
ソーシャルゲームのためのデータベース設計
PDF
Goでかんたんソースコードの静的解析
PDF
Pythonによる黒魔術入門
PDF
C/C++プログラマのための開発ツール
PDF
明日使えないすごいビット演算
PPTX
「ネットワーク超入門 IPsec VPN編」
PDF
ARM CPUにおけるSIMDを用いた高速計算入門
PDF
TCAMのしくみ
Form認証で学ぶSpring Security入門
ELFの動的リンク
テスト文字列に「うんこ」と入れるな
GraphQLのsubscriptionで出来ること
C#で速度を極めるいろは
コンテナの作り方「Dockerは裏方で何をしているのか?」
目grep入門 +解説
ARM Trusted FirmwareのBL31を単体で使う!
いつやるの?Git入門 v1.1.0
Constexpr 中3女子テクニック
LLVM最適化のこつ
できる!並列・並行プログラミング
ソーシャルゲームのためのデータベース設計
Goでかんたんソースコードの静的解析
Pythonによる黒魔術入門
C/C++プログラマのための開発ツール
明日使えないすごいビット演算
「ネットワーク超入門 IPsec VPN編」
ARM CPUにおけるSIMDを用いた高速計算入門
TCAMのしくみ
Ad

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

PDF
Hokkaido.cap#2 一般的なプロトコルのパケットを覗いてみよう
PDF
Windowsのパケットモニタ作成
PPTX
Apache Camel Netty component
PDF
Hokkaido.cap#1 Wiresharkの使い方(基礎編)
PDF
debugging server with strace
PDF
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
PPTX
システムパフォーマンス勉強会#8
PDF
Trema day 1
PPTX
Prosym2012
PPTX
FD.io VPP事始め
PDF
ラズパイでデバイスドライバを作ってみた。
PDF
Boost Tour 1.50.0 All
PPTX
Polyphony の行く末(2018/3/3)
KEY
P2Pって何?
PDF
RouterBOARD with OpenFlow
PDF
Scapy presentation
PPTX
VPP事始め
PDF
Inside winnyp
PDF
実践 WebRTC 〜最新事例と開発ノウハウの紹介〜
PDF
Netty & Apache Camel
Hokkaido.cap#2 一般的なプロトコルのパケットを覗いてみよう
Windowsのパケットモニタ作成
Apache Camel Netty component
Hokkaido.cap#1 Wiresharkの使い方(基礎編)
debugging server with strace
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
システムパフォーマンス勉強会#8
Trema day 1
Prosym2012
FD.io VPP事始め
ラズパイでデバイスドライバを作ってみた。
Boost Tour 1.50.0 All
Polyphony の行く末(2018/3/3)
P2Pって何?
RouterBOARD with OpenFlow
Scapy presentation
VPP事始め
Inside winnyp
実践 WebRTC 〜最新事例と開発ノウハウの紹介〜
Netty & Apache Camel
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