How spending our Saturday hacking earned us 20k

Note: I have personally archived this amazing article due to the fact that the original is no longer available.

How spending our Saturday hacking earned us 20k

Intigriti organised a hacking event in which Arne Swinnen, Jeroen Beckers and I managed to earn a total of €20.000 in bounties. We earned this by bypassing one of the targets main IDOR defense mechanisms.

People often ask us bug hunters what our thought process was before finding a bug. In this article I try to dive deeper into my thought process, and the bugs that we found because of it.

Disclaimer: Because of the nature of the target, all endpoints have different names.

The target was quite hardened and had multiple layers of defense. Besides the regular IDOR defense they also had, what we believed to be, “encrypted parameters”.

 

An example of a request:

I first saw this at the start of the event and immediately started to think of ways to bypass or ‘crack’ this layer of defense. Here are some of the first things that popped into my mind when looking at the target:

  • Maybe the ‘E’ value is ignored? So we can just change the ‘V’ value and test for IDOR’s?
  • Maybe the E value is generated in the front-end and we can reverse engineer the algorithm and sign our own values?
  • What if we change the type? Or delete the E value? Will the system fallback on the unencrypted values?

I started testing my first thought and just edited the V value. The results were very misleading because requests appeared to give no errors. Eventually it turned out the V value was (almost) always ignored and they only looked at the E value. For some endpoints the system did look at the V value and ignored the E value.

In these instances where the system was looking at the V value, we would stumble upon the next layer of IDOR defense. Their second layer of IDOR defense would give us messages like: This doesn’t seem to be working, try again or contact us.


I went on to testing my second idea, perhaps the E value was generated in the front-end. It didn’t take long before I realized these values were always present in the response of the previous request and thus gave up on this idea. However I did spend a little time trying to find out if I could “guess” what encryption method was being used. I couldn’t make any sense out of it however. One thing was clear though: you can get different E values back for the same V value. But the server only accepts the last generated E value. This lead us to believe some kind of timestamp was included within the E value.


When changing the T (type) value of the requests to something else (none, hidden, number, …). You would get the same error like when trying to change the E value: This doesn’t seem to be working, try again or contact us. So this


I started running out of ideas when suddenly Arne gave me the brilliant idea to find a signing oracle. The signing oracle would give us the encrypted E if we give it a plaintext V value. For example, say there exist an endpoint /encryptValue which accepts parameters ‘V’ and replies with value ‘E’. We give it our ‘V’ value (id=6548116) and it replies with the ‘E’ value (E=bm90YWN0dWFsbHliYXNlNjQ).

There is no way to know how this E value is generated. Is it some kind of hash with trailing / prepended data? Is it encrypted? We simply don’t know, but that is fine. The backend would accept this E value and decrypt it, that’s all that matters.

I started searching for “oracle signing” endpoints and quickly stumbled upon the fact that your username also has an ‘E’ value. So simply changing your username gives you back the ‘E’ value for your username.

I started checking some endpoints with incremental numbers in an attempt to find out whether this idea actually worked. I had already been going through the application for half a day so I knew there was a “/getInvoice” endpoint which accepts the ID of an invoice (12340).

To test if the oracle bug worked I updated my username to the invoice ID +1 (12341). I copied the E value from my username to the E value in the request and sent the request. I was quite astonished when I saw the request gave another error. I did not receive the invoice with the ID I requested, but I knew the oracle was working.

Usually when the ‘E’ value was incorrect, you would get an error like this: This doesn’t seem to be working, try again or contact us. However, this time I got another error: Entity does not belong to client

Although this might seem like just another error, this was quite a breakthrough. This error indicated the server was accepting our E value, but that one of their next IDOR checks was successfully stopping us. We managed to bypass one of the layers of IDOR defense the company had.

Because we were at a live hacking event I shared this knowledge with Arne & Jeroen, hoping they would find something with this bug.

We quickly went through all of the ‘sensitive’ endpoints we could think of that included some kind of guessable or incremental ID. Unfortunately we were dealing with quite a hardened target and finding an endpoint with a missing second authorization check was quite a pain.

