2024/09/13
well-known portをキャプチャしてみよう
目的
- ネットワークに関して理解を深める。
- 目的に応じたプロトコルがあることを認識する。
- 普段見えないパケットを可視化して、順序やプロトコルフォーマットを認識する。
- トラブルシューティングに使える手段を手に入れる。
想定状況
- WindowsやLinuxを利用したことはあるがネットワークに苦手意識がある。
- pingを使ったことはあるが仕組みを見たことはない。
- プロトコルとかいっぱいありすぎて分からん。
概要
WindowsやLinuxでウェルノウンポートをいくつかキャプチャして、wiresharkで見てみましょう。
Windowsもキャプチャなら標準でできるようになったので楽になりましたね。
ウェルノウンポートは分かりやすいまとめを色々な方がされているので都度確認してみてください。
試験環境準備
以前の記事で使った環境を使い回しましょう。
vagrantの説明が必要な場合は以下をご確認ください。
これで、tomcatが動作するcentosにアクセスできるようになっているはずです。
また、キャプチャしたパケットを参照するツールはいくつか選択肢がありますが、ここではデファクトスタンダードと思われるwiresharkを使ってみましょう。
windows updateを実行する。
任意ですが、お作法として記載しておきます。
powershellまたはGUIで、OSに対して更新プログラムを適用しましょう。
chocolateyでWindowsにアプリをインストールする。
公式サイトに従いchocolatey自体をインストールする。
オプションのユーザ登録は不要。
管理者権限PowerShellでワンライナー実行のはず。
chocolatey自体のインストールが終わったら、以下のコマンドでアプリをインストールする。
choco install -y wireshark
因みに、今回はwiresharkは参照機能しか使いません。
上記のように、choco installではキャプチャのための機能がインストールできないようです。
GUIで手動でキャプチャに必要な機能を追加すれば良いので、興味があれば是非やってみてください。
PowerShellは閉じてしまって大丈夫です。
この後色々画面を切り替えますが、それぞれの画面を後で使うので都度閉じなくて大丈夫です。
パケットをキャプチャしてみよう。その1 ping
取り敢えずキャプチャ実施
今、お手元のパソコンでは、ホストOSとしてのWindowsと、ゲストOSとしてのcentosが起動しているはずです。
この二台は通信可能なのでしょうか?
試してみましょう。
説明の前に取り敢えずキャプチャしてみましょう。
Windowsキー+Rで「ファイル名を指定して実行」を起動し、cmdと入力し、Ctrl+Shiftを押しながらエンターを押して、管理者権限でコマンドプロンプトを起動します。
コマンドプロンプト
set T=%time: =0%
set DATETIME=%date:/=%_%T:~0,2%%T:~3,2%%T:~6,2%
where pktmon
pktmon start --capture -f PktMon_%DATETIME%.etl
pktmon status
ping 192.168.55.101
pktmon stop
pktmon etl2pcap PktMon_%DATETIME%.etl
set PATH=%PATH%;"C:\Program Files\Wireshark"
wireshark C:\Windows\System32\PktMon_%DATETIME%.pcapng
思っていたパケットがキャプチャされない時は、フィルタがかかっていないか確認してみましょう。
pktmon filter list
Windows側、centos側それぞれ、IPアドレスは何か?確認する方法は色々ありますが、今回は以下で確認してみましょう。
Windows側
ipconfig | findstr IPv4
centos側
ip a | grep "inet "
また、VagrantfileにてIPアドレスの指定を行っているため、そちらも確認してみましょう。
考え方の整理
さて、上記で取り敢えずはキャプチャしてパケットを可視化してみました。
ここで一旦、キャプチャ結果の確認の前に、pingについて簡単に確認しておきましょう。
やはり、ネットワーク的に通信可能か?という確認をする際、取り敢えずpingを打ってみる、ということは多いのではないでしょうか?これは、トラブルシューティングの考え方としては分割統治と言って、物事を切り分けて管理しやすくする、という感じのやり方と思ってください。
ここでの問題とは何でしょうか?
- 問題:ネットワーク的に繋がっているか不明。
- 対象:ホストOSとゲストOS。
- 調査:pingによる分割統治。
トラブルシューティングのまとまった考え方は、セキュリティやデータベースなど、色々な分野でのまとめがあるので、色々確認してみてください。
ここでは特に、ネットワークに関してのトラブルシューティングですね。
問題を分割する対象は「ホストOSとゲストOS」、となっていますが、もう少し細かくしていくと、ネットワークの階層の考え方、プロトコルスイートとか、プロトコルスタックとかいう考え方が出てきます。「物理的なLANケーブル、macアドレス、IPアドレス、TCPポート、アプリごとのプロトコル」といった5層を思い浮かべてもらえれば良いかと思います。
他にも色々ありますが、先ずは一旦この5層から考えていきましょう。
「pingを打つ」というのが、問題をどう分割してくれるのでしょうか?
端的な答えを先に書いておくと、レイヤーで分割し、どこかまではOK!と分かる、、、かも知れない、という感じです。
pingの利用プロトコル
pingを実行した際に、内部的にはicmpというプロトコルが利用されています。
ICMP ( Internet Control Message Protocol )
Echo or Echo Reply Message
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data ...
+-+-+-+-+-
プロトコルはこういった感じでフォーマットが定義されているはずなので、取り敢えずは頭文字と、正式名称と、フォーマットをざっと見るようにしていってみましょう。
RFCという、プロトコルの定義ドキュメントを引用しています。何か新しいプロトコルに出会ったら、色々な方の解説の確認と並行して、定義そのものにも目を通してみましょう。
さて、ping、詰まりはicmpですが、TCP/UDPのウェルノウンポートのどれを使っているのでしょうか?
答えは、「使っていない」となります。
「ウェルノウンポートをキャプチャ」と言いながら、先ずicmpという、TCPもUDPも使っていないものから紹介している訳です。酷いですね。
これはどういうことかというと、icmpというプロトコルが、TCPレイヤーを利用するプロトコルではない、IPレイヤーのプロトコルである、ということになります。
正確には3.5なのかとかあるかもですが、一旦概要の理解を目指して進めます。
IPアドレスというのは、聞いたことがあるかと思います。これがネットワークの階層構造の考え方、レイヤーで言えば3層目、L3とも呼ばれます。L3スイッチとかのL3と同じです。
L3としてのアドレスで、目的地にL3としてのパケットが届くか?帰ってくるか?
これを、icmpでは、Echo or Echo Reply Messageというフォーマットで定めており、pingというアプリは、引数に相手先のIPアドレスを渡すと、そこに向かってicmpのエコーを投げてくれる、ということなのですね。そして、相手のOSがicmpを理解できて、Echo Replyのパケットを返すことができれば、pingのアプリとしては、「パケット帰ってきたよ!」という報告をくれる、という感じですね。
「ping」とは、潜水艦で、アクティブソナーとかパッシブソナーとか、何か兵器的な話の機能に似ているということで、「そこに誰かいますか?」というアプリの名前に使ったという感じらしいです。
ping利用時の期待値
pingは万能なのかというと、そういうことはありません。
ここで分割統治に話が戻ってくるのですが、「ping応答があった」ならば、「そのIPアドレスの誰かとは、L3までは繋がっていると言える」ということが分かるのです。なので、例えばその誰かとメールができないとか、メッセージのやり取りができない、ということなら、TCPポート間違ってないか、セキュリティ的に拒否してないか、メールアドレス間違ってないか?とか、L4以上に問題があると切り分けれる、ことになります。
では逆に、pingが通らなければ、必ずLANケーブルとかに問題があると、L3以下の問題と言えるのでしょうか?
答えとしてはNoで、セキュリティ的に、「icmpに応答しない」という設定もあり得る為です。そしてicmpについて制限をしているのが、相手の端末なのか、経路上のネットワーク機器なのか、この段階では判別できません。
よって、pingを打つ時は、期待値として、「応答あればL3疎通は確認できる」「応答なければレイヤー切り分け継続」ということになるかと思います。
ですので、「何かネットワーク繋がらないっぽいから取り敢えずping打つ」は、分割統治の期待値持って行えば、トラブルシューティングの手法にかなった動きと言えると思います。
問題は、期待値を持たず、脊髄反射でpingを打って、、、、、で、その次どうすれば良いんだ?これで何が分かったんだ?、、、と止まってしまうことかなと思います。
「ネットワーク」というものは、ノードとリンク、詰まり、パソコンやサーバ、ネットワーク機器などと、それらを繋ぐ有線なり無線なりのメディア、媒介で成り立つもの、ということなので、問題が起こった場合には、先ずは登場人物を挙げて、その関係を図にする
というアプローチが効果的だと思います。
調査を一緒に行う関係者の認識の統一にもなりますし、自分一人で対処している
場合でも、見落としや勘違いに気付く契機になるかも知れません。
また、ネットワークは階層構造となっていると説明しました。
Requirements for Internet Hosts -- Communication Layers
This RFC covers the communications protocol layers: link layer, IP layer, and transport layer; its companion RFC-1123 covers the application and support protocols.
1.1.3 Internet Protocol Suite
- Application Layer
- Telnet (remote login)
- FTP (file transfer)
- SMTP (electronic mail delivery)
- Transport Layer
- Transmission Control Protocol (TCP)
- User Datagram Protocol (UDP)
- Internet Layer
- IP
- ICMP
- IGMP
- Link Layer
これまたプロトコルの定義に関するドキュメントに階層構造の考え方が書かれています。よって、問題を整理する際に、今回利用しているプロトコルは何である、どことどこは何のプロトコルを利用しているのか、可視化することも重要になるはずです。
こういった、分解する為の考え方があって初めて、「ネットワークにおいて起こっている問題」を細かめに定義することができて、調査に関しても、問題に応じた切り分けの手段を検討、実行することができる、という感じだと思います。闇雲に知っているコマンドを乱射する、というのは、調査とは言いにくいものである、と指摘される可能性がある、という感じです。期待値を持ち、このコマンドの実行で、問題がどう切り分けられるのか?考えてから、整理してから進むようにしていきましょう。その為にも、体系的な理解に向けて、継続的に座学、実機検証を行って行きましょう。
今回は、pingというアプリ、コマンドで、L3のプロトコルであるicmpを利用して、上記のキャプチャでは無事にエコーに応答があった、詰まり、L3としては疎通できていることを確認できました。
でも、もしその次に、「tomcatがいるということですが、そこと通信できない」という問題の報告があった場合、どういった手段で、何を切り分けていけるでしょうか?
改めてキャプチャ結果を確認
- pingの中身はicmpというプロトコル
- icmpはTCPレイヤー無い為ポートなし
- トラブルシューティングは計画的に
という感じの話でした。
では改めて、キャプチャ結果を見てみましょう。ウェルノウンポートがなくても、wiresharkでのパケットの見方を確認してみます。
wiresharkの画面の見方は色々な方が文章や動画で説明してくれていますので、分からない場合は調べてみてください。
表形式で、色がついているのがパケットの行ったり来たりしている流れで、画面下の方は選択したパケットの内容を見せてくれています。
例えば画面では、No42をクリックした状態で、「Internet Control Message Protocol」とあり、Typeが「8」であるということが示されているようです。
主な列の概説は以下の通りです。
- No キャプチャしたパケットの通番です。
- Time wiresharkの設定次第で、キャプチャ開始からの経過時間か、時計で何時何分何秒だったか切替可能です。
- Source どのIPアドレスからパケットが送信されたかを示しています。
- Destination どのIPアドレスへのパケットかを示しています。
- Protocol wiresharkが理解可能であればプロトコル名が表示されます。
pingは、パケットとしては、リクエストして、レスポンスがある、1対1で終わるものなので、その会話を見つけたいという場合は、wiresharkの「対話フィルタ」という機能を利用してみましょう。
会話を見たいパケットを右クリックして、対話フィルタ>IPv4を選んでみましょう。
画面上の方で、フィルタを設定してくれたのが分かるでしょうか?
この場合、SourceかDestinationのIPアドレスをフィルタとして指定してくれているみたいです。画面が見やすくなったかなと思います。
ICMP ( Internet Control Message Protocol )
Type
8 for echo message;
0 for echo reply message.
例えば、パケットのうち、icmpの一つ目のフィールドは、8であればエコーで、0であればエコーへの応答ということのようです。
確かに、No43のパケットを見てみると、ちゃんと0になっていますね。
これでicmpの中身を見ていくことはできそうだと思えたかなと思います。
画面について他にも見てみると、icmpの上に、三角形の折り畳みが3つあります。
- フレーム
- イーサネット2
- インターネットプロトコルv4
ということですが、これがicmpの利用している各レイヤーのプロトコルとなります。
- 第1層 フレーム
- 第2層 イーサネット
- 第3層 インターネットプロトコル
ということで、「プロトコルスイート」とか「プロンプトスタック」とか言われる、とちらっと書いたのですが、積み重ねて使うもので、層ごとに好きなものを使えるよ、という考え方で成り立っています。歴史的に、標準化があってとか、何故こうなのか?という説明は興味あれば是非調べてみてください。
今回はicmpに着目しているので触れませんが、それぞれの層に関してもフォーマットの定義がある為、是非確認してみてください。
Linuxでキャプチャする場合
tcpdumpというコマンドが利用できることが多いはずです。
cmderでcentosにアクセスしてみましょう。
参考にした記事のとおりであれば、以下の場所にVagrantfileがあるはずです。
cmder(Windows上)
cd bashtst
vagrant status
vagrant up
vagrant ssh
こんな感じになっているはずです。
C:\tools\Cmder\bashtst
$ vagrant ssh
This system is built by the Bento project by Chef Software
More information can be found at https://github.com/chef/bento
[vagrant@centosstr9 ~]$
「vagrant@centosstr9」という感じで、centosstr9というゲストOSに、vagrantユーザでログインできたでしょうか?
cmder(centos上)
which tcpdump
結果としてはコマンドがインストールされていないようです。
[vagrant@centosstr9 ~]$ which tcpdump
/usr/bin/which: no tcpdump in (/home/vagrant/.local/bin:/home/vagrant/bin:/root/.local/bin:/root/bin:/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/bin)
[vagrant@centosstr9 ~]$
今回はcentosなので、dnfというコマンドでtcpdumpを追加してみましょう。
sudo dnf install -y tcpdump
インストールできたら、以下でキャプチャを開始してみましょう。
sudo tcpdump -i any -w `date "+%Y%m%d_%H%M%S"`_tcpdump.cap
直ぐにコマンドプロンプトで、pingを実施してみましょう。
コマンドプロンプト
ping 192.168.55.101
pingが終わったら直ぐにcmderに戻って、Ctrl+Cでtcpdumpを停止しましょう。
tcpdumpの結果をwiresharkで見てみたいので、一旦centosからログアウトして、scpでファイルを持ってきましょう。
cmder(centos上)
ls -l
exit
先ず上記でコピー対象ファイル名を確認してcentosからログアウトし、WindowsのVagrantfileがあるフォルダに戻ったはずです。続けて以下を実行します。
cmder(Windows上)
vagrant ssh-config > ssh.config
scp -F ssh.config vagrant@centosstr9:/home/vagrant/\*.cap /tools/Cmder/bashtst/
for /f "usebackq" %A in (`ls -1t ^| head -n 1`) do set tcpdumpcap=%A
set PATH=%PATH%;"C:\Program Files\Wireshark"
wireshark %tcpdumpcap%
Windowsでキャプチャしたのと同じような感じで、ちゃんとやり取りできていることが分かると思います。
pingで応答がなかった場合
では次に、centosからWindowsへpingを飛ばしてみましょう。
期待値はどうでしょうか?普通に応答があることかなと思います。
以前の画面が残っていなければ、Windowsキー+Rで「ファイル名を指定して実行」を起動し、cmdと入力し、Ctrl+Shiftを押しながらエンターを押して、管理者権限でコマンドプロンプトを起動します。残っていればそのまま作業しましょう。
コマンドプロンプト
set T=%time: =0%
set DATETIME=%date:/=%_%T:~0,2%%T:~3,2%%T:~6,2%
pktmon start --capture -f PktMon_%DATETIME%.etl
pktmon status
Windows側のキャプチャ準備が整ったら、cmderを操作して、centosからpingを実施してみましょう。
cmder(Windows上)
cd bashtst
vagrant ssh
centosにログインしたら、以下を実行します。
cmder(centos上)
sudo -i any tcpdump -w `date "+%Y%m%d_%H%M%S"`_tcpdump.cap
cmderをもう一つ画面開きたいので「Ctrl+T > エンター」で新しいタブを開きましょう。再度作業ディレクトリに移動して、centosへログインします。
cmder(Windows上)
cd bashtst
vagrant ssh
centosにログインしたら、以下を実行します。
cmder(centos上)
ping 192.168.55.1 -c 4
pingが終わったら、Ctrl+TABで、cmderのタブをtcpdumpをしている画面に切り替えて、Ctrl+Cでtcpdumpを停止します。
また、ホストOS側でキャプチャをしているコマンドプロンプトの画面については以下を実行して、pktmonでのキャプチャを停止します。
コマンドプロンプト
pktmon stop
pktmon etl2pcap PktMon_%DATETIME%.etl
では、ここまでで、期待通りだったでしょうか?これはお手元のパソコンの状況によって変わってきます。私の手元のパソコンでは、期待に反して、pingは通りませんでした。
[vagrant@centosstr9 ~]$ ping 192.168.55.1 -c 4
PING 192.168.55.1 (192.168.55.1) 56(84) bytes of data.
--- 192.168.55.1 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3162ms
[vagrant@centosstr9 ~]$
こういった場合に、パケットキャプチャが役に立ちます。
先ずはtcpdumpで取得した、pingを投げている側のキャプチャを見てみましょう。
cmder(Windows上)
cd bashtst
scp -F ssh.config vagrant@centosstr9:/home/vagrant/\*.cap /tools/Cmder/bashtst/
for /f "usebackq" %A in (`ls -1t ^| head -n 1`) do set tcpdumpcap=%A
wireshark %tcpdumpcap%
ここから分かることは、centosからpingを投げてはいるが、「no response found!」というInfoからも分かるように、icmpの応答がもらえていないようです。
ではここで、、、、、どうすれば良いんだ?
と止まってしまわないように、ノード、リンク、レイヤーを考えて行きましょう。
宛先のノードではパケットは見えているのでしょうか?確認してみましょう。
管理者権限のコマンドプロンプトに戻ります。
コマンドプロンプト
wireshark C:\Windows\System32\PktMon_%DATETIME%.pcapng
どうでしょうか?ちゃんとパケットは届いていますね!なのに、「no response found!」となっています。Infoで、seqが1から4まであり、それらはtcpdumpの出力の方とも一致していると思います。
なので、ここから分かることは、ホストOS側でicmpの要求は受け取っているのに、リプライをしていない。となります。
ここが、「これはお手元のパソコンの状況によって変わってきます。」とした理由で、今回の私の手元のパソコンの場合は、以下のコマンドで調査し、対処して、状況が変わりました。
管理者権限のコマンドプロンプトに戻ります。
コマンドプロンプト
netsh advfirewall set currentprofile logging filename %systemroot%\system32\LogFiles\Firewall\pfirewall.log
netsh advfirewall set currentprofile logging maxfilesize 4096
netsh advfirewall set currentprofile logging droppedconnections enable
dir %systemroot%\system32\LogFiles\Firewall\
type %systemroot%\system32\LogFiles\Firewall\pfirewall.log
先ず上記で、ファイアウォールでのログ出力を設定しました。拒否したパケットについて記録してくれるはずです。ではcentosの方からpingを実行してみましょう。
cmder(Windows上)
cd bashtst
vagrant ssh
centosにログインしたら、以下を実行します。
cmder(centos上)
ping 192.168.55.1 -c 4
ログ出力有無を確認します。
コマンドプロンプト
dir %systemroot%\system32\LogFiles\Firewall\
type %systemroot%\system32\LogFiles\Firewall\pfirewall.log
以下のように出力されました。
C:\Windows\system32>type %systemroot%\system32\LogFiles\Firewall\pfirewall.log
#Version: 1.5
#Software: Microsoft Windows Firewall
#Time Format: Local
#Fields: date time action protocol src-ip dst-ip src-port dst-port size tcpflags tcpsyn tcpack tcpwin icmptype icmpcode info path
2024-09-15 19:57:14 DROP ICMP 192.168.55.101 192.168.55.1 - - 84 - - - - 8 0 - RECEIVE
2024-09-15 19:57:15 DROP ICMP 192.168.55.101 192.168.55.1 - - 84 - - - - 8 0 - RECEIVE
2024-09-15 19:57:16 DROP ICMP 192.168.55.101 192.168.55.1 - - 84 - - - - 8 0 - RECEIVE
2024-09-15 19:57:17 DROP ICMP 192.168.55.101 192.168.55.1 - - 84 - - - - 8 0 - RECEIVE
C:\Windows\system32>
期待通り、「受信はしていても、ファイアウォールにてdropされていた」となります。原因が分かれば対処も可能なはずです。
netsh advfirewall firewall show rule name="ファイルとプリンターの共有 (エコー要求 - ICMPv4 受信)"
netsh advfirewall firewall set rule name="ファイルとプリンターの共有 (エコー要求 - ICMPv4 受信)" profile=private,public new enable=yes
netsh advfirewall firewall show rule name="ファイルとプリンターの共有 (エコー要求 - ICMPv4 受信)"
詰まり、ファイアウォールの設定で、許可設定を行ったということになります。
これで改めてcentosからpingを試してみましょう。今度はWindows側のキャプチャも仕掛けてみましょう。
コマンドプロンプト
set T=%time: =0%
set DATETIME=%date:/=%_%T:~0,2%%T:~3,2%%T:~6,2%
pktmon start --capture -f PktMon_%DATETIME%.etl
pktmon status
Windows側のキャプチャ準備が整ったら、cmderを操作して、centosからpingを実施してみましょう。
cmder(Windows上)
cd bashtst
vagrant ssh
centosにログインしたら、以下を実行します。
cmder(centos上)
ping 192.168.55.1 -c 4
pingが終わったら、ホストOS側でキャプチャをしているコマンドプロンプトの画面について以下を実行して、pktmonでのキャプチャを停止し、キャプチャ結果を見てみましょう。
コマンドプロンプト
pktmon stop
pktmon etl2pcap PktMon_%DATETIME%.etl
wireshark C:\Windows\System32\PktMon_%DATETIME%.pcapng
ちゃんと疎通できましたね!このようにして、期待と相違する事象があった際は、図を描き、可能な箇所のログを取得し、切り分けを行っていきましょう。
ファイアウォールの設定は必要に応じて戻しておきましょう。
netsh advfirewall firewall show rule name="ファイルとプリンターの共有 (エコー要求 - ICMPv4 受信)"
netsh advfirewall firewall set rule name="ファイルとプリンターの共有 (エコー要求 - ICMPv4 受信)" profile=private,public new enable=no
netsh advfirewall firewall show rule name="ファイルとプリンターの共有 (エコー要求 - ICMPv4 受信)"
pingについては以上です。
パケットをキャプチャしてみよう。その2 http
次はちゃんとウェルノウンポートについて見ていきましょう。
httpは現在では各所に活用されている、不可欠のインフラと言って差し支えないプロトコルだと思います。
Hypertext Transfer Protocol -- HTTP/1.0
↓更新された定義
HTTP Semantics
各種プロトコルの定義は随時更新されるため、都度最新の定義は何番か、確認するようにしましょう。
On the Internet, HTTP communication generally takes place over TCP/IP connections.
The default port is TCP 80 [15], but other ports can be used.
ポート番号は「80」ということなので、実際キャプチャしてみましょう。
Windowsキー+Rで「ファイル名を指定して実行」を起動し、cmdと入力し、Ctrl+Shiftを押しながらエンターを押して、管理者権限でコマンドプロンプトを起動します。
コマンドプロンプト
set T=%time: =0%
set DATETIME=%date:/=%_%T:~0,2%%T:~3,2%%T:~6,2%
where pktmon
pktmon start --capture -f PktMon_%DATETIME%.etl
pktmon status
curl http://192.168.55.101
pktmon stop
pktmon etl2pcap PktMon_%DATETIME%.etl
wireshark C:\Windows\System32\PktMon_%DATETIME%.pcapng
先ず、curlの結果はどうだったでしょうか?Failという文字が見えるようなので、何か上手く行ってないような気がします。
では、キャプチャ結果を見てみましょう。
今回はちゃんとTCPを利用しているプロトコルなので、対話フィルタでTCPを選択できますね。
先ず、centosに向けて、ポート80へのSYNパケットを投げているようです。しかし、その次で、centos側から、RSTパケットが返されているようです。
詰まり、相手のサーバから、応答があったけれど、どうやらそれは期待する応答ではなかったようです。
TCPのSYNパケットなどの定義もまた確認してみてください。
curl: (7) Failed to connect to 192.168.55.101 port 80 after 2021 ms: Couldn't connect to server
ここで、IPアドレスに対しては、正についさっきまで、pingでL3としての疎通は確認してましたね。なので、自信を持って、問題はL4以上にある、と言えるのです。詰まり、先ずはポートについて疑いましょう。
この後の動き方はいくつかあるかと思いますが、取り敢えずはサーバ側でどのポートがLISTEN状態かを確認してみましょう。
cmder(Windows上)
cd bashtst
vagrant ssh
centosにログインしたら、以下を実行します。
cmder(centos上)
ss -antup
ここで、期待値としては、80番ポートでLISTENがあることなのですが、、、見当たりません。どういうことだろうか、、、、確かに、tomcatは起動しているはずなのに、、
ということで、tomcatの設定を確認してみましょう。
[vagrant@centosstr9 ~]$ sudo grep port /opt/tomcat/conf/server.xml
<Server port="8005" shutdown="SHUTDOWN">
Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
<Connector port="8080" protocol="HTTP/1.1"
port="8080" protocol="HTTP/1.1"
<!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
<!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2
<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
<!-- Define an AJP 1.3 Connector on port 8009 -->
port="8009"
<!-- You should set jvmRoute to support load-balancing via AJP ie :
[vagrant@centosstr9 ~]$
xmlファイルなのでコメントアウトに注意しなくてはなりませんが、取り敢えずぱっと見で、「port="8080" protocol="HTTP/1.1"」という記載が目につきます。
どうやら、tomcatはデフォルトでポートは8080で待ち受けているようです。確かに、ssコマンドの結果にも、8080で待ち受けているログがありました。
それが誰なのか確認してみましょう。
ps faux | grep tomcat | cut -c 1-100
sudo ss -antups | grep 8080
先ずは㎰コマンドで、tomcatのプロセスIDを確認しています。また、ssコマンドの結果は先ほどよりも情報が増えたと思います。
[vagrant@centosstr9 ~]$ ps faux | grep -e tomcat | grep -v -e grep | cut -c 1-100
tomcat 35087 1.2 8.1 2973700 148588 ? Sl 17:19 3:36 /usr/bin/java -Djava.util.logging
[vagrant@centosstr9 ~]$ sudo ss -antups | grep 8080
tcp LISTEN 0 100 *:8080 *:* users:(("java",pid=35087,fd=43))
[vagrant@centosstr9 ~]$
私の手元のパソコンでは、tomcatのプロセスIDは35087で、これが8080ポートでLISTENしている、ということが確認できました。
「ウェルノウンポートをキャプチャ」と言いながら、2つ目もウェルノウンポートへのキャプチャではないものを紹介している訳です。酷いですね。
では、改めてWindows側から、ポート8080に対してhttpアクセスを行ってみましょう。
コマンドプロンプト
set T=%time: =0%
set DATETIME=%date:/=%_%T:~0,2%%T:~3,2%%T:~6,2%
where pktmon
pktmon start --capture -f PktMon_%DATETIME%.etl
pktmon status
curl http://192.168.55.101:8080
pktmon stop
pktmon etl2pcap PktMon_%DATETIME%.etl
wireshark C:\Windows\System32\PktMon_%DATETIME%.pcapng
今度はちゃんと見れましたね!
ここで、httpのプロトコルフォーマットを確認してみましょう。
Hypertext Transfer Protocol -- HTTP/1.1
https://datatracker.ietf.org/doc/html/rfc2616#section-5
5 Request
A request message from a client to a server includes, within the first line of that message, the method to be applied to the resource, the identifier of the resource, and the protocol version in use.
Request = Request-Line ; Section 5.1
*(( general-header ; Section 4.5
| request-header ; Section 5.3
| entity-header ) CRLF) ; Section 7.1
CRLF
[ message-body ] ; Section 4.3
5.1 Request-Line
The Request-Line begins with a method token, followed by the Request-URI and the protocol version, and ending with CRLF.
The elements are separated by SP characters. No CR or LF is allowed except in the final CRLF sequence.
Request-Line = Method SP Request-URI SP HTTP-Version CRLF
リクエストは、ヘッダと、ボディがあり、それは改行コードCRLFで分けられている、という構造のようです。また、ヘッダはメソッド、URI、バージョンということなので、キャプチャ結果を再度見てみましょう。
確かにヘッダがあり、改行も記録されていますね!
6 Response
After receiving and interpreting a request message, a server responds with an HTTP response message.
Response = Status-Line ; Section 6.1
*(( general-header ; Section 4.5
| response-header ; Section 6.2
| entity-header ) CRLF) ; Section 7.1
CRLF
[ message-body ] ; Section 7.2
6.1 Status-Line
The first line of a Response message is the Status-Line, consisting of the protocol version followed by a numeric status code and its associated textual phrase, with each element separated by SP characters.
No CR or LF is allowed except in the final CRLF sequence.
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
レスポンスも似たような考え方になっているようですね。確かに、バージョンとステータスコードに続いて、改行コードが見えています。
今回は最も良く使っているであろうhttpというプロトコルをキャプチャし、プロトコルフォーマットと見比べてみる所までやってみました。httpはここまでとします。
パケットをキャプチャしてみよう。その3 telnet
次はレガシープロトコルとされている、telnetを見てみましょう。
取り敢えずキャプチャ、、、の前に、環境準備
レガシーと言われるだけあり、最近はデフォルトでは利用できないことが多いと思います。
centos側のtelnetサーバ準備
先ずはcentos側にtelnetをインストール、起動しましょう。
sudo dnf install -y telnet telnet-server
sudo systemctl enable telnet.socket
sudo systemctl start telnet.socket
sudo systemctl status telnet.socket
sudo ss -antups | grep :23
exit
一旦仮想マシンを電源オフしておきましょう。
vagrant halt
Windows側のポートフォワーディング準備
続いて、VirtualBoxに設定を加える必要があります。Vagrantfileを任意のエディタで開き、「forwarded_port」の設定を19行目に追記してみましょう。この設定をすることで、仮想マシンへのパケットの受け渡しを上手いことやってくれます。
centosstr9.vm.network "private_network", ip: "192.168.55.101", :netmask => "255.255.255.0"
centosstr9.vm.network "forwarded_port", guest: 23, host: 2300
centosstr9.vm.provision "shell", inline: <<-SHELL1
編集後、以下を実行し、centosを起動します。
vagrant up
もしvagrant upが上手くいかなくなったら、エラーメッセージで調べて対処を行っても良いのですが、「vagrant」の名の通り、簡単に壊して作り直して、という対処ができることが売りの一つなので、以下のコマンドで仮想マシンを一度完全に消してしまって、もう一度一からやり直す、ということも検討してみてください。
vagrant destroy
vagrant up
今回であれば、Vagrantfileの内容をもう一度やり直してくれます。なので、tomcatがインストールされたcentosが起動する状態まで、10分程度で戻ってくれます。
フォワーディングが設定されているか確認してみましょう。
ホストOSの2300ポートを、ゲストOSの23ポートへ繋いでくれるように設定できているようです。
もう一つ、2222→22という設定もありますが、これはいつ誰がやってくれたのでしょうか?これはvagrantが良い感じに設定してくれていた、ということになります。便利ですね。
Windows側のtelnetクライアント準備
コマンドプロンプトで「telnet」と実行しても、そんなコマンドないよ、と怒られるかと思います。appwizから機能追加しておけば利用可能ではありますが、今回はメジャーなアプリを利用してみましょう。
Windowsキー+Rで「ファイル名を指定して実行」を起動し、powershellと入力し、Ctrl+Shiftを押しながらエンターを押して、管理者権限でPowerShellを起動します。
choco install -y teraterm
上記でteratermをインストールしています。teratermは、telnet、ssh、シリアルの3つの接続が選べるので、何かと便利です。サーバとの通信はssh主流になっていると思いますが、nasやNW機器とはtelnetやシリアル接続も利用されると思います。
ではキャプチャしてみましょう
では、準備は整ったと思うので、早速キャプチャしてみましょう。
teratermを起動すると上記のような画面で、接続先を指定できると思います。
TELNET PROTOCOL SPECIFICATION
ここで、telnetの仕様を確認してみましょう。
Port Assignment
When used for remote user access to service hosts (i.e., remote terminal access) this protocol is assigned server port 23 (27 octal).
That is L=23.
一番最後にポートに関する記載はありました。ただ、この仕様書は初めて利用する際のマニュアルとしては難しいので、サーバ上でマニュアルコマンドを実行してみましょう。
[vagrant@centosstr9 ~]$ man telnet
TELNET(1) BSD General Commands Manual TELNET(1)
NAME
telnet — user interface to the TELNET protocol
SYNOPSIS
telnet [-468EFKLacdfrx] [-X authtype] [-b hostalias] [-e escapechar] [-k realm] [-l user]
[-n tracefile] [host [port]]
上記のような感じで、コマンドの使い方が出てきたかと思います。色々とオプションはありますが、一番最後の[host [port]]を指定するのが基本的な使い方のようです。今回はコマンドラインでなく、アプリ利用しますが、仕様としては見ておきましょう。
それではteratermの画面に戻って、IPアドレスとポート番号を入力してみましょう。
- ホスト 127.0.0.1
- サービス Telnet
- TCPポート 2300
ここで、エンターを押す前にパケットキャプチャを仕掛けましょう。centos側で以下を実行します。
sudo tcpdump -i any -w `date "+%Y%m%d_%H%M%S"`_tcpdump.cap
では、teratermに戻ってエンターを押してみましょう。ログインを促されるはずなので、vagrant/vagrantでログインしましょう。取り敢えずpwdで今どこにいるか確認してみました。
ではtcpdumpをCtrl+Cで停止しましょう。その後、キャプチャ結果をWindows側に持ってきて、wiresharkで見てみましょう。
cmder(Windows上)
scp -F ssh.config vagrant@centosstr9:/home/vagrant/\*.cap /tools/Cmder/bashtst/
for /f "usebackq" %A in (`ls -1t ^| head -n 1`) do set tcpdumpcap=%A
wireshark %tcpdumpcap%
ProtocolがTELNETとなっており、ちゃんと認識されているようです。今回の場合、IPアドレスは末尾2がWindows側、末尾15がcentos側のようです。因みにその上の3行ですが、
→SYN
SYN、ACK←
ACK→
となっており、これがTCPの3wayハンドシェイクと呼ばれるものですね。
さて、telnetのやり取りをもう少し見てみましょう。
#省略
ここまでで、ログインを促されて、それに対してユーザ名を入力したようですが、クライアント側からの通信は、何と一文字ごとに行われているのですね。私はタイプミスしたのでそれもしっかりとキャプチャ結果に出ていました。更に続きを見てみると、、、
やはり、秘密にされるべきパスワードが、普通に平文で見えてしまっています。この後のpwdコマンドの実行とその結果のやり取りも確認できてしまいました。これがレガシープロトコルとされる理由と思ってください。teratermの接続選択肢にあるとおり、現在ではsshを利用した通信が推奨されています。
telnetはIPアドレスとポート番号を指定して、プロトコルの勉強として手動でメール送信してみるとか、対象のポートが利用可能かWindows側から確認するとか、便利なツールとしては活用できると思います。一方で、セキュリティの観点からは非推奨なプロトコルである、ということになります。ツールは、目的に応じて使い分けましょう、ということですね。
telnetに関してはここまでといたします。
パケットをキャプチャしてみよう。その4 https
次はhttpにsがついたプロトコルを見ていきましょう。
取り敢えずキャプチャ
httpsの接続先を自前で用意しても良いのですが、少し手間がかかるので、今回は普通にインターネット上のサーバへのアクセスを見てみましょう。少し前から、各種ブラウザがhttpsアクセスを基本とし始めたり、セキュリティを意識した流れがあり、これまた社会インフラと言って良いプロトコルだと思います。通販なんかも安全じゃないと使いたくないですもんね。
コマンドプロンプト
set T=%time: =0%
set DATETIME=%date:/=%_%T:~0,2%%T:~3,2%%T:~6,2%
pktmon start --capture -f PktMon_%DATETIME%.etl
pktmon status
curl -I https://www.google.co.jp/
pktmon stop
pktmon etl2pcap PktMon_%DATETIME%.etl
wireshark C:\Windows\System32\PktMon_%DATETIME%.pcapng
自前でhttpsアクセスを確認したい場合は、以下を参考にしてみてください。
https://qiita.com/kubo4ka/items/5cfd2d3522e8d18fa146
httpsとは
さて、キャプチャ結果を見る前に、プロトコルについて確認してみましょう。
HTTP Over TLS
↓更新
This memo describes how to use TLS to secure HTTP connections over the Internet.
1. Introduction
HTTP [RFC2616] was originally used in the clear on the Internet.
However, increased use of HTTP for sensitive applications has required security measures.
SSL, and its successor TLS [RFC2246] were designed to provide channel-oriented security.
This document describes how to use HTTP over TLS.
ということですので、どうやら、インターネット上で平文でやり取りしていたhttpについて、機密性を担保したいアプリが出てきたので、チャネルの暗号化をSSL、そしてその後継プロトコルであるTLSによって行うようにしてみたよ、という感じのようです。ポート番号も443という記載があります。SSLはもう脆弱性が見つかってメンテされなくなり、現在ではTLSという後継のプロトコルが改版されている、ということですね。
詰まり、TLSというプロトコルを確認する必要がありそうです。フローを載せてくれていたので見てみましょう。
The Transport Layer Security (TLS) Protocol Version 1.2
Dierks & Rescorla Standards Track [Page 35]
RFC 5246 TLS August 2008
Client Server
ClientHello -------->
ServerHello
Certificate*
ServerKeyExchange*
CertificateRequest*
<-------- ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished -------->
[ChangeCipherSpec]
<-------- Finished
Application Data <-------> Application Data
Figure 1. Message flow for a full handshake
* Indicates optional or situation-dependent messages that are not always sent.
- クライアント側から通信を開始
- サーバ側から証明書関係のやり取りを開始
- クライアント側からも証明書関係の応答
- 暗号化の合意
- 暗号化通信
といった感じのようです。
上記はTLSに関する定義なので、httpsとは詰まり「TLSで暗号化した通信であり、暗号化対象の通信が利用しているプロトコルはhttpである」、ということのようですね。
証明書、CAなどセキュリティに関する体系的な理解は以下の書籍などを確認してみてください。
暗号技術入門
https://cr.hyuki.net/
証明書に関する章が一連の流れ、攻撃の可能性、対策の必要性を説明してくれています。
色々な人が要約をブログなどにまとめていたりもします。
http://www.spiritek.co.jp/spkblog/2017/01/26/%E6%9A%97%E5%8F%B7%E6%8A%80%E8%A1%93%E5%85%A5%E9%96%8010-%E8%A8%BC%E6%98%8E%E6%9B%B8/
キャプチャ結果の確認
改めてキャプチャ結果を見てみましょう。
- ClientHello
- ServerHello
- ClientKeyExchange
- ChangeCipherSpec
- Application Data
ちゃんとこの順序でやり取りがされていることが見えますね。No258のApplication Dataの中身を見てみると、httpであることも分かります。ここは最後のサーバからの応答なので、webページの内容を返却しているはずです。ただ、暗号化されているので、内容を確認することはできません。これで、盗聴されても何も分からない、安全である、と言える訳ですね。なりすまし対策などは上記の本などを参考にしてみてください。暗号化のアルゴリズムや、何故鍵の交換を行っても問題ないのかも、分かりやすく解説されています。
httpsについては以上とします。
パケットをキャプチャしてみよう。その5 ssh
telnetを確認した際に、現在ではsshを推奨されているとしましたので、こちらも見てみましょう。何が違うのでしょうか?
取り敢えずキャプチャ
cmder(Windows上)
cd bashtst
vagrant ssh
centosにログインしたら、以下を実行します。
cmder(centos上)
sudo tcpdump -i any -w `date "+%Y%m%d_%H%M%S"`_tcpdump.cap
cmderをもう一つ画面開きたいので「Ctrl+T > エンター」で新しいタブを開きましょう。再度作業ディレクトリに移動して、centosへログインします。
cmder(Windows上)
cd bashtst
vagrant ssh
sshのログインが終わったら、Ctrl+TABで、cmderのタブをtcpdumpをしている画面に切り替えて、Ctrl+Cでtcpdumpを停止し、exitでcentosをログオフします。
cmder(Windows上)
cd bashtst
scp -F ssh.config vagrant@centosstr9:/home/vagrant/\*.cap /tools/Cmder/bashtst/
for /f "usebackq" %A in (`ls -1t ^| head -n 1`) do set tcpdumpcap=%A
set PATH=%PATH%;"C:\Program Files\Wireshark"
wireshark %tcpdumpcap%
sshとは
The Secure Shell (SSH) Transport Layer Protocol
sshの開発元の説明が分かりやすいフローになっていたので確認してみてください。
SSH Client SSH Server
--> Client initiates the connection by contacting server -->
<-- Sends server public key <--
<-- Negotiate parameters and open secure channel -->
--> User login to server host operating system -->
元々は上記のある企業の商品だったものが、標準として認められていった、という歴史があるようですね。
キャプチャ結果の確認
- TCPの3wayハンドシェイク
- クライアント側からイニシャライズとしてバージョンの提示
- サーバ側からも応答としてバージョンの提示
- 鍵交換
- 暗号化されたやり取り
ということで、こちらも流れの確認ができましたね。telnetの時の様に、どこかに平文でパスワードが出ていないかと探しても、見つかりません。
Message Code: Elliptic Curve Diffie-Hellman Key Exchange Init (30)
KEX host key (type: ecdsa-sha2-nistp256)
鍵交換のアルゴリズムや、暗号化アルゴリズムなどのやり取りをしているな、ということは見えますね。強度は大丈夫でしょうか?脆弱性、危殆化といった情報は、日々変化していきますので、世間一般のニュースの確認と併せて、セキュリティ的なニュースも見ておく習慣を付けてみましょう。
sshについては以上とします。
その他
ntp、domain、bootps、bootpc、pop3など、日常生活で利用しているプロトコルは是非確認してみてください。
以上