Post

HTB • Juggling Facts

Juggling Facts is a web challenge released on Hack the Box by Xclow3n that is marked as very easy and involves finding and exploiting a PHP type juggling vulnerability in a web application

An organization seems to possess knowledge of the true nature of pumpkins. Can you find out what they honestly know and uncover this centuries-long secret once and for all?

Code Review

In index.php, we can see that the PHP application only has two endpoints at / and /api/getfacts, and they both map to controllers/IndexController.php.

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
43
44
45
46
47
48
49
50
51
52
<?php

class IndexController extends Controller
{
    public function __construct()
    {
        parent::__construct();
    }

    public function index($router)
    {
        $router->view('index');
    }

    public function getfacts($router)
    {
        $jsondata = json_decode(file_get_contents('php://input'), true);

        if ( empty($jsondata) || !array_key_exists('type', $jsondata))
        {
            return $router->jsonify(['message' => 'Insufficient parameters!']);
        }

        if ($jsondata['type'] === 'secrets' && $_SERVER['REMOTE_ADDR'] !== '127.0.0.1')
        {
            return $router->jsonify(['message' => 'Currently this type can be only accessed through localhost!']);
        }

        switch ($jsondata['type'])
        {
            case 'secrets':
                return $router->jsonify([
                    'facts' => $this->facts->get_facts('secrets')
                ]);

            case 'spooky':
                return $router->jsonify([
                    'facts' => $this->facts->get_facts('spooky')
                ]);
            
            case 'not_spooky':
                return $router->jsonify([
                    'facts' => $this->facts->get_facts('not_spooky')
                ]);
            
            default:
                return $router->jsonify([
                    'message' => 'Invalid type!'
                ]);
        }
    }
}

The endpoint / does not ingest any user input, so we’re probably not interested in that. The /api/getfacts endpoint looks to parse the request body as JSON on line 17, then process the type key which is passed in the request body.

Things get interesting when the application seems to block requests where type is set to “secrets”, and the client IP address is not 127.0.0.1. Notice how the strict comparison operator === is used to compare the values on line 24.

The application then uses a switch statement to compare type to “secrets”, and returns some secret content if they match. This differs from the previous comparison because the switch statement works as a loose comparison (==), whereas the initial comparison is strict (===). This disparity can be viewed in the following tables.

Strict comparison table Strict comparison table

Loose comparison table Loose comparison table

Logic flaws caused by this are known as PHP type juggling vulnerabilities.

Exploitation

In this case, the logic can be exploited by setting type to true in the request body. When the statement on line 24 compares type and “secrets”, it should not match, but when these are compared on line 31, they should match. Let’s try this out with curl.

1
2
addr='127.0.0.1:1337' # Change this
curl "$addr/api/getfacts" -d '{"type":true}'

The flag is returned!

This post is licensed under CC BY 4.0 by the author.