HTB - Travel
Zweilosec's writeup on the Hard difficulty Linux machine from https://hackthebox.eu
HTB - Travel
Overview

TODO: Finish this writeup~! Short description to include any strange things to be dealt with
Useful Skills and Tools
Useful thing 1
Browse and edit LDAP with Apache Directory Studio (need link)
Useful thing 2
SSH port forwarding to connect to remote ports that are closed (need sudo to use ports under 1024)
Enumeration
Nmap scan
I started my enumeration with an nmap scan of 10.10.10.189. The options I regularly use are: -p-, which is a shortcut which tells nmap to scan all ports, -sC is the equivalent to --script=default and runs a collection of nmap enumeration scripts against the target, -sV does a service scan, and -oG <name> saves the output with a filename of <name>, -n stops DNS resolution of hosts, and -v allows me to see progress as it discovers things rather than waiting for the full report when it finishes.
The only ports that nmap showed as open on this machine were 22 (SSH), 80 (HTTP), and 443 (HTTPS). From the nmap DNS NSE script scan I saw three virtual hosts for this IP:
I added all three to my /etc/hosts file so I could connect.

Connecting to www.travel.htb I found a "coming soon" type site with a countdown. On this site I found a contact information section with a potential a user email format.

Checking port 443 only led to an under construction site with no useful information.

The Firefox plugin wappalyzer told me the site was using WordPress version 5.4. I fired up wpscan to check the site for vulnerabilities using the syntaxwpscan --url http://blog.travel.htb/ --enumerate.

I discovered a WordPress login page at http://blog.travel.htb/wp-login.php but there was nothing else useful from the scan.

I tried resetting my password since this version of WordPress was reportedly vulnerable to information leakage through this, but it did not lead to anything useful.

The page at xmlrpc.php likewise did not seem to be useful at this time.

Navigating to the virtual host blog-dev also seemed to be a dead-end, so I started another Dirbuster scan to see if anything useful that I could access could be found.

There was an RSS feed using the Awesome RSS WordPress plugin on the blog site.

In the source code of the page I noticed a section that said DEBUG that caught my eye. I didn't know what to do with it, but it seemed interesting.

There was also a section that talked about using "Additional CSS" and importing it from the dev site. This seemed like a potential way to get code to cross domains.

Another interesting find was the raw XML output that feeds the RSS page. Perhaps there was an XML deserialization vulnerability in the site.
Since the wpscan results didn't seem to yield any useful information I checked out my Dirbuster scan of the dev-blog site and looked for interesting directories.

