Yummy

Port Scan
22/tcp open ssh syn-ack ttl 63 OpenSSH 9.6p1 Ubuntu 3ubuntu13.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 a2:ed:65:77:e9:c4:2f:13:49:19:b0:b8:09:eb:56:36 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNb9gG2HwsjMe4EUwFdFE9H8NguzJkfCboW4CveSS+cr2846RitFyzx3a9t4X7S3xE3OgLnmgj8PtKCcOnVh8nQ=
| 256 bc:df:25:35:5c:97:24:f2:69:b4:ce:60:17:50:3c:f0 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEZKWYurAF2kFS4bHCSCBvsQ+55/NxhAtZGCykcOx9b6
80/tcp open http syn-ack ttl 63 Caddy httpd
| http-methods:
|_ Supported Methods: POST HEAD OPTIONS GET
|_http-favicon: Unknown favicon MD5: 0C6ECE85EA540E6ABEBA19B1436C17E2
|_http-title: Yummy
|_http-server-header: CaddyAn initial Nmap scan detects an SSH service running on port 22 and a nginx web server on port 80 .
To access the webapp lets add it to our /etc/hosts file
Web App Enumeration
Visiting the website we find that it belongs to a restaurant named yummy.
I notice a register and login feature so i created an account.
There is also a Book A Table button so lets check it out

The page was a form that takes in some basic information so ijust fill this out. after confirming it says i can mange the appointment at our account, so i head to the Dashboard page

we get a download button labeled Save iCalendar. Clicking it triggers a request to:


Lets take a look at the request to understand what happens.
The page makes a request to /export/Yummy_reservation.... This immediately raises a question: is the export endpoint reading files from the server? Or does it look for files on the system. maybe it's vulnerable to path traversal ?

At first, simply repeating the /export request fails with a 500 error. However, replaying both:
/reminder/<id>Then
/export/<file>
in sequence using Burp Repeater β Grouped requests works.


Now trying the path traversal on the /etc/passwd file and we actully got it. his indicates the server does not sanitize file paths correctly, allowing access to sensitive files.

Letβs check the crontab using the same method to check for interesting entries:
And we actually find 3 files,
app_backup.sh is just a file that is used in all boxes to reset it to default. but lets check the other files for information
we don't find anything important in the dbmonitor.sh file
From /data/scripts/table_cleanup.sh we find:
Reading the source code
Now, since we can read files on the system, why not read the website source code. But there's the problem of not knowing the file location, so let's try a little trick
we'll use /proc/self/cwd
This is a symbolic link that points to the current working directory of the process that accesses it.
So If you reference
/proc/self/cwd/app.py, it resolves toapp.pyin the current working directory of the process. Which gives us the source code.
Now, this code is huge, so let's dissect it and see the most important parts.
The first thing that catches our eyes is that it imports signature.py from /config and
verfication.py from /middleware so these are 2 more files we need to check out.
Another interesting thing is the admin and verification methods.
So what we find is there's a page called /admindashboard to access this page if first checks our cookie and look for the administrator in the role header. Also looking, I notice that it's vulnerable to SQL injection (SQLI)
We find that the prime q is too small. This makes it trivial to factor n and get the private key
The pair of RSA keys are generated in the config/signature.py. The validation is done in the middleware/verification.py
The verify_token checks for X-AUTH-Token and then decodes the JWT token with the public key to retrieve the current_role as customer or administrator.
With this, we:
Extract
nandefrom the tokenFactor
n(usingRsaCtfTool,)Forge an administrator token
So now our mission is to forge an admin cookie and go to the admin dashboard page.
to do this lets first install RsaCtfTool
This works because one of the primes (q) used was too small
Now we forge a new token with role administrator using the recovered private key:
Use the new token as the X-AUTH-Token cookie and access /admindashboard

From reviewing the source code, we know the admin panel accepts:
s=β Search queryo=β Sort order (ASC or DESC)
Adding a single qoute to the url resulted in this verbose error confirming SQLI

We can use sqlmap to dump the database but this didnt reveal anyhting important.
Another thing we can do is to check for permissions.
The DB user has FILE permission which means we can write to files. so the next step should be to write a reverse shell and look for a way to run it.
Lets take a look back at the cronjobs files. Remember the dbmonitor.sh that we ignored befor`e? lets take a close look at how it works
Basiclly this file runs every minute to check if the MYSQL service is working. If it is not active,
it sets a status and timestamp into a
dbstatus.jsonfile,sends a notification to root via email
then checks for the latest version of a
fixer-v*script and runs the latest version with/bin/bash.
Then it checks for dbstatus.json file exists in the /data/scripts directory and grep the word database is down
sends and email to root saying the service is down.
Deletes the dbstatus.json file.
if If the dbstatus.json file exists but does not contain the phrase "database is down
Deletes the file.
Runs the latest fixer-v* script found in /data/scripts
If the MySQL service is running, the script simply logs that everything is okay
Since we have file write, we can manually create a dbstatus.json file containing any content that does NOT include "database is down." Once detected, the script will attempt to execute the latest fixer-v* script using /bin/bash . This allows us to introduce a malicious fixer-v2
Then write dbstatus.json
dont forget to run netcat
now you might see the shell is very unstable and extremly limited to upgrade it we can do the following
Shell as www-data
Lets look for other users that we can have shell
Lets look over to /data/scripts
The app_backup.sh script runs every 2 minutes. We can't overwrite it as we don't have direct privileges, but because of the directory permissions, we can simply delete it and rewrite it with our own code.
now lets run ncat again and wait for the task to be executed, then we should have a shell as www-data
again lets upgrade the shell we have using:
Shell as qa
Now that we have higher permissions on the system lets further enumerate
In the /var/www directory, the app-qatesting directory is shared between www-data and qa. which means we can access it
Using the hg log commandβsimilar to git log βwe can view the commit history
We discover commit 5:6c59496d5251 contains DB creds:
Using these creds we can ssh:
Shell as dev
This means we can execute hg pull as dev.
At first glance, this doesnβt seem too dangerous, itβs just a version control operation using Mercurial (hg). But when you understand how Mercurial hooks work and how sudo handles file access, it becomes a powerful weapon.
What is hg pull?
hg pull fetches new changesets from a remote Mercurial repository. If hooks are defined (e.g., changegroup, pretxnchangegroup, etc.), they get triggered automatically during certain stages of this pull.
Since we're running:
The pull is executed as the dev user. And when hg pull runs, it uses the Mercurial configuration (hgrc) of the repository into which it's pulling. not the one it's pulling from.
So if we control the target repo (which we do), and we define a hook inside .hg/hgrc, it will be executed as dev when hg pull is run.
Understand the Context:
We canβt modify
devβs~/.hgrcβ no access.We canβt modify the source repo
/home/dev/app-productionβ itβs owned bydev.But we can create our own repo in
/tmp/, which is where the hook will run!
First lets create a test repo
Create a malicious hook script:
This script just spawns an interactive shell.
Add a Mercurial hook to execute the script:
We tell Mercurial to run this script during a changegroup operation (i.e., pull):
Now we are ready to execute the pull request
We now have a shell as dev
Shell as root
After escalating to dev, we ran:
The rsync is being used to copy the content of the production-ready app to /opt/app while excluding the .hg directory.
The vulnerability lies in the wildcard: *
Wildcards (*) expand to all files and directories, but when passed through a tool like rsync, the tool just runs what you feed it β even if it includes unexpected file types like binaries or symlinks.
So, if we drop a SUID binary, like bash, into /home/dev/app-production/, and rsync copies it with permissions intact... we win.
Copy bash into the app directory:
This creates a SUID-enabled shell. When run by a regular user, it runs with the permissions of the owner β in this case, root.
Trigger rsync:
Now bash gets copied to /opt/app/bash with the SUID bit preserved.
Run your SUID binary:
The -p flag tells bash to not drop privileges β and since itβs SUID-root, we are now root.
Last updated
Was this helpful?