はじめに

秋らしくなってきましたね!

今年の夏、私は試験勉強の夏になりました。 6 ~ 7 月にかけて LPIC (Linux Professional Institute certification) をいくつか受験してきました。 受験した試験は 201, 202, 303, 304 の 4 つです。無事全ての試験に合格し、 LPIC 1 ~ 3 までの全てのレベルの認定を取得することができました。

試験範囲はざっくりこんな感じでした。

  • LPIC-2 201 (キャパシティプランニング、ストレージ、ネットワークなど)
  • LPIC-2 202 (DNS/Web/メール/ファイル サーバーなど)
  • LPIC-3 303 Security (暗号化、アクセス制御、アプリケーション/ネットワークセキュリティなど)
  • LPIC-3 304 Virtualization & High Availability (旧バージョン。この試験範囲は [305 仮想化] および [306 高可用性] の 2 つの試験に引き継がれました。)

このうち 201 の試験範囲で出てきた nc コマンドをご紹介します。

目次

  • nc コマンドについて
  • 検証環境
    • AlmaLinux
    • Linux Mint
    • ネットワーク
    • 疎通確認
    • 注意事項
  • nc コマンドの使い方
  • ポートスキャン
    • サーバー側で待ち受けポートを解放
    • 解放されているポートへのスキャン
  • チャット
  • ファイル転送
    • 受け入れ準備
    • 転送するファイル
    • ファイルの転送
    • 転送されたファイルの確認
  • バックドア
  • 他にも
  • まとめ

nc コマンドについて

nc とは Netcat/netcat のことです。 Netcat の概要については以下の通りです。

Netcat は、Unix系OSコマンドラインアプリケーションの一つ。TCPやUDPのパケットを読み書きするバックエンドとして機能するツールで、ネットワークを扱う万能ツールとして知られる。オリジナル版より機能的に優位な派生・互換ツールが開発され、用いられている。

https://ja.wikipedia.org/wiki/Netcat

今回は nc コマンドの挙動を確認するため、 304 の試験範囲でも出てきた VirtualBox を使いました。

検証環境

  • ホストマシン: macOS Monterey 12.4
  • ゲストマシン: VirtualBox で構築した AlmaLinux, Linux Mint
    • ゲスト OS 間で通信できるよう、両 OS の 設定 > ネットワーク から ネットワークアダプターを有効化 し、 NAT ネットワーク を割り当てています。
  • nc: Version 7.91

AlmaLinux

AlmaLinux は CentOS の開発中止を受けて 2021 年にリリースされた Redhat 系の Linux です。

https://almalinux.org/

OS を確認するコマンドは以下の通り。

[alma@alma ~]$ cat /etc/redhat-release
AlmaLinux release 9.0 (Emerald Puma)

Linux Mint

Linux Mint は Ubuntu や Debian が母体なので、 OS を確認するコマンドも AlmaLinux とは少しと違いますね。

https://linuxmint.com/

mint@mint:~$ cat /etc/lsb-release
DISTRIB_ID=LinuxMint
DISTRIB_RELEASE=20.3
DISTRIB_CODENAME=una
DISTRIB_DESCRIPTION="Linux Mint 20.3 Una"

ネットワーク

それぞれの端末で $ ip route を実行します。

AlmaLinux

[alma@alma ~]$ ip route
default via 10.0.2.1 dev enp0s3 proto dhcp src 10.0.2.4 metric 100
10.0.2.0/24 dev enp0s3 proto kernel scope link src 10.0.2.4 metric 100

Linux Mint

mint@mint:~$ ip route
default via 10.0.2.1 dev enp0s3 proto dhcp metric 20100
10.0.2.0/24 dev enp0s3 proto kernel scope link src 10.0.2.6 metric 100
169.254.0.0/16 dev enp0s3 scope link metric 1000

以上より、VirtualBox 上の 2 つの端末が同一ネットワーク内 10.0.2.0/24 にあり、 alma には 10.0.2.4 、 mint には 10.0.2.6 のプライベート IP アドレスが与えられていることが分かります。

以下 alma をクライアント、mint をサーバーとします。

疎通確認

それぞれの端末から ping を実行してみます。

クライアント —-> サーバー

