[Feb 15, 2026 - 23:59:50 (PST)] exegol-htb-seasons /workspace # ssh wacky@10.129.8.230
The authenticity of host '10.129.8.230 (10.129.8.230)' can't be established.
ED25519 key fingerprint is SHA256:JacnW6dsEmtRtwu2ULpY/CK8n/8M9tU+6pQhjBG3a4w.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.129.8.230' (ED25519) to the list of known hosts.
wacky@10.129.8.230's password:
Linux wingdata 6.1.0-42-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.159-1 (2025-12-30) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Mon Feb 16 03:00:03 2026 from 10.10.14.127
wacky@wingdata:~$
From here, I am able to read out the user flag!
wacky@wingdata:~$ cd /home/wacky
wacky@wingdata:~$ ls
user.txt
wacky@wingdata:~$ cat user.txt
b02bc6db68028c4aafbd8ea50213748f
wacky@wingdata:~$
Looking for sudo -l, looks like I have some files to work with
wacky@wingdata:~$ sudo -l
Matching Defaults entries for wacky on wingdata:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty
User wacky may run the following commands on wingdata:
(root) NOPASSWD: /usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py *
We are able to run the script below
#!/usr/bin/env python3
import tarfile
import os
import sys
import re
import argparse
BACKUP_BASE_DIR = "/opt/backup_clients/backups"
STAGING_BASE = "/opt/backup_clients/restored_backups"
def validate_backup_name(filename):
if not re.fullmatch(r"^backup_\d+\.tar$", filename):
return False
client_id = filename.split('_')[1].rstrip('.tar')
return client_id.isdigit() and client_id != "0"
def validate_restore_tag(tag):
return bool(re.fullmatch(r"^[a-zA-Z0-9_]{1,24}$", tag))
def main():
parser = argparse.ArgumentParser(
description="Restore client configuration from a validated backup tarball.",
epilog="Example: sudo %(prog)s -b backup_1001.tar -r restore_john"
)
parser.add_argument(
"-b", "--backup",
required=True,
help="Backup filename (must be in /home/wacky/backup_clients/ and match backup_<client_id>.tar, "
"where <client_id> is a positive integer, e.g., backup_1001.tar)"
)
parser.add_argument(
"-r", "--restore-dir",
required=True,
help="Staging directory name for the restore operation. "
"Must follow the format: restore_<client_user> (e.g., restore_john). "
"Only alphanumeric characters and underscores are allowed in the <client_user> part (1–24 characters)."
)
args = parser.parse_args()
if not validate_backup_name(args.backup):
print("[!] Invalid backup name. Expected format: backup_<client_id>.tar (e.g., backup_1001.tar)", file=sys.stderr)
sys.exit(1)
backup_path = os.path.join(BACKUP_BASE_DIR, args.backup)
if not os.path.isfile(backup_path):
print(f"[!] Backup file not found: {backup_path}", file=sys.stderr)
sys.exit(1)
if not args.restore_dir.startswith("restore_"):
print("[!] --restore-dir must start with 'restore_'", file=sys.stderr)
sys.exit(1)
tag = args.restore_dir[8:]
if not tag:
print("[!] --restore-dir must include a non-empty tag after 'restore_'", file=sys.stderr)
sys.exit(1)
if not validate_restore_tag(tag):
print("[!] Restore tag must be 1–24 characters long and contain only letters, digits, or underscores", file=sys.stderr)
sys.exit(1)
staging_dir = os.path.join(STAGING_BASE, args.restore_dir)
print(f"[+] Backup: {args.backup}")
print(f"[+] Staging directory: {staging_dir}")
os.makedirs(staging_dir, exist_ok=True)
try:
with tarfile.open(backup_path, "r") as tar:
tar.extractall(path=staging_dir, filter="data")
print(f"[+] Extraction completed in {staging_dir}")
except (tarfile.TarError, OSError, Exception) as e:
print(f"[!] Error during extraction: {e}", file=sys.stderr)
sys.exit(2)
if __name__ == "__main__":
main()
So, we can create a malicious TAR file to do that
Looks like a well known vulnerability as well, with some pocs available: