SlideShare una empresa de Scribd logo
1 de 58
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

Más contenido relacionado

La actualidad más candente

Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Akihiro Suda
 
本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話Kumazaki Hiroki
 
ネットワーク ゲームにおけるTCPとUDPの使い分け
ネットワーク ゲームにおけるTCPとUDPの使い分けネットワーク ゲームにおけるTCPとUDPの使い分け
ネットワーク ゲームにおけるTCPとUDPの使い分けモノビット エンジン
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」Takuto Wada
 
Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門Etsuji Nakai
 
40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていること40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていることonozaty
 
コンテナの作り方「Dockerは裏方で何をしているのか?」
コンテナの作り方「Dockerは裏方で何をしているのか?」コンテナの作り方「Dockerは裏方で何をしているのか?」
コンテナの作り方「Dockerは裏方で何をしているのか?」Masahito Zembutsu
 
CyberChefの使い方(HamaCTF2019 WriteUp編)
CyberChefの使い方(HamaCTF2019 WriteUp編)CyberChefの使い方(HamaCTF2019 WriteUp編)
CyberChefの使い方(HamaCTF2019 WriteUp編)Shota Shinogi
 
Scapyで作る・解析するパケット
Scapyで作る・解析するパケットScapyで作る・解析するパケット
Scapyで作る・解析するパケットTakaaki Hoyo
 
DockerコンテナでGitを使う
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使うKazuhiro Suga
 
ネットワークスイッチ構築実践 2.STP・RSTP・PortSecurity・StormControl・SPAN・Stacking編
ネットワークスイッチ構築実践 2.STP・RSTP・PortSecurity・StormControl・SPAN・Stacking編ネットワークスイッチ構築実践 2.STP・RSTP・PortSecurity・StormControl・SPAN・Stacking編
ネットワークスイッチ構築実践 2.STP・RSTP・PortSecurity・StormControl・SPAN・Stacking編株式会社 NTTテクノクロス
 
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)Kuniyasu Suzaki
 
CTF for ビギナーズ ネットワーク講習資料
CTF for ビギナーズ ネットワーク講習資料CTF for ビギナーズ ネットワーク講習資料
CTF for ビギナーズ ネットワーク講習資料SECCON Beginners
 
Protocol Buffers 入門
Protocol Buffers 入門Protocol Buffers 入門
Protocol Buffers 入門Yuichi Ito
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織Takafumi ONAKA
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021Hiroshi Tokumaru
 
インターネットの仕組みとISPの構造
インターネットの仕組みとISPの構造インターネットの仕組みとISPの構造
インターネットの仕組みとISPの構造Taiji Tsuchiya
 
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)Hironobu Suzuki
 
MCC CTF講習会 pwn編
MCC CTF講習会 pwn編MCC CTF講習会 pwn編
MCC CTF講習会 pwn編hama7230
 

La actualidad más candente (20)

Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
 
本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話本当は恐ろしい分散システムの話
本当は恐ろしい分散システムの話
 
ネットワーク ゲームにおけるTCPとUDPの使い分け
ネットワーク ゲームにおけるTCPとUDPの使い分けネットワーク ゲームにおけるTCPとUDPの使い分け
ネットワーク ゲームにおけるTCPとUDPの使い分け
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門
 
40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていること40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていること
 
コンテナの作り方「Dockerは裏方で何をしているのか?」
コンテナの作り方「Dockerは裏方で何をしているのか?」コンテナの作り方「Dockerは裏方で何をしているのか?」
コンテナの作り方「Dockerは裏方で何をしているのか?」
 
CyberChefの使い方(HamaCTF2019 WriteUp編)
CyberChefの使い方(HamaCTF2019 WriteUp編)CyberChefの使い方(HamaCTF2019 WriteUp編)
CyberChefの使い方(HamaCTF2019 WriteUp編)
 
Scapyで作る・解析するパケット
Scapyで作る・解析するパケットScapyで作る・解析するパケット
Scapyで作る・解析するパケット
 
DockerコンテナでGitを使う
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使う
 
Gstreamer Basics
Gstreamer BasicsGstreamer Basics
Gstreamer Basics
 
ネットワークスイッチ構築実践 2.STP・RSTP・PortSecurity・StormControl・SPAN・Stacking編
ネットワークスイッチ構築実践 2.STP・RSTP・PortSecurity・StormControl・SPAN・Stacking編ネットワークスイッチ構築実践 2.STP・RSTP・PortSecurity・StormControl・SPAN・Stacking編
ネットワークスイッチ構築実践 2.STP・RSTP・PortSecurity・StormControl・SPAN・Stacking編
 
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
 
CTF for ビギナーズ ネットワーク講習資料
CTF for ビギナーズ ネットワーク講習資料CTF for ビギナーズ ネットワーク講習資料
CTF for ビギナーズ ネットワーク講習資料
 
Protocol Buffers 入門
Protocol Buffers 入門Protocol Buffers 入門
Protocol Buffers 入門
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
 
SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021SPAセキュリティ入門~PHP Conference Japan 2021
SPAセキュリティ入門~PHP Conference Japan 2021
 
インターネットの仕組みとISPの構造
インターネットの仕組みとISPの構造インターネットの仕組みとISPの構造
インターネットの仕組みとISPの構造
 
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
 
MCC CTF講習会 pwn編
MCC CTF講習会 pwn編MCC CTF講習会 pwn編
MCC CTF講習会 pwn編
 

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

Hokkaido.cap#2 一般的なプロトコルのパケットを覗いてみよう
Hokkaido.cap#2 一般的なプロトコルのパケットを覗いてみようHokkaido.cap#2 一般的なプロトコルのパケットを覗いてみよう
Hokkaido.cap#2 一般的なプロトコルのパケットを覗いてみようPanda Yamaki
 
Hokkaido.cap #osc11do Wiresharkを使いこなそう!
Hokkaido.cap #osc11do Wiresharkを使いこなそう!Hokkaido.cap #osc11do Wiresharkを使いこなそう!
Hokkaido.cap #osc11do Wiresharkを使いこなそう!Panda Yamaki
 
Windowsのパケットモニタ作成
Windowsのパケットモニタ作成Windowsのパケットモニタ作成
Windowsのパケットモニタ作成Shinichi Hirauchi
 
Apache Camel Netty component
Apache Camel Netty componentApache Camel Netty component
Apache Camel Netty componentssogabe
 
Hokkaido.cap#1 Wiresharkの使い方(基礎編)
Hokkaido.cap#1 Wiresharkの使い方(基礎編)Hokkaido.cap#1 Wiresharkの使い方(基礎編)
Hokkaido.cap#1 Wiresharkの使い方(基礎編)Panda Yamaki
 
debugging server with strace
debugging server with stracedebugging server with strace
debugging server with straceYoshinari Takaoka
 
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」
[TL06] 日本の第一人者が C# の現状と今後を徹底解説! 「この素晴らしい C# に祝福を!」de:code 2017
 
システムパフォーマンス勉強会#8
システムパフォーマンス勉強会#8システムパフォーマンス勉強会#8
システムパフォーマンス勉強会#8shingo suzuki
 
Trema day 1
Trema day 1Trema day 1
Trema day 1ykuga
 
FD.io VPP事始め
FD.io VPP事始めFD.io VPP事始め
FD.io VPP事始めtetsusat
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。Kazuki Onishi
 
Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)Polyphony の行く末(2018/3/3)
Polyphony の行く末(2018/3/3)ryos36
 
RouterBOARD with OpenFlow
RouterBOARD with OpenFlowRouterBOARD with OpenFlow
RouterBOARD with OpenFlowToshiki Tsuboi
 
VPP事始め
VPP事始めVPP事始め
VPP事始めnpsg
 
実践 WebRTC 〜最新事例と開発ノウハウの紹介〜
実践 WebRTC 〜最新事例と開発ノウハウの紹介〜実践 WebRTC 〜最新事例と開発ノウハウの紹介〜
実践 WebRTC 〜最新事例と開発ノウハウの紹介〜Yusuke Naka
 

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

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

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