play with the room here!
Game zone was an educational box, that really dove deep into sqli attacks and introduced a unique privesc vector.
Please note that this writeup will not be in the order of the room, as i blackboxxed the first half. my only intention in this writeup is to display the steps i used to acquire root access. Let's hit it!
Like all good stories, this one started with an nmap scan.
By the results, I know that this box is very friendly and aimed at beginners. I head over to the webserver in search of where I can take off.
The webpage has a login functionality present, based on the room, it is safe to assume that the login functionality is vulnerable to SQL injection. I used Hydra and Seclists to bruteforce for a working SQLi payload. I first tried to attack the admin user. If you are unsure of how to use Hydra, refer to this document: https://redteamtutorials.com/2018/10/25/hydra-brute-force-https/ The Seclists wordlist I used is under Fuzzing/SQLi.
No valid payloads were found. This is probably because the user, 'admin', doesn't exist.
Now I have a working payload, I use it on the login form and log into the application. I am presented with a search feature.
It is vulnerable to SQLi. This search capability is probably using the user input to build a SELECT statement. This means that the search form is likely vulnerable to a union attack. If you are unfamiliar, the 'union' command in SQL allows a user to add an additional SELECT onto a preexisting SELECT statement. In order to build a union, the amount of items we are selecting has to match that of the original query. We can discover this by just bruteforcing with null values.
The payload | ' UNION SELECT NULL, NULL, NULL-- - | does not return an error. From this I can determine that the original query returns 3 columns and so my union statement needs to return 3 columns. Further enumeration also reveals that all 3 columns are strings, you can confirm this by replacing the, 'NULL' with a string. ei. 'a' I try to determine the database type by using database-specific functions. The user() function returns successfully, confirming that the back-end database is MySQL.
Next, I use a MySQL specific payload to dump the tables from information_schema. ' union select 'a',group_concat(table_name),'x' from information_schema.tables where table_schema=database()-- -
Obviously, the users table looks interesting. I use the following MySQL specific payload to dump the columns from these two tables. ' union select 'b',group_concat(column_name),'a' from information_schema.columns where table_schema=database()-- -
I went to select the, 'pwd' and 'username' values. I wasn't thinking at the time so I used two different injections, however you can select both with a single injection.
The 'pwd' value holds the hash of a user. I save this hash for offline cracking. Result from: ' UNION SELECT 'a',pwd,'b' FROM users-- -
Similarly, the 'username' value holds the username, which here we can see is agent47. Result from: ' UNION SELECT 'a',username,'b' from users-- - (Remember you can select 'a', username, pwd for a single, working injection.) I take the hash and use an online hash analyzer to ascertain how I will build my JohnTheRipper command. https://tunnelsup.com/hash-analyzer/
The encryption is SHA-256, I save the hash in a file and crack it with john.
The password was cracked with the default dictionary. Remember how SSH was open from that nmap scan earlier? These credentials could possibly be used to SSH. There is only one way to confirm if this is true.
Great, I can now grab user. However, there is still privesc. This time around it was via SSH tunnels, of which I was not familiar with. This is where my blackboxxing of the room ended. The room explained the process of reverse SSH tunnels and a command to show active services. I display active daemons with ss -tulpn.
Every port here corresponds to a service we have already encountered. All except port 10000. I use my new found SSH tunneling skills to access port 10000 from my localhost.
Now I can access this port. I visit it in my browser and discover another webserver.
The webmin CMS is running. I've seen a lot of CVEs for this CMS. So it's best I start looking for a version number. None are available with what I can access. So I start looking for a default password. I can't find any, but I find this article specifying the ability to log in with a system user. https://doxfer.webmin.com/Webmin/Installing_Webmin
I login with agent47 and I get greeted by a version number. We are running 1.580!
I enumerate for publicly available exploits using Searchsploit.
A very promising Metasploit module exists. Time to own root!
It looks like Agent 47 needs to ask his higher-ups about updating their security policies.
(thanks flip67 for the meme)