[client@alma ~]$ ping 10.0.2.6 -c 3
PING 10.0.2.6 (10.0.2.6) 56(84) bytes of data.
64 バイト応答 送信元 10.0.2.6: icmp_seq=1 ttl=64 time=0.625 ミリ秒
64 バイト応答 送信元 10.0.2.6: icmp_seq=2 ttl=64 time=0.629 ミリ秒
64 バイト応答 送信元 10.0.2.6: icmp_seq=3 ttl=64 time=1.28 ミリ秒

--- 10.0.2.6 ping 統計 ---
送信パケット数 3, 受信パケット数 3, 0% packet loss, time 2039ms
rtt min/avg/max/mdev = 0.625/0.843/1.275/0.305 ms

サーバー —-> クライアント

server@mint:~$ ping 10.0.2.4 -c 3
PING 10.0.2.4 (10.0.2.4) 56(84) bytes of data.
64 bytes from 10.0.2.4: icmp_seq=1 ttl=58 time=0.505 ms
64 bytes from 10.0.2.4: icmp_seq=2 ttl=58 time=0.887 ms
64 bytes from 10.0.2.4: icmp_seq=3 ttl=58 time=0.797 ms

--- 10.0.2.4 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2012ms
rtt min/avg/max/mdev = 0.505/0.729/0.887/0.163 ms

ネットワークと疎通を確認できたので、実際に nc コマンドを使ってみましょう。

注意事項

nc コマンドは便利なコマンドですが、使い方によってはサイバー攻撃と見なされるものもあります。

使用の際は自分で管理している検証環境への実行に限るなど、適切に使用してください。

nc コマンドの使い方

$ nc [options] [hostname] [port] のように引数を渡します。

$ nc -h でオプション一覧を確認してみます。

表示される内容は環境により少し異なるようです。ここではホストマシン macOS での実行結果を貼っています。

$ nc -h
usage: nc [-46AacCDdEFhklMnOortUuvz] [-K tc] [-b boundif] [-i interval] [-p source_port]
	  [--apple-recv-anyif] [--apple-awdl-unres]
	  [--apple-boundif ifbound]
	  [--apple-no-cellular] [--apple-no-expensive]
	  [--apple-no-flowadv] [--apple-tcp-timeout conntimo]
	  [--apple-tcp-keepalive keepidle] [--apple-tcp-keepintvl keepintvl]
	  [--apple-tcp-keepcnt keepcnt] [--apple-tclass tclass]
	  [--tcp-adp-rtimo num_probes] [--apple-initcoproc-allow]
	  [--apple-tcp-adp-wtimo num_probes]
	  [--setsockopt-later] [--apple-no-connectx]
	  [--apple-delegate-pid pid] [--apple-delegate-uuid uuid]
	  [--apple-kao] [--apple-ext-bk-idle]
	  [--apple-netsvctype svc] [---apple-nowakefromsleep]
	  [--apple-notify-ack] [--apple-sockev]
	  [--apple-tos tos] [--apple-tos-cmsg]
	  [-s source_ip_address] [-w timeout] [-X proxy_version]
	  [-x proxy_address[:port]] [hostname] [port[s]]
	Command Summary:
	-4                            Use IPv4
	-6                            Use IPv6
	-A                            Set SO_RECV_ANYIF on socket
	--apple-recv-anyif
	-a                            Set SO_AWDL_UNRESTRICTED on socket
	--apple-awdl-unres
	-b ifbound                    Bind socket to interface
	--apple-boundif ifbound
	-C                            Don't use cellular connection
	-c                            Send CRLF as line-ending
	--apple-no-cellular
	-D                            Enable the debug socket option
	-d                            Detach from stdin
	-E                            Don't use expensive interfaces
	--apple-no-expensive
	-F                            Do not use flow advisory (flow adv enabled by default)
	--apple-no-flowadv
	-G conntimo                   Connection timeout in seconds
	--apple-tcp-timeout conntimo
	-H keepidle                   Initial idle timeout in seconds
	--apple-tcp-keepalive keepidle
	-h                            This help text
	-I keepintvl                  Interval for repeating idle timeouts in seconds
	--apple-tcp-keepintvl keepintvl
	-i secs                       Delay interval for lines sent, ports scanned
	-J keepcnt                    Number of times to repeat idle timeout
	--apple-tcp-keepcnt keepcnt
	-K tclass                     Specify traffic class
	--apple-tclass tclass
	-k                            Keep inbound sockets open for multiple connects
	-L num_probes                 Number of probes to send before generating a read timeout event
	--tcp-adp-rtimo num_probes
	-l                            Listen mode, for inbound connects
	-m                            Set SO_INTCOPROC_ALLOW on socket
	--apple-initcoproc-allow
	-N num_probes                 Number of probes to send before generating a write timeout event
	--apple-tcp-adp-wtimo num_probes
	-o                            Issue socket options after connect/bind
	-n                            Suppress name/port resolutions
	--setsockopt-later
	-O                            Use old-style connect instead of connectx
	--apple-no-connectx
	--apple-delegate-pid pid      Set socket as delegate using pid
	-p port                       Specify local port for remote connects (cannot use with -l)
	-r                            Randomize remote ports
	-s addr                       Local source address
	-t                            Answer TELNET negotiation
	-U                            Use UNIX domain socket
	-u                            UDP mode
	-v                            Verbose
	-w secs                       Timeout for connects and final net reads
	-X proto                      Proxy protocol: "4", "5" (SOCKS) or "connect"
	-x addr[:port]                Specify proxy address and port
	-z                            Zero-I/O mode [used for scanning]
	--apple-delegate-uuid uuid    Set socket as delegate using uuid
	--apple-ecn mode              Set the ECN mode
	--apple-ext-bk-idle           Extended background idle time
	--apple-kao                   Set keep alive offload
	--apple-netsvctype            Set the network service type
	--apple-nowakefromsleep n      No wake from sleep (when n >= 2 generate KEV_SOCKET_CLOSED)
	--apple-notify-ack            Receive events when data gets acknowledged
	--apple-sockev                Receive and print socket events
	--apple-tos tos               Set the IP_TOS or IPV6_TCLASS option
	--apple-tos-cmsg              Set the IP_TOS or IPV6_TCLASS option via cmsg
	--apple-no-reuseport          Do not use the SO_REUSPORT socket option
Port numbers can be individual or ranges: lo-hi [inclusive]

それではいくつか実験してみましょう。

ポートスキャン

ポートスキャンとは、サーバーや接続要求を行なうことで解放されているポートを確認する行為で、クラッキングの準備段階でも使われる基本的な手法です。

コマンドは以下の通り。ここではポート番号として 12345 を指定しています。

[client@alma ~]$ nc -zv 10.0.2.6 12345
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connection refused.

オプション -zv の意味はこんな感じです。

-z  Zero-I/O mode [used for scanning]

-v  Verbose

コマンド実行結果から、ポート 12345 への接続が失敗したことがわかります。 この場合 12345 ポートを解放していないからですね。

ではサーバー側でポートを解放してみましょう。

サーバー側で待ち受けポートを解放

コマンドは以下の通り。ポート番号として 12345 を指定しています。

server@mint:~$ nc -lk 12345

オプションはこんな感じです。

-k     Keep inbound sockets open for multiple connects

-l, –listen  Bind and listen for incoming connections

コマンドの実行により、サーバー側が入力待ち状態になります。

この状態で先程と同じコマンドをクライアント側で実行するとどうなるでしょうか?

解放されているポートへのスキャン

[client@alma ~]$ nc -zv 10.0.2.6 12345
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 10.0.2.6:12345.
Ncat: 0 bytes sent, 0 bytes received in 0.08 seconds.

今度はポートスキャンが成功し、サーバー 10.0.2.6 の 12345 番ポートが開いていることを確認できました。

チャット

次にクライアント側のコマンドを少し変えて、クライアント・サーバー間でチャットしてみましょう。

サーバー側は先程のポートスキャン検証時と同様、引き続き入力待ち状態とします。

オプションを指定せずに以下のコマンドを実行します。

[client@alma ~]$ nc 10.0.2.6 12345

これでクライアント側も入力待ち状態になりました。

あとは画像の通りです。片方の端末で入力した情報がもう片方の端末で表示されています。

画面左側がサーバー、画面右側がクライアントです。

nc_test2

ファイル転送

次にクライアント側のコマンドをさらに少し変えて、クライアント・サーバー間でファイルを受け渡してみましょう。

一度サーバー側の入力待ち状態を Ctrl + c で解除します。

受け入れ準備

次のコマンドを実行し、クライアント側からのファイル転送を待ち状態にします。

server@mint:~$ nc -kl 12345 > tmp.txt

転送するファイル

転送するためのファイルとして tmp.txt を作成しました。

作成したファイルのハッシュ値を確認します。

ハッシュ値とは

ハッシュ値とは、データから一定の計算(関数)によって求められた固定長の値のことですね。

ハッシュは暗号や認証にも使われる技術で、データが改ざんされていないことを確認するために用いられます。 今回は、転送したファイルがクライアントとサーバーで同一の内容のファイルを見ていることを確認するためにハッシュ値を使います。

ハッシュ値を求めるためのハッシュ関数にはいくつか種類がありますが、今回は SHA-256 を使いました。 SHA-256 は、任意の長さのデータから 256 ビットのハッシュ値を算出する関数です。

コマンドは以下の通りです。

[client@alma ~]$ sha256sum tmp.txt
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  tmp.txt

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 がハッシュ値ですね。

ファイルの転送

それではファイルを転送します。クライアント側で以下のコマンドを実行します。

何も出力されませんでしたが、直前のコマンド実行が exit code 0 で終わったことを確認しました。

[client@alma ~]$ nc 10.0.2.6 12345 < tmp.txt
[client@alma ~]$ echo $?
0

転送されたファイルの確認

ファイルを確認するため入力待ち状態を Ctrl + c で解除します。

転送されたファイルのハッシュ値を確認すると、クライアント側で求めたハッシュ値と一致していることを確認できました。

server@mint:~$ sha256sum tmp.txt
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855  tmp.txt

バックドア

すでにお察しの方もおられるかもしれませんが、サーバーに対してコマンドを実行することもできます。

チャットの例でも見たように通常の読み書きは標準入出力として扱われますが、 -e オプションをつけることで入力をシェルに渡せるようになります。

バックドアを用意できるということですね。

つまり適切な方法でサーバーを待機させておけば、 nc コマンドを使って正規のログインや認証手続きを実施することなく、未認証ユーザーとしてネットワーク経由で特定のサーバーのシェルにアクセスし、 OS コマンドインジェクションを実行できるということです。

これはとてもとても危険なことです。

確かに、チャットの例ではクライアントからサーバーへ書き込みができるのは、サーバー側が入力待ち状態になっている間でした。

しかし適切なオプションを指定すれば、セッション切断後もサーバーを入力待ち状態にしたり、ステルスモードにすることで端末画面無しで動作させることもできます。 また送信元ポート番号や IP アドレスの指定ができるので、送信元の詐称も可能です。

実行例についてこの記事では扱いませんが、通常インストールされる nc コマンドには -e オプションは含まれておらず、使用できません。

他にも

他にも様々な機能があります。

Linux ではプリインストールされていることも多く、 Windows で使うこともできます。

curl のように Web サーバーから情報を取得したり、 Web サーバーやプロキシサーバーとして使用したり、メールの送信もできます。

プロトコルはデフォルトで TCP を使うため、 ICMP での通信が許可されていないネットワーク上で ping による疎通確認ができない場合などに活用することもできるでしょう。

https://nmap.org/ncat/guide/index.html

まとめ

今回は nc コマンドにフォーカスした内容でしたが、LPIC の試験勉強を通して広く深く様々なことを学ぶ機会になりました。

どの試験の試験勉強も楽しかったですが、特にネットワーク系のコマンドについて 201 で学べたことや 303 で Linux に限らずにサイバーセキュリティについてじっくり学べたことが特に印象に残っています。

今は情報処理完全確保支援士試験(旧 セキュリティスペシャリスト(SC))に向けて勉強中ですが、 303 で学んだ知識がかなり役立っています。

もちろん今回ご紹介した nc コマンドを含め、業務ですぐに使える知識ばかりを勉強しているわけではありませんが、仕事の中で見聞きする情報や概念への理解力は格段に上がったことを日々実感しています。

SC は情報セキュリティに関する国家試験では最難関の試験なので、私には難解な内容ばかりですが、合格できるかは別としてサイバー攻撃の手法、ネットワークやセキュリティ技術について学ぶことはとても楽しいと感じます。 経験の浅い私がエンジニアとしてのベースの知識を拡張する上ではとても良い機会になっているのではないかと、個人的には感じています。

資格取得をサポートする制度・仕組みが会社にあることにも心から感謝しています。 学んだことを業務で活かしていきたいと思います。