The apartment building where I live, like many other places, has introduced safety measures around COVID-19. They’re mandated by the government anyway.

One measure is to limit access to “amenity spaces” such as the gym, lounge, etc.

Some industrious company put out a new face on an old parking app to now be Amenity Pass. It’s what my landlord company uses.

Amenity Boss slash Parking Boss slash Amenity Pass website

Initially, after months of no gym time allowed in the building, only one household was allowed in at a time. There was hyper-competition around those reservations.

It was then that I wanted to write a “sniper” program for Amenity Pass. Like the OG eBay programs.

What’s the first thing you do before writing any bot, though?

That’s right – see if someone else already did and you can steal it.

If you search “amenitypass.app” across all of GitHub you’ll encountered this repo. Just as we’d hoped, it is indeed a working bot.

GitHub search results for amenitypass.app

Let’s pause now for an explanation of Amenity Pass security measures.

  • An admin for your building sets up an account for each apartment.
  • Username is effectively your apartment number (i.e. 0301).
  • You get assigned an immutable 6-digit passcode as a security measure for making or deleting reservations.
    • Almost certainly you can bruteforce this but I did not go there. 🤐
  • When you make a reservation, you also provide your full name, email address, and phone number.
    • Though none of that seems to ever be validated in my experience.

I’d inspected traffic generated by using the web app. Retrieving available passes, making a reservation, all the good stuff.

There were some ideas in my head on how to write this program. Good ideas, I swear!

The guy whose bot we’re looking at took a much hackier, shorter approach than that. It is the reason we’re here.

Let’s take an innocent walk through his Node program. We’ll start in the package.json file. What could possibly go wrong there?

Vulnerable dependencies?! Who cares.

Screenshot of package.json code with some censoring

Oh. Ah. Ehhhh. We already knew his name but now we have App to Book Gym Slots on Behalf of Ebin Joby of Apt XX4 at XXXXXXXXe Apartments.

Exactly where he lives. Easy to search –

Screenshot of search results for this person's building

We proceed to index.js with some curiosity as to why nodemailer was present in the package file.

Boom! Maybe the post title spoiled it but –

Screenshot of index.js top of file

There’s just a set of Gmail credentials hard-coded in there. I would never violate Google terms and conditions in any way, but through an act of magic, these creds revealed themselves to be valid.

What most interested me is that this must be an old account. My understanding is you can’t just mass-create Gmail boxes anymore for throwaway purposes, as you need a phone number for activation.

“Maybe this is their main Gmail account?” you ask.

I know it’s not because there’s a different Gmail for the author further down. Then gymbot.js is a fork of this script and has an email for their roommate too.

Screenshot of gymbot.js lower file

Do we even care about the passcode and phone number at this point? They’re here anyway.

Screenshot of gymbot.js middle file

“What does this guy do for a living?!” you scream into the heavens.

LinkedIn reveals he’s a data scientist who, for God-knows-what-reason, wrote “I like to eliminate vulnerabilities” in his profile.

Screenshot of LinkedIn profile with highlighted text

Uhhhh cool. At this point I did report the leak via GitHub issue. Who knows what will come of it.

Screenshot of GitHub issue

Anyway – finders keepers if you get to that Gmail account quick 😉


Randy Gingeleski - GitHub - gingeleski.com - LinkedIn