I found a potentially accessible git repo while scanning blog-dev with dirbuster.
The dirbuster scan also shows that some security has been put in place against automated scanners. I could see the repeated chain of /./ dirs that told me the scanner was stuck. After telling it to ignore those directories it found the git directory.
I made a folder named gitdump to dump the contents of the git repo into and ran git-dumper (from https://github.com/arthaud/git-dumper) to clone the repository.
The repository appeared to be the source code for the Awesome RSS application I saw earlier. The README.md file described the current status of the project.

The PHP file rss_template.php parses URLs and then creates SimplePie objects from them and sets that object's cache location to a local memcache. SimplePie is a WordPress plugin that allows for RSS feeds in php-based sites. . Feeds are requested from the custom_feed_url parameter if it exists, otherwise it defaults to http://www.travel.htb/newsfeed/customfeed.xml which I found earlier through dirbuster.
Memcached is used to cache requests in memory in the form of key-value pairs so that they can be retrieved quickly without making multiple requests. In this instance the memcache keys are prefixed with xct_ when they are stored.

There was further evidence of website security in the file template.php. It looked like they were trying to implement a rudimentary web application firewall by filtering out any requests that contained file://, @, -o, -F, or attempts to access the localhost. Even though some URL filtering is used, there are still many ways to bypass this. For example, ftp:// or even gopher:// could be used instead of file://, and if the localhost needs to be directly referenced different encoding schemes could be used. For example, 127.0.0.1 in hex is 0x7F000001, and in decimal 2130706433. Most URL parsers can automatically translate addresses no matter which numbering scheme is used.
The TemplateHelper class uses the file_put_contents() function to write data to a file in the /logs/ directory. This method is called from the __construct() and __wakeup() functions through the init() function. These two functions are known as "magic methods" in PHP and are triggered when certain actions happen. For example, the __wakeup() method is called when an object is deserialized. Since these are public functions, they can be called from other PHP files that reference this document, such as seen in rss_template.php.

The rss_template.php also has code that includes a debug.php if the parameter debug is set. This is what I had seen in the source code of the /awesome-rss site. After noticing this in the PHP code I went back to the same page to see if I could trigger this to do something. I set the debug flag by typing http://blog.travel.htb/awesome-rss?debug in the URL bar and got back something different in the page's source code than before.

Using the debug parameter added a bit of deserialized PHP code to the middle of the page, but there was nothing that seemed immediately useful. I did notice that the key portion of the output was prefixed with _xct like described in the PHP code.
The url_get_contents() function in rss_template.php allows for the import of a custom URL through the custom_feed_url attribute, so I hosted a web server using python SimpleHTTPServer and accessed my test page by loaded my custom URL using this link: http://blog.travel.htb/awesome-rss/?custom_feed_url=http://10.10.15.53:8090/test.html

Unfortunately the test did not actually load anything on the page, though I noticed that it did reach back to my server and pull the contents of the directory, including pulling some .png files automatically (and interestingly also including a .netxml file I had in the directory from playing around with airodump-ng earlier that day.)
This confirmed the SSRF vulnerability that the rudimentary PHP WAF was trying to protect against, though I still needed to figure out how to make it run code. Storing it in the memcached key that I saw being loaded through debug.php seemed like a likely route. Since directly referencing file includes in a URL using the most common methods were blocked, I needed to to use a less common method. Searching for SSRF file inclusion bypass led me to https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf.

This presentation from Black Hat included one case study where the researcher found a vulnerability where they were able to use SSRF to exploit Memcached. This example looked like exactly what I needed.

From rss_template.php I found the syntax to connect including the address 127.0.0.1:11211. Since the data to be included has to come from the local machine, I needed a way to embed it without pulling files from my machine. After doing some research, I decided to try doing this using the gopher protocol. Gopher is an older protocol that is used to access resources over a network but is still supported by most browsers as well as tools such as cURL. The Gopher protocol was first described in RFC 1436. IANA assigned it TCP port 70, though this is rarely ever used.
I sent a request in the browser to test this out using my customized URL, using the hex-encoded IP 0x7F000001 in place of 127.0.0.1.
This created a key named TEST in memcached with the value test. Using the ?debug flag again after requesting the above URL returns the following:
My test key was successfully cached! Now I had to see if I could use this to exploit the site. Since memcached stores PHP objects in a serialized format it can be exploited by injecting a malicious object and triggering it through deserialization using the __wakeup() method I saw earlier. The code from the git dump didn't seem to have any methods for direct deserialization, so I looked at the RSS feed SimplePie plugin source code on GitHub to see if it held any clues.
SimplePie code review
Beware, the following section is a labyrinthine mess of tracing function calls across multiple libraries and classes. I'll try to explain as best I can, but if you would rather skip this section click here.

https://github.com/WordPress/WordPress/blob/master/wp-includes/SimplePie/Cache/Memcached.php
I didn't have to look through the code long to find the relevant code. The __construct function from the SimplePie_Cache_Memcached class is what is called by the get_feed() function in the website's code. It looked like they had left the default host and port values, but had customized the timeout and prefix values. This code further explained what was actually stored in the memcached key.

I also decided to check in Misc.php and Cache.php since they were referenced in the Memcache.php code. Cache.php has a get_handler function which returns an object based on the type of handler requested. One of the handlers is SimplePie_Cache_Memcached. In this the $name variable is set to $filename and the $type variable is set to $extension.
Looking back at the source code of Memcached.php, I traced through what was going on. This function takes the MD5 hash of $name (filename) and $type (extension) together. The prefix (in this case _xct) is added to the front afterwards.

I spent awhile looking for the proper usage of this method, but finally came across Class-SimplePie.php.
This code calls the get_handler() function from Cache.php with the parameters cache_location ,cache_name_function($url), and a filetype of spc.

After searching inside the SimplePie class for $cache_name_function I found a small function that set it to md5.
The end result of all of this: It means that $filename (later $name) is set to the MD5 sum of the URL md5($url) , while $extension (later $type) is set to spc . This result is then all concatenated and the MD5 sum is taken and appended with _xct. This gives me the information I need to create the memcached key to store my malicious payload in. the __construct method above gives the template. Some pseudo-code for this result is key_name = _xct + md5sum( md5sum(url) + ':spc' ) I verified this by using the original URL of the page I ran debug on.
Crafting the payload
The beginning of this resultant hash matches the output I saw in the debug code given by the customfeed.xml site earlier!
In the Memcached.php class, I also see a load() method that calls unserialize().
Using this I can create a malicious object that will save a PHP file to the logs folder when it's deserialized. The TemplateHelper class comes in handy here. I mirrored this from the one in the earlier code. Note: the $file and $data variables must be made public as private variables can't be accessed directly from outside the class.
This PHP script serializes an instance of the class TemplateHelper, which will write a my backdoor to a file called back_door.php in the /jobs/ folder after deserialization.
Next, we need to set this payload as a value for the key
xct_4e5612ba079c530a6b1f148c0b352241so that it is deserialized when the debug method is called.
fixing and uploading final URL - https://github.com/tarunkant/Gopherus
final url - the length of the contents is important! make sure it is correct (111 in my case)
HAVE TO decimal/hex encode 127.0.0.1~~~!!! 2130706433 or 0x7f000001 and add xct_
After that it took awhile to figure out where my back_door.php was located. I found a hint in the README.md file I had found in the git repository earlier: * create logs directory in wp-content/themes/twentytwenty after that the TemplateHelper class told me it was stored in the /logs/ folder.
a shell can be obtained by using parameter on the backdoor:
xct_4e5612ba079c530a6b1f148c0b352241
Initial Foothold - www-data
www-dataNothing of interest in the /var/www/html directory
In the /opt/wordpress directory found and extracted a .sql file to my home machine; tried to open with sqlitebrowser but it told me it wasnt a valid database. I used the file command on it and it said it was a stnadard ASCII file so I opened it with vim and started browsing
picture
Finding user credentials
It was a sqldump output file rather than an actual database, but contained all of the recent queries to the database. I found password hashes for an admin user and lynik-admin , loading in hash-identifier to check what type of hash then loaded to crack with hashcat
https://scottlinux.com/2013/04/23/crack-wordpress-password-hashes-with-hashcat-how-to/ tells me the correct hash type to use for hashcat is m=400
Unfortunately I was only able to crack one of the hashes. The password for lynik-admin was 1stepcloser , which I then used to SSH into the machine.
Road to User
I tried to see what lynik-admin could do with sudo, but apparently this user was not in the sudoers file
User.txt
Path to Power (Gaining Root Access)
Enumeration as lynik-admin
lynik-adminIn lynik-admin's home folder I found a .ldaprc file which looked interesting. According to the manpage this file is used to set configuration variables for connecting to LDAP.

this file is used to store Vim history data. You can find recent files, deleted data, and search history here.There is a line which was deleted from the .ldaprc file. bind password = Theroadlesstraveled . Let's try using it to connect to LDAP.
To do this remotely I would use the command:
The -h option specifies the host to connect to, and the -x option means use simple anonymous authentication. The -b flag is used to specify the search base, while the -D flag specifies the bind Domain Name, both of which can be found in the .ldaprc file above. -w is used to specify the bind password.
But...since I am logged in why do it the hard way?
I was able to successfully dump the contents of the LDAP database, and found a list of users.
Since lynik-admin is an LDAP administrator, I now had the ability to modify user and device attributes stored in the LDAP database. In a Windows domain, this could give me the ability to promote a user to domain admin if I wished. In this case I will just try to use this to promote a user to root. Modifying LDAP through standard queries is pretty tedious, so I used Apache's Directory Studio to get a nice simple GUI. This can be downloaded for free from https://directory.apache.org/studio/downloads.html.
need to port forward 389 (need sudo rights for low port)
tried portforwarding using localhost and 127.0.0.1, but failed to connect, checked ip a and /etc/hosts to find out more and noticed 172.20.0.10
ssh port forward tunnel
checked ip a and /etc/hosts to find out more and noticed 172.20.0.10
login as lynik failed with password, but it says that only an ssh key can be used to login
https://serverfault.com/questions/653792/ssh-key-authentication-using-ldap
According to the sshd_config manpage, the AuthorizedKeysCommand configuration is used to specify the program from which the SSH server retrieves user public keys from. The sss_ssh_authorizedkeys utility retrieves user public keys from the specified domain. According to the documentation, SSH public keys can be stored in the sshPublicKey attribute in LDAP.
Next I tried adding the public key attribute to the lynik user. First, I had to add a new objectClass attribute then select ldapPublicKey After that I added the attribute sshPublicKey to lynik and clicked on Edit as Text in the editor and paste the public key.
searching for ssh keys and ldap led to https://serverfault.com/questions/653792/ssh-key-authentication-using-ldap which shows that it is possible to add keys through ldap
pictures
enumeration as lynik
lynikSince lynik-admin is an ldap admin and can modify anything, I tried setting lynik uid and gid to 0 (root) but then was denied ssh login due to configuration to deny root login;
I checked sudoers file and saw that admins and members of sudo group can run all commands as root so I changed group id to 27 (sudo) then logout and back in
Getting a shell
after adding this user to the sudoers group:
Root.txt
Thanks to xct & jkr for this very challenging and fun machine! It was quite a journey learning about PHP deserialization and learning how to read through the complex maze of the SimplePie code.
If you like this content and would like to see more, please consider buying me a coffee!
Last updated
Was this helpful?