One of the endpoints I looked at was the /getArchive endpoint. This endpoint would return all bills / earnings you ever received. Unlike other endpoints this one behaved a little different. Most other endpoints included your ID using a field of type “text”. This endpoint expected a field of type “hidden” however. See the example below

Because the type was hidden, there was no value in the request either. There was no way of knowing what this E was. I had a strong feeling this would be my user ID. What else could it have been?

I quickly set my username to my userID and supplied the E value to this endpoint. Initially this didn’t work as I got the following error: Could not find client with this ID. In previous endpoints I had noticed that sometimes only the last part of your user ID is sent. I cut the first part of my user ID and tried again. This worked and gave me back my archive.

This meant that the hidden field was indeed my user ID. I asked the user ID of Jeroen and quickly tried with his account. The request went through and I got a full archive of Jeroen’s bills and earnings.

I quickly (perhaps a little “too” quick) sent in the report and marked it with a CVSS score of 7.7 (High severity). Because we were at a live hacking event the team immediately looked at the report. I forgot to explain some important steps in my report and thus the development team did not quite understand the report. So they asked me if I could present my finding for them.

I went to the room with the employees of the target and started setting up. As if 20 people watching you isn’t stressful enough already, the HDMI on my laptop wasn’t working with the projector. Fortunately Stijn (CEO of Intigriti) gave me his MacBook and asked me to showcase the demo on his machine. I had never worked on a Mac before and didn’t even know how to switch between burp and Firefox. I must’ve looked like an idiot in front of all these people. When I finally managed to open Burp and Firefox I explained the many steps we had to take to finally achieve this bug:

  1. Change your username to someone else’s ID.
  2. Use the E value of your username in this request
  3. We figured out the “Hidden” value was just your user id.

I gave the demo with the account of Jeroen. However, one of the people attending the meeting wanted me to try this with his ID. I went through the process again and eventually got access to his full archive. You could immediately see everyone in the room had a clear understanding of the impact of this vulnerability.

By the time I had settled back in my chair an Intigriti member came by to tell me the company decided to change the criticality from high to exceptional. I was quite happy with this because this equals a bounty of €10.000.

Meanwhile we were still hunting for more IDORs using our oracle bug. Arne found a way to get the total earnings of someone by just supplying their real name. He also got a chance to showcase his bug and just like me his bug was assigned a criticality of exceptional. Arne insisted to share 50% of his bounty with me because it wouldn’t have been possible without the oracle bug. I am still extremely thankful for this.

Jeroen managed to find a vulnerability where he was able to get access to the profile pictures of other users. Unlike most other targets, for this specific target profile pictures were not supposed to be public. He too earned a bounty for this.

After my presentation I had a little chat with the development team which cleared up a lot of things for me. First of all, there is not really any encryption going on. The ‘E’ value is just a randomly generated string that is ‘mapped’ to some cleartext value to make it impossible to perform IDORs, as you can’t guess the ID of another user.

This ‘mapping’ is supposed to be per transaction only. This means that the E values should only be valid for one endpoint at a time. This would have prevented the E value of my username (/changeUsername) from working with the archive endpoint (/getArchive).

Both Arne and I received a bonus and a trophy. Arne got the trophy for best hacker which he definitely deserved. I received a trophy for finding the best bug and a bonus for being the first to find a critical bug.

In the end I spent 75% of my day bypassing this layer of defense. While trying to find ways around it I constantly saw other hackers submitting reports and earning bounties. Although this got quite demotivating at times, I knew that finding a way around this layer of defense would be worth the effort.

Some things to remember:

  • No target is completely secure, everyone makes mistakes
  • Don’t give up because you see some ‘advanced layer of defense’
  • If possible, brainstorm with other hackers to get more ideas
  • Always write clear and detailed reports, unless you like presenting in front of 20 people

Note: I have personally archived this amazing article due to the fact that the original is no longer available.

Author: McPeters Joseph

Joseph McPeters is a Security Researcher. He specializes in network and web application penetration testing. Contact: admin@incidentsecurity.com

Leave a Reply

Your email address will not be published. Required fields are marked *