Preparing for a Robbery

This story is about the time I found a flaw in a ticket site some time ago, but since I was extremely busy in 2018 I never got around to write it down. But I finally took the time to share a little story of how a badly configured website can be used to break into a house.

Disclaimer for the people that don’t read to the end: No I did not prepare for a robbery. But I probably could have…

The Beginning

An ‘adult over 13 years’ staring right back at you!
An ‘adult over 13 years’ staring right back at you!

It all started with the renewal of a season pass for a zoo in the Netherlands. It wasn’t so much the renewal itself that was so special that I decided to dig a bit, but what did trigger my curiosity was the passport photo of myself that stared back at me on my screen. I thought the photo was only for the pass and maybe a visual check on site, but my creepy face was stored somewhere online! I quickly renewed my pass and dove into Burp Suite to have a closer look.


Follow the Numbers

While looking at the URL for the photo, I saw there were two numbers that follow the images folder.

https://[CDN-URL]/subscriptions/images/136270/92383.jpg

So first thing I wanted to know is what these numbers did. Since it was a fairly low number I guessed that it wasn’t any kind of random identifier that was generated, but that I could probably do something with it, like add 1 to it… I did, pressed enter and nothing... Then I subtracted one and found my own partner staring at me! Subtracting more gave me more 404’s, so that didn’t work.

Since we both live on the same address, I quickly figured out that the first number in the URL was some kind of address identifier, to group families together. Time to subtract one from the first number and by making sure the photo number was also one lower than my partner’s ID, sure enough a new photo popped up!

I quickly ran a few numbers and started to gather some address-codes and pass ID’s. But if that was possible, what else could the API show me? It was time to dig into the code of the page and the calls that were made by the browser while having an active session. There must be more information I can find out…


History Lessons

While diving into the calls made to the server I found an API call that was called GetSubscriptionScanHistory and that surely sounded interesting enough. It was called after pressing the button that read ‘Usage history’.

The Dutch button ‘Gebruiksgeschiedenis’ (Usage history) is calling me
The Dutch button ‘Gebruiksgeschiedenis’ (Usage history) is calling me

After pressing the button, a screen pops up that shows you the dates and times of the ten or twenty last visits (I forgot the actual amount):

The usage history at the time (yes, only used my card once that year)
The usage history at the time (yes, only used my card once that year)

But if I was able to find out at what days and times I had used my season pass to enter the park, it must be possible to try and find the dates of other people, to use that and find victims and an empty house! And sure enough, there were lots of people that visited on a regular basis.

Let’s take the family that was assigned the ID 60006 and request their history. The URL used was nothing more than the following:

https://[Ticketsite]/[zoo]/SubscriptionManagement/60006

And when requesting this family’s history I was presented with a lovely list of regular visits. The list went on for quite some time, but it was soon clear they had a habit of visiting every second week on a Saturday or Sunday morning around 10:00AM. Don’t take attention to number 94479, since that was the father and it seemed he came in later on the 22nd of July and sometimes it seemed he went out and back in again.

The response with the full history
The response with the full history

We can break down the result into the following pieces of information:

  • subscriptionID (identifier for the address)
  • subscriptionProductID (Personal pass ID)
  • actionDate (Date and time of visit)
  • ticketCode (Personal identifier for back-end)

Target Acquired!

I now have the family complete and their personal ID’s, so time to request the photos that are tied to those passes with three separate requests. A father, mother and a small child. Three very recognizable faces, probable dates of their visits in the future and the usual visiting times are already known to me. It was time to wait for them to enter the park and follow them home later that day.

Three photos of a mother, father and their child
Three photos of a mother, father and their child

Two weeks later I was ready to go. I waited outside of town, curled the API to check on the status and sure enough… It was 10:03 that the first one arrived, followed by the second one. And thankfully this time the father joined them right away in the morning. The house was empty, they were going to have a good time and so would I!

This whole story was complete nonsense, since I don’t think I even have the balls to actually break into a stranger’s house. I already have stage fright doing physical or walk-in tests that might involve some basic social engineering! So I am not suitable for this, but that wasn’t the idea of this story.

What isn’t a lie, is the information regarding the ticket site. I disclosed the flaw last year and it was patched that same evening already. They now use completely randomised UUID’s that are completely unrelated to a shared address. They also implemented authorization so it is now impossible to request someone else’s information, whether that is a photo or the usage history. Thankfully it was not possible to request the names or other personal information via public calls, since that was protected by the authorization used to log in into the website. At least… I wasn’t able to find it… And yes, I tried!

I usually don’t have a lot of time to find things that are broken on the internet, but when I do I fantasise about what someone could do with the information. But right after I stop daydreaming, an email with the responsible disclosure is on its way to the parties involved…

Previous Post Next Post