Wednesday, February 4, 2026

Academy Walkthrough: A Study in Chaining Misconfigurations to Root Access

Academy

In this walkthrough of the "Academy" machine, we explore how a forgotten note, weak encryption, and improper file permissions can lead to a complete system takeover. Deep Log Analysis is used to uncover clear text credentials, and SUDO Exploitation is used to escalate privileges to the highest level.

Tools: nmap, ffuf, hash-identifier, Hashcat, Linpeas.

Level: Intermediate level

Enumeration

Started with a standard Nmap scan to identify open ports and services.

nmap -A -p- -T4 <machine_IP>

Nmap result:

21/tcp open  ftp     vsftpd 3.0.3 
ftp-anon: Anonymous FTP login allowed. note.txt
22/tcp open  ssh     OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
80/tcp open  http    Apache httpd 2.4.38 ((Debian)) anonymous

Key Findings

  • Port 21 (FTP): vsftpd 3.0.3 is running with anonymous login allowed. The scan revealed an interesting file named note.txt, which is our primary point of interest.
  • Port 22 (SSH): OpenSSH is exposed, suggesting we might find credentials later to log in.
  • Port 80 (HTTP): A standard Apache web server is running. If FTP hits a dead end, it will enumerate web directories here.

Why investigate FTP first?

Anonymous FTP access is a legacy configuration that administrators frequently overlook. It frequently overlooks the legacy configuration that allows anonymous FTP access. It frequently contains files—backups, notes, or configuration scripts—that were intended to be temporary but were never removed.

> ftp <machine IP>


After successfully logging in with FTP, try to access the note.txt file.

Anonymous FTP access turned out to be very informative. Inside, we found note.txt, which contained an SQL INSERT statement intended for the backend database.

This file unintentionally leaked a specific user record, identifying StudentRegno (10201321) as our login username and containing a 32-character password hash (cd73502828457d15655bbd7a63fb0bc8).

Cracking Weak Cryptography

To crack the password hash, I used the hashcat tool. But first, we need to determine what type of hash it is, so I use the hash-identifier tool.


It confirmed that it’s MD5. To crack this hash, I used Hashcat tool and the rockyou.txt password file with the following command.

> hashcat -m 0 hash.txt <rockyou file location>


Woot! We successfully cracked the hash and now have the password (student) for StudentRegno (10201321).

Web Exploitation.

Okay, so far, so good. According to the nmap response, we also have port 80 open, so navigate to the website using the machine IP and enumerate port 80.

When we visit the website, it receives the default Apache 2 Debian page.


No, as such information appeared on the page, proceed to perform directory fuzzing on the endpoint using the ffuf tool with the following command.

command : fuff -w <wordlist location>:FUZZ -u <url>/FUZZ


This revealed the two directories.
academy, phpmyadmin

Navigating to the /academy directory presented a login page. The cracked credentials (10201321 / student) successfully authenticated the session.


Yahh! Successfully logged in.

Upon accessing the "My Profile" section, it was discovered that the application failed to validate file uploads. This allowed for the upload of malicious PHP files.


let’s upload the .php reverse shell https://github.com/pentestmonkey/php-reverse-shell/blob/master/php-reverse-shell.php .

Manipulate the shell PHP file and add the attacker's machine IP and update the port, then run the Netcat listener.

After uploading the shell file, access it using the page's view source code feature.


noticed the netcat listener response.

We got a shell, which is great, but not as a root user, as shown by the command whoami, which displays the www-data user rather than the root user.

So now what's next? We need to perform root user privilege escalation, and that's where the fun begins.

I’m going to use the tool LinPEAS (https://github.com/peass-ng/PEASS-ng/tree/master/linPEAS).

Linpease is an automated tool that goes out and does hunting for possible paths to escalate privileges on Linux/Unix*/MacOS hosts.

To use this tool, you need to start the Python server on the linpeas file location.


Using this server, use the wget command to download the linpeas file to the already connected target machine.

To change the file permissions, run the command chmod +x <filename> after successfully loading it on the target machine.


Run the file ./linpease.sh and look at the results.

The critical information and endpoints we received in the response are highlighted in red. One backup.sh file endpoint from the grimmie user has administrative privileges. The second option is password.


Let's see what the var/www/html/academy/includes/config.php endpoint contained.


The file contains the username grimmie and the password "My_V3ryS3cur3_P4ss."

Now, since we already know that the ssh port is open on the machine, let's connect with the following command

> ssh grimmie@<machine_IP>
enter the password : My_V3ryS3cur3_P4ss

Once you've successfully entered the machine, look for the backup.sh file. manipulate the file with nano command and Inject the one-liner Bash reverse shell code with the attacker's machine IP and save the file.


It runs as root, so when the backup.sh script is run, the attacker gains root access.
Now, use the cat and ls commands to find the flag.txt file.

Summary :

Initial Vector: Information disclosure via Anonymous FTP (note.txt).

Access: Cracking the MD5 hash found in the note to access the web application. Foothold: Unrestricted file upload leading to Remote Code Execution (RCE).

Privilege Escalation: Clear-text credentials in PHP config files (Lateral Movement) $\rightarrow$ Exploiting a writable script running with root privileges.

Happy Hacking!!

Share:

Saturday, September 28, 2024

MetaCTF ⚑ Write-Ups

 MetaCTF ⚑

Challenge categories: Web Exploitation

Challenge Name: Library

Challenge Link: https://compete.metactf.com/291/problems

Tools: Manually.

Challenge Description:

In this challenge, we are performing a penetration test on a small book library app built in the Go language that appears to exhibit some abnormal behaviour. The app is designed to process book requests, but certain endpoints return unexpected responses. The objective is to identify the root cause—whether it’s a coding bug, improper input validation, or potentially a security vulnerability in the request handling. This exercise will challenge your ability to analyze code logic and identify security flaws that could compromise the app's functionality or expose it to attacks.

The challenge description contained the source code download link with a live web application to perform the penetration testing.

Application Dashboard:

Open the provided link in the browser to access the library dashboard, where we can find a welcome message and a list of available books. You can also view the details of each book.

Source Code Review:

Download the application's source code using the given link in the challenge description.

The application source code file contained two “.html“ files and one “main.go” file, which contained all the backed code of the application.

The home.html file contains an HTML template snippet that is likely used in a Go (Golang) web application. It dynamically generates a list of books, with each book title rendered as a hyperlink. The syntax {{range .}} indicates the use of Go's templating engine, which is commonly used for web applications built using Go.

<home.html>

In the above image, the <ul> element creates an unordered list that will be dynamically populated with <li> (list items). The {{range.}} syntax is part of Go’s templating system and is used for iterating over a collection. The dot (.) represents the current context passed into the template, which in this case likely refers to a list of book objects. This indicates that the template expects to receive a slice or array of books, with each book being iterated over within the {{range.}} block.

In the range loop, a list item (<li>) is created for each book in the collection.

The <a href="/books?book={{.Param}}">{{.Title}}</a> tag adds a clickable link for each book. The link is used {{.Param}} as a query parameter, which is likely a unique ID or identifier for the book. Inside the link, {{.Title}} displays the book's title as clickable text.

The {{end}} marks the end of the {{range .}} loop, indicating where the iteration stops.

<book.html>

This HTML template is designed to display the content of a single book in a web application. It uses Go templating syntax to dynamically render the book's content inside the <p> tag.

In the above image, the <p> tag is used to display a paragraph of text. {{.}} is Go's template syntax, where the dot (.) refers to the current data passed to the template. In this case, it represents a string of book content. When the page loads, {{.}} will be replaced with the actual content of the book.

The Go file (main.go) is a simple web server application that provides book-related content via Go's HTTP package and templating engine. It defines a ReadBook structure with a method that reads a file's content and returns it as a string while handling any file reading errors.

The application stores a hardcoded map of books (books), with each key-value pair representing a book identifier and description. The application also includes two HTTP handlers: homeHandler, which generates a homepage listing available books using the home.html template, and bookHandler, which retrieves and displays individual book content based on the query parameter book using the book.html template.

<main.go>

Vulnerable Code: The provided Go code is vulnerable to Server-Side Template Injection (SSTI) in the bookHandler function. below the vulnerable part of the code.

This part of the code takes the book query parameter from the URL (userBook) and directly passes it to the template.New("book").Parse() function, without any sanitization or validation.

This can result in template injection if an attacker supplies malicious input through the book parameter. Since Go templates allow for the execution of code within {{ ... }} attacker could potentially inject arbitrary template code that gets executed on the server.

To get the flag from the server, we have to use the constructed below payload.

Payload: /books?book={{.ReadBook%20"flag.txt"}}

In this payload the {{.ReadBook "flag.txt"}} is a Go template syntax where .ReadBook refers to the ReadBook method defined in the application. The injected payload attempts to call the ReadBook method to read a file called "flag.tx".

Exploitation Part:

Step 1. Open the link given in the challenge description.

Step 2. Click on any list data and the URL contains the book parameter which is vulnerable to SSTI. 

Step 3: Inject the crafted payload on the book parameter for the flag.


Mitigation Part

To mitigate the SSTI risk:

Remove Dynamic Parsing: Never send user input directly to the template parser.

Validate Input: Use only predefined values (such as book IDs) in the template and reject any untrusted or unexpected entries.

Fixed Code for bookHandler function

func bookHandler(w http.ResponseWriter, r *http.Request) {
    userBook := r.URL.Query().Get("book")
    bookContent, validBook := books[userBook]

    if validBook {
        tmpl := template.Must(template.ParseFiles("templates/book.html"))
        tmpl.Execute(w, bookContent)
        return
    }

    http.Error(w, "No valid book specified", http.StatusBadRequest)
}

    • Removed Dynamic Template Parsing: The template.New("book").Parse(userBook) section has been removed to avoid processing untrusted input.
    • Only Predefined Books: The code now only renders templates for books that exist in the books map, preventing arbitrary template execution.

    Reference: Server-side template injection: https://portswigger.net/web-security/server-side-template-injection

    HackTricks: https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection#ssti-in-go

    Payatu : https://payatu.com/blog/ssti-in-golang/

    w3school : https://www.w3schools.com/go/

    _____________________________________________________________________
    Connect: LinkedIn: https://www.linkedin.com/in/sudeeplamsoge/

    Twitter : https://x.com/SudeepLamsoge

    Comments & Suggestions are always welcome. :)

    Share:

    Saturday, September 7, 2024

    In-depth analysis of CVE: PodcastGenerator 3.2.9—Blind SSRF via XML Injection.


    Application: Podcast Generator

    Vulnerable Version: v3.2.9

    Vulnerable version link: https://github.com/PodcastGenerator/PodcastGenerator/releases

    Vulnerability Description:

    Podcast Generator (PG) is an open-source content management system written in PHP, specifically designed for podcast publishing. It provides users with tools to easily manage all aspects of podcast publication, from uploading episodes to submitting them to the Podcast Index and iTunes store.

    In this write-up, we'll explore a Blind Server-Side Request Forgery (SSRF) via XML injection attack in depth, including a practical understanding of the source code and payload.

    Lab Setup:

    Download the vulnerable application from the provided link. We'll use a localhost XAMPP server for this demonstration.

    Download the XAMPP server: https://www.apachefriends.org/download.html

    1. Set up the Apache and MySQL servers using XAMPP.


    2. Unzip the downloaded Podcast Generator file to the server location:
      "C:\xampp\htdocs\<project name>".


    3. Open your web browser and navigate to the URL where you uploaded the Podcast Generator files (e.g., http://localhost:8080/PodcastGenerator).


    Source Code Analysis:

    After logging into the application, you'll notice a feature called "Upload New Episode".

    When adding a new episode, the application creates an XML file to store the data instead of using a database.

    Since the application uses an XML file for data storage, we can attempt an XML entity injection attack. Further analysis reveals that the application lacks input validation on its parameters.

    In the episodes_upload.php file, the $_POST['shortdesc'] function accesses data sent via an HTTP POST request from an HTML form, specifically the input named shortdesc (short description).

    The strlen() PHP function calculates the string length, checking if the short description exceeds 255 characters. However, the $_POST['shortdesc'] input is passed directly into the strlen() function without sanitization or validation, potentially exposing the application to cross-site scripting or injection attacks.

    Due to this lack of validation, we can perform an XML entity injection attack and escalate it to a blind SSRF attack. But first, let's understand what blind SSRF and XML entity injection attacks are.

    Blind SSRF:

    Blind SSRF vulnerabilities occur when an application makes a request to a back-end server, but the server's response isn't shown on the front-end.

    To detect a Blind SSRF attack, we can trigger an HTTP request to an external system under our control and monitor for network interactions, such as using Burp Suite Collaborator.

    XML Injection:

    XML entity injection, also known as XML External Entity (XXE) attack, involves an attacker interacting with the server using XML data.

    Some applications use XML format to exchange data between server and browser.

    Using an XML injection attack, an attacker can perform various actions, such as retrieving sensitive files or conducting an SSRF attack via XXE.

    Exploiting Blind SSRF:

    As the application creates an XML file to store data, we can exploit this vulnerability by injecting an XML payload.

    Payload:

    test]]></shortdescPG><imgPG path="">http://localhost:3132</imgPG><shortdescPG><![CDATA[test

    When adding normal data, the application stores the short description input value in the <![CDATA[]]> section.

    Note that the "testing" data is added to the CDATA section, and to balance the query, we must add the mentioned payload.

    The image below shows the difference between adding normal data and the payload, demonstrating how to balance the payload to exploit the blind SSRF attack.

    Payload Breakdown:

    test]]></shortdescPG><imgPG path=""><http://localhost:3132></imgPG><shortdescPG><![CDATA[test

    The <shortdescPG> tag uses CDATA, which likely just stores text and doesn't directly contribute to the SSRF.

    The key part of the payload is the URL http://localhost:3132 inside the <imgPG> tag. If the application processes this payload by taking the content between the <imgPG> tags and performs a server-side request (e.g., to fetch an image or resource), an attacker can exploit this by sending the server to a location under their control (such as localhost, internal services, or external servers).

    The URL http://localhost:2222 suggests the attacker is attempting to force the server to make a request to a local service on port 2222.

    Exploitation Part:

    Step 1. Log into the application using the URL:
    http://localhost:8080/PodcastGenerator/admin/

    Step 2. Navigate to "Upload New Episodes" under "Episodes".

    Step 3. Add the following payload to the short description parameter, with the listener on port 2222, then click save:

    payload:

    test]]></shortdescPG><imgPG path=""><http://localhost:2222></imgPG><shortdescPG><![CDATA[test

    Listen on the port using Netcat (NC) on port 2222

    Step 4. Open the submitted podcast data and observe the response from the server.

    WOOT!, We have successfully received the hit back from the server.

    Mitigation Part: 
    • Implement strict input validation and sanitization mechanisms to ensure that XML input from untrusted sources does not contain malicious content, including external entities.
    • Always utilize a strong database so that the input is validated from both the server and the client sides.
    • Ensure that all systems and applications are updated with the latest security patches offered by the vendor.
    Hope you understand the blind SSRF via XML injection in depth.

    Comments and suggestions are welcome.

    LinkedIn: https://www.linkedin.com/in/sudeeplamsoge/
    Twitter : https://x.com/SudeepLamsoge
     

    Share:

    Monday, September 2, 2024

    MetaCTF ⚑ Write-Ups

    MetaCTF ⚑ Write-Ups

    Challenge 3: Challenge categories: Web Exploitation

    Challenge Name: Login Query 

    Tools: Burp Suite.

    Challenge Description:

    In this challenge, we need to find the password for "jim404" without using a forgot password functionality. The challenge provides a source code link to help identify the loophole and bypass the login process.

    This challenge teaches us how to extract database information using SQL queries. As mentioned in the challenge description, it appears to be an SQL injection attack.

    Source Code Analysis:

    Download the source code using the link provided in the challenge description. Upon opening the source code files, you'll observe that they contain the login page (index.php) and (app.py), which houses the backend code for the login process. This CTF challenge is written in Python.

    The index.html file contained both the login page code and the JavaScript code. The JavaScript includes an asynchronous function called login() that manages the user login process on the webpage. This function communicates with a server to authenticate the user's credentials and updates the webpage based on the login's success or failure.

    Another file is app.py. This file contains the backend code used to manage the login process and validate the username and password with the database.

    Upon reviewing the code, it was observed that the application lacked proper validation for the username and password parameters. The SQL query is constructed by directly concatenating user input (username and password_hash) into the query string. This practice makes the application vulnerable to SQL injection attacks, allowing an attacker to manipulate the input and potentially execute arbitrary SQL commands.

    In the above image, the Python code is part of a Flask web application. It defines two routes ("/" and "/login") and handles requests to these routes. In the def Login() function, line 21 retrieves JSON data sent in the POST request body and stores it in the data variable. The next two lines extract the username and MD5 hash password.

    The SQL query is a particularly interesting part of this code. It selects the username, public_btc_address, private_btc_key, and balance from the users table. The query filters results based on matching username and password_hash values against the provided credentials.

    It’s observed that the application has not implemented any validation on username and password_hash parameters. Now, let's exploit this vulnerability using the information we've gathered.


    Challenge exploit:

    Open the given login page using the given URL in the challenge description.

    We use the Burp Suite tool to capture the requests.

    After intercepting the login request with the username "jim404" and a random password, we examine the response. The response reveals the entire SQL query along with a login failure error message.

    Breakdown the query:

    Query :

    SELECT username, public_btc_address, private_btc_key, balance FROM users WHERE username='admin' AND password_hash='0a1f508dd056bb8d1052ec6a6cb5b8b3';

    The query is designed to retrieve the username, public_btc_address, private_btc_key, and balance from the users table for the user whose username is 'admin' and whose password_hash matches the provided hash ('0a1f508dd056bb8d1052ec6a6cb5b8b3').

    To verify the username parameter's vulnerability to SQL injection, we employed the query ' or '1' = '1';--. This is a common technique used to exploit SQL injection vulnerabilities. Its most potent effect is when it successfully bypasses authentication controls.

    In this scenario, the input ' OR '1'='1' can bypass the authentication check because '1'='1' always evaluates to true. This could potentially lead to the retrieval of all records in the users table. Additionally, the double dash (-- ) signifies an SQL comment which causes the SQL query to ignore the remaining part of the query, including the password check.

    SELECT username, public_btc_address, private_btc_key, balance FROM users WHERE username='' OR '1'='1'; --' AND password_hash='d41d8cd98f00b204e9800998ecf8427e';

    The "username" parameter is closed and then a "or" statement is used. This means that if the "username" parameter is not true, then the condition "1=1" is always true. After that, a semicolon is used to end the query, followed by double hyphens to comment out the remaining part of the query.

    Once we successfully bypass the authentication process, only the admin data is shown, but we need the "jim404" user account to get the flag.

    To exploit the SQL injection for the jim404 user, we are using a UNION-based SQL injection attack.

    The UNION operator allows you to combine the results of two or more SELECT statements into a single result set.

    • Each SELECT statement within the UNION must have the same number of columns in the result set with the same data types in corresponding columns.
    • The columns in each SELECT statement must be in the same order.

    Craft the payload using the query:

    Payload:

    jim404' UNION ALL select null, null, null, password_hash from users ;--

    Final Query:

    SELECT username, public_btc_address, private_btc_key, balance FROM users WHERE username=''jim404' UNION ALL select null, null, null, password_hash from users ;--' AND password_hash='d41d8cd98f00b204e9800998ecf8427e';

    To find the password_hash for the user jim404, use the UNION ALL function to concatenate all the strings and get all the data

    • jim404': This is the part of the username parameter that closes the existing username string in the original SQL query. If the original query uses a single quote (') to wrap the username, the attacker's input will terminate the string.
    • UNION ALL: Combines the results of two SELECT statements. UNION ALL includes duplicate rows, whereas UNION would remove them.
    • SELECT null, null, null, password_hash FROM users: This is the injected SELECT statement. It selects three null values followed by the password_hash from the users table.
    • ;--: The semicolon (;) ends the original query, and -- is a comment that ignores the rest of the original query. Everything after - is treated as a comment by the SQL engine, effectively removing the password check in the original query.


    WOOT, successfully get the FLAG for the “jim404” account.

    Reference :

    Mitigation:

    • Use parameterized queries or prepared statements.
    • Properly sanitize all the user-submitted values used in the query before using them.
    • Disallow common characters used in SQL Injection payloads, such as the characters “<>/?*()&” and common SQL operations like SELECT and UPDATE.

    Share: