Linuxの指紋
dual display
前回の妄想、NotePCの外部Displayに、巨大なTVを使えないか? ターゲットがWindows10なら、HDMIなケーブルを買ってくれば、ちょちょいのちょい で行くはず。TV側の扱いは、シャープ方面に詳しい取扱説明書が有ったので、読んでみた。
うるさく言ってたのは、認証が通ったちゃんとしたケーブルを使えって事。安いケーブルだと、画像がボケたり、場合によっては映らない事があるとな。4Kな画像を映そうとすると、帯域が16Gも必要とか。
そんな訳なんで、100均には影も形もなかったよ。何も知らない素人が買ってって、映らない、ケーブル壊れてると、クレームされるのが恐いんで、置くのを自粛したんだろう?
さて、ケーブルはどこに? ちゃんとした家電量販店なら置いてあるのは分かってるけど、ホームセンターにも有るかな? まて、ブルーレイCDに繋ぐには繋がりで、レンタルCD屋にもありそうだな。散歩の方向を変えて、偵察してくるか。日経Linux買いますか?HDMIケーブル買いますかだな。
で、Windows10方面はいいんだけど、リナ方面はどうなってる? Windows7改めDebian(32)なマシンも有るからなあ。少し事情を調べておくか。
debian:tmp$ xrandr Screen 0: minimum 320 x 200, current 1366 x 768, maximum 8192 x 8192 LVDS-1 connected primary 1366x768+0+0 (normal left inverted right x axis y axis) 345mm x 194mm 1366x768 59.97*+ 50.00 1360x768 59.80 59.96 : 320x180 59.84 59.32 VGA-1 disconnected (normal left inverted right x axis y axis) HDMI-1 disconnected (normal left inverted right x axis y axis) DP-1 disconnected (normal left inverted right x axis y axis) DP-2 disconnected (normal left inverted right x axis y axis)
ThinkPad SL510 には、こんなに映像系が用意されてるの?
gui版のツール lxrandr が、既に入っていたよ。 Windows + 17 Display's なんて言う、楽しい事をやった人を発見。尊敬しますよ。
tcpdump file
前回はtcpdumpをgdb観光した。ソースをざっと辿ってみると、tcpdumpって、ご本尊がlibpcapで、それを操るshellみたいな物っていう風に感じた。tcpdumpは、パケットの録音と再生装置。CUIで見せてくれるのがtcpdumpで、GUIで見せてくれるのがwiresharkだ。
録音したデータは、共通規格なんで、どこでも使える。
debian:tmp$ file OBLOG OBLOG: pcap capture file, microsecond ts (little-endian) - version 2.4 (Ethernet, capture length 262144)
vbox$ file OBLOG OBLOG: tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 262144)
VMwareのネットに繋がってるOpenBSDからDebinaに向かってsshした時の、取っ掛かりをDebian側で録音したもの。同一ログをOpenBSD側で確認すると、tcpdumpが生成したと言ってきた。
このファイルの構造ってどうなってるのだろうか? そんなのlibpcapのソース嫁。じゃ、あんまりなので、リバースエンジニアリングぽい事をしてみるか。
vbox$ grep tcpdump /etc/magic # (We call them "tcpdump capture file(s)" for now, as "tcpdump" is 0 ubelong 0xa1b2c3d4 tcpdump capture file (big-endian) 0 ulelong 0xa1b2c3d4 tcpdump capture file (little-endian)
まずは、fileコマンドが使っているデータベースを検索。あれ? シグネチャーが同一じゃんと一瞬思っちゃったけど、型を見ると、ubelongとulelongの違いが有る。ストリーム表現した時に、並びが違うから、判定出来るよとな。それにしても、何の捻りも無いシグネチャーだな。zip('abcd', '1234') とわね。
vbox$ hexdump OBLOG | head -2 0000000 c3d4 a1b2 0002 0004 0000 0000 0000 0000 0000010 0000 0004 0001 0000 aae5 60bd 59aa 0009
little-endianってdumpした時、素直に読めないから嫌いだぞ >Intel
次に2、4とかはバージョン番号だろう(多分)。後、fileコマンドで、caputure length 262144なんてのが有る。これもヘッダーに埋め込まれいるんだろう。262144ってHexにすると幾つになる?
vbox$ gdb -q (gdb) p/x 262144 $1 = 0x40000
これも、それっぽいのが、dump結果の2行目に表われていますなあ。後はソース嫁。この場合、tcpdumpのそれを見ても、見つからないはず。libpcapを見れ。
libpcap/pcap.h
/* * The first record in the file contains saved values for some * of the flags used in the printout phases of tcpdump. * Many fields here are 32 bit ints so compilers won't insert unwanted * padding; these files need to be interchangeable across architectures. */ struct pcap_file_header { bpf_u_int32 magic; u_short version_major; u_short version_minor; bpf_int32 thiszone; /* gmt to local correction */ bpf_u_int32 sigfigs; /* accuracy of timestamps */ bpf_u_int32 snaplen; /* max length saved portion of each pkt */ bpf_u_int32 linktype; /* data link type (DLT_*) */ };
面倒かけないように32bitのint単位で扱うよとな。
wireshark
外見から分かるのは、上記ぐらいかな。後は懇切丁寧にパケットを分解してくれるwiresharkに登場願おう。データが表示されたら、全部展開しておいて、それをプレーンなテキストとしてファイルに落とせば、レポートが出来上がるよ。
ether frame
Frame 1: 78 bytes on wire (624 bits), 78 bytes captured (624 bits) Encapsulation type: Ethernet (1) Arrival Time: Jun 7, 2021 14:13:09.612778000 JST [Time shift for this packet: 0.000000000 seconds] Epoch Time: 1623042789.612778000 seconds : Ethernet II, Src: Vmware_59:e8:ba (00:0c:29:59:e8:ba), Dst: Vmware_4d:18:2d (00:0c:29:4d:18:2d) Destination: Vmware_4d:18:2d (00:0c:29:4d:18:2d) Source: Vmware_59:e8:ba (00:0c:29:59:e8:ba) Type: IPv4 (0x0800)
Frame 1ってなってる所はwiresharkがまとめてくれたサマリーだ。注目は到着日時。それとepochにした時間。おっと、epochを人間が分かる日に直してる。
vbox$ gdb -q (gdb) p/x 1623042789 $1 = 0x60bdaae5 (gdb) q vbox$ hexdump OBLOG | grep 60bd 0000010 0000 0004 0001 0000 aae5 60bd 59aa 0009 0000070 4811 0000 0000 aae5 60bd 59be 0009 004a
packet毎に、到着日時を記録してるんだな。まあ、logですから。 次は、 イーサネットフレームだな。
MacAddressと下位のプロトコル(IPv4)を指定してる。MacAddressは、ベンダーがVmwareってちゃんと知ってるよ。VMwarePlayerのconfigファイル、OpenBSD.vmxに当てってみると
ethernet0.connectionType = "nat" ethernet0.virtualDev = "e1000" ethernet0.generatedAddress = "00:0c:29:59:e8:ba"
MACaddressって、偽装が簡単だな。ルーターで、MACアドレスでフィルタリングするのは、気休めか。
IP header
次は、 IPv4 だな。注目は
Differentiated Services Field: 0x48 (DSCP: AF21, ECN: Not-ECT) Flags: 0x4000, Don't fragment Fragment offset: 0 Time to live: 64 Protocol: TCP (6)
フラグメントしないでね。64回ルーターを通ったら消滅してね。更に荷物があるけど、それはTCPだからね。
TCP header
最後は、 Transmission Control Protocol
1011 .... = Header Length: 44 bytes (11) Flags: 0x002 (SYN) Window size value: 16384 : Options: (24 bytes), Maximum segment size, No-Operation (NOP), No-Operation (NOP), SACK permitted, No-Operation (NOP), Window scale, No-Operation (NOP), No-Operation (NOP), Timestamps TCP Option - Maximum segment size: 1460 bytes TCP Option - No-Operation (NOP) TCP Option - No-Operation (NOP) TCP Option - SACK permitted TCP Option - No-Operation (NOP) TCP Option - Window scale: 6 (multiply by 64) TCP Option - No-Operation (NOP) TCP Option - No-Operation (NOP) TCP Option - Timestamps: TSval 2780959048, TSecr 0 Kind: Time Stamp Option (8) Length: 10 Timestamp value: 2780959048 Timestamp echo reply: 0 [Timestamps] [Time since first frame in this TCP stream: 0.000000000 seconds] [Time since previous frame in this TCP stream: 0.000000000 seconds]
tcpdumpでは、下記のように表示したよ。
vbox$ tcpdump -tt -r OBLOG tcpdump: WARNING: snaplen raised from 116 to 262144 1623042789.612778 aa.bb.cc.128.33778 > aa.bb.cc.129.ssh: S 2874817133:2874817133(0) win 16384 \ <mss 1460,nop,nop,sackOK,nop,wscale 6,nop,nop,timestamp 2780959048 0> (DF) [tos 0x48]
tcpdump by gdb
OpenBSDがデフォで用意してるtcpdumpはgdbから正しく機能しなかった(応答が無くなる)。普通のtcpdumpはどうかと試してみる。
(gdb) bt : #8 0x140a7d74 in print_packet (user=0xcf7f9b18 "", h=0xcf7f9968, sp=0x5acda002\ "") at ./tcpdump.c:3075 #9 0x059c0907 in pcap_offline_read (p=0x4641ea00, cnt=-1, callback=0x140a7d00 \ <print_packet>, user=0xcf7f9b18 "") at /usr/src/lib/libpcap/savefile.c:336 #10 0x059a7911 in pcap_loop (p=0x4641ea00, cnt=-1, callback=0x140a7d00 <print_p\ acket>, user=0xcf7f9b18 "") at /usr/src/lib/libpcap/pcap.c:69 #11 0x140a5175 in main (argc=3, argv=0xcf7fa134) at ./tcpdump.c:2524
こんな具合にちゃんと動いているな。 色々ggしてみたが、手がかり無し。
tcpdump -o
あちこにに手を出してしまったけど、OpenBSDのtcpdumpに組み込まれている、OSの推測方法を探ってみる。前回目星を付けておいた。
print-tcp.p
/* OS Fingerprint */ : head = pf_osfp_fingerprint_hdr(ip, ip6, tp); if (head) { int prev = 0; printf(" (src OS:");
指紋の鑑定は、 pf_osfp_fingerprint_hdr
で、やっているみたいだ。Makefileを見ると
# TCP OS Fingerprinting .PATH: ${.CURDIR}/../../sys/net .PATH: ${.CURDIR}/../../sbin/pfctl SRCS+= pf_osfp.c pfctl_osfp.c
こんな風に、部外者を招聘してる。何とKernelで使われているネット関係のエリアになるやつだ。カーネル側のコードとユーザーランド側と混在してて、使い分けている。
struct pf_osfp_enlist * pf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcp) : if ((fpresult = pf_osfp_find(&pf_osfp_list, &fp, PF_OSFP_MAXTTL_OFFSET))) return (&fpresult->fp_oses); return (NULL); }
この関数の中で、渡されて来たパケットデータから分析に必要な部分を取り出して、fpにまとめる。 pf_osfp_list
の方は、台帳だ。一致してたら、それを返すって事だ。
pfctl_osfp.c
には、/etc/pf.osを読み込むルーチンが置いてあるなあ。
pfctl_file_fingerprints(int dev, int opts, const char *fp_filename) : if (GET_INT(window, &w_mod, "window size", T_DC|T_MSS|T_MTU| T_MOD, 0xffff) || GET_INT(ttl, NULL, "ttl", 0, 0xff) || GET_INT(df, NULL, "don't fragment frag", 0, 1) || GET_INT(psize, &p_mod, "overall packet size", T_MOD|T_DC, 8192) || GET_STR(tcpopts, "TCP Options", 1) || GET_STR(class, "OS class", 1) || GET_STR(version, "OS version", 0) || GET_STR(subtype, "OS subtype", 0) || GET_STR(desc, "OS description", 2))
こんな風に読み込んで、検索に都合のよい形に変形してる。
pf.os(5)
# tcpdump -s128 -c1 -nv 'tcp[13] == 2' 03:13:48.118526 10.0.0.1.3377 > 10.0.0.2.80: S [tcp sum ok] \ 534596083:534596083(0) win 57344 <mss 1460> (DF) [tos 0x10] \ (ttl 64, id 11315, len 44) almost translates into the following fingerprint 57344:64:1:44:M1460: exampleOS:1.0::exampleOS 1.0
これ、指紋台帳への登録方法。基本の貴だ。これだけでは、心元ないので、tcpoptsで詳細を追加しとけ。例が、pf.osの現場に載ってた。
linuxの指紋
ここまで分かれば、OS推測用のデータベース /etc/pf.os を更新するのは容易であろう。以前録音、じゃなくて録パケットしたログから、必要な情報を炙り出してみる。最初はOpenBSD用ね。
ob$ tcpdump -t -v -r OBLOG tcpdump: WARNING: snaplen raised from 116 to 262144 aa.bb.cc.128.33778 > aa.bb.cc.129.ssh: S [tcp sum ok] 2874817133:2874817133(0) win 16384 <mss 1460,nop,nop,sackOK,nop,wscale 6,nop,nop,timestamp 2780959048 0> (DF) [tos 0x48] (ttl 64, id 17994, len 64)
このデータを登録しればいいんだけど、先客に
16384:64:1:64:M*,N,N,S,N,W6,N,N,T: OpenBSD:6.1::OpenBSD 6.1
こんなのが居る。翻訳結果も同様になった(と言う事は、6.1の頃から全く代わりが無いと言う事だ)。tcpoptionsのmssが、どうでもいいよってなってるけど、そこを無理して現在の数値1460に設定してみるか。
マッチは、最初から見ていくので、少なくとも、上記のデータよりも手前の方に書いておく必要が有る。
16384:64:1:64:M1460,N,N,S,N,W6,N,N,T: OpenBSD:6.9::OpenBSD 6.9
ob$ tcpdump -t -o -r OBLOG tcpdump: WARNING: snaplen raised from 116 to 262144 aa.bb.cc.128.33778 > aa.bb.cc.129.ssh: S (src OS: OpenBSD 6.9) 2874817133:2874817133(0) win 16384 <mss 1460,nop,nop,sackOK,nop,wscale 6,nop,nop,timestamp 2780959048 0> (DF) [tos 0x48]
成功した。じゃ、いよいよlinuxからのパケットの収録をする。ターゲットの素性は、こんな奴だった。この情報、台帳登録時に必要になるからね。
sakae@pen:~$ uname -a Linux pen 4.19.0-16-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64 GNU/Linux
録パケ開始。sshでOpenBSDにlogin。指紋を採取された事を知らない、哀れなLinux
ob# tcpdump -s128 -w LINLOG 'tcp[13] == 2' tcpdump: listening on em0, link-type EN10MB ^C 169 packets received by filter 0 packets dropped by kernel
ちゃんとget出来たか、再生してみる。
ob$ tcpdump -r LINLOG -v -t -o tcpdump: WARNING: snaplen raised from 116 to 128 aa.bb.cc.129.53392 > aa.bb.cc.128.ssh: S [tcp sum ok] (src OS: unknown) 4214038903:4214038903(0) win 64240 <mss 1460,sackOK,timestamp 3988811210 0,nop,wscale 7> (DF) (ttl 64, id 32018, len 60)
そして、登録情報
64240:64:1:60:M1460,S,T,N,W7: Linux:4.19::Linux 4.19(debian)
検証大事大事だよ
ob$ tcpdump -r LINLOG -t -o tcpdump: WARNING: snaplen raised from 116 to 128 aa.bb.cc.129.53392 > aa.bb.cc.128.ssh: S (src OS: Linux 4.19) 4214038903:4214038903(0) win 64240 <mss 1460,sackOK,timestamp 3988811210 0,nop,wscale 7> (DF)
これで、嘘は付けないぞ。なんてのは、裏側を知らない人。簡単にサツの裏をかけるぞ。例えば、IP Headerの中に埋め込まれているTTLが指紋の一部として採用されてる。
ob$ sysctl -a | grep ttl net.inet.ip.ttl=64 :
sysctlを使って簡単に変更出来ちゃうからね。OpenBSDでは64だけど、Windowsなんてのは太っ腹に128に設定されてる。
また、ルーターを渡り歩いて来るパケットは、ルーター色にパケットが変色しちゃうんで、この機構の使い所は限定されてしまうぞ。
何か良いアイデアが有ったら、 p0f v3 (version 3.09b) に、コンタクトをお願い致します。