- Challenge Setup: The website is build with the old web framework Helma
- Key Discoveries: Users can traverse a chain of HopObjects
- Vulnerability: The video HopObject
allows to access arbitrary properties
- Exploitation: Accessing the __parent__
property leads us to the Global HopObject
and eventually via the accessKey
property to the flag
The challenge is about the old web framework Helma, which has not been maintained for more than 7 years. The challenge's objective is to retrieve the access key of the configuration file.
In the following sections, we walk through the entire process, from the initial analysis to the final exploitation.
Starting with the landing page, we have a selection of different movie categories containing movies and subcategories.
The server files seem very odd with file extensions like .hac
, .hsp
or .skin
. After some research, it's clear that the old web framework named Helma, written in Java, is being used. The flag is hidden in the app.properties
configuration file in the accessKey
property. With this key, we can modify, add and delete any categories and movies from the website, as we will see in a moment. Fortunately, there is some documentation about this obscure framework.
Helma is organized around two core concepts: HopObjects and Actions. HopObjects
are Helma’s server‐side, JavaScript‐implemented object types that can be persisted in a database. They allow developers to model application data as native JavaScript objects with properties, methods and inheritance, without having to write separate database schemas. Actions
, on the other hand, are the controllers in Helma’s MVC‐style architecture. Each Action
is a JavaScript function that is bound to a specific URL endpoint and is responsible for processing incoming HTTP requests, manipulating HopObjects
. Actions
can also render responses in HTML, JSON and other formats.
The main HopObject
is the root
object, defining the entry point of the web page with the Root/main.hac
file, like in this challenge. There is an Action
defined with the path /add_category
, triggering the code inside Root/add_category.hac
. Checking it out, we are greeted by an HTML form requiring, among other things, the accessKey
:
The Root/type.properties
describes that accessing the Root
object's collection goes via the name
properties of the underlying HopObjects
. Added categories via add_category
are added to the collection of Root
. The same goes for subcategories and videos, which can be added to categories. This effectively means by clicking through the hyperlinks in the website we can traverse the collections of the HopObjects
starting with Root
, going recursively over Category
, if subcategories were added, and finally reaching Video
and the Property
objects.
The challenge files overwrite the usual HopObjects
behaviour. They will always call the getProperty
function of a HopObject
to retrieve its properties:
function getChildElement(name) {
if (this.getProperty && this.getProperty(name)) {
var prop = new Property();
prop.obj = this;
prop.name = name;
return prop;
}
return this.get(name);
}
The getProperty
function for Video
objects works slightly differently than for the others:
function getProperty(name) {
if (name == "category") {
return this._parent;
} else {
return this[name];
}
}
We control the name
parameter for this function via the URL path. Due to this[name]
, we can retrieve any property of the object this
like name
and producer
. But more importantly, we can also get internal properties like _id
or __parent__
. The accessKey
is part of the Global
object, so effectively we need to traverse the properties of any Video
object, reaching the Global
object and its accessKey
property to retrieve the flag.
Setting up a local instance is not quite necessary, but it makes debugging much easier. For this, we need to leak the used Helma version, which turns out pretty simple. We can trigger an error, for example, by checking out the __created__
property, revealing it is Helma v1.5.2:
As the code is the best documentation, let's have a look at the source code of HopObjects. Here we find all of the different internal properties. Playing around with __parent__
will result in following URL to obtain the flag:
/Documentary/The+Fall+of+Arasaka+Tower/__parent__/accessKey
All of the information leaks come from handling unvalidated and unsanitized user input in the getProperty
function of the Video
object. Moreover, dynamically handling access to properties like this always creates openings for attackers. Using for example a white list would be much more secure in this case only allowing specific properties to be accessed. Finally, avoid using an unmaintained web framework like Helma - migrate to a more modern alternative.
dach2025{wh0_n33ds_n0de_j5_anyw4y_edabc46f6280250fc7e646dee1a3937c}