An Impactful ‘No Rate Limiting’ Bug

1 week ago 13
BOOK THIS SPACE FOR AD
ARTICLE AD

JateloCybersec

Before getting into this, I want to mention something I feel is important in the previous article about the IDOR I found on that SaaS application. At the time, it was my first valid bug(again, I’m not a pro hunter and it’s probably because I haven’t dedicated as much time as other hunters — not an excuse, just the way it is). So without making this any longer than it needs to be, something I learned about the previous submission was the art of patience and having faith that taking a little time after finding a bug to fully internalize it won’t lead to a duplicate. I might be wrong here but look, after reporting the bug that impacted the integrity of the system(a user could add stuff in another user’s notepad), if only I took a minute to calm myself down, let the adrenaline flow out of my system, maybe I would have landed two bounties on the same object. Picture this, there is no control limiting a users to their scratchpad objects. The scratchpad object was referenced in two different functionalities: if you can modify, there’s a pretty high chance that you can also read, right? That’s when it hit me, reading another user’s scratchpad would have been more impactful since there, it’s confidentiality we are talking about which usually has a higher CVS score than integrity. It’s been almost a couple of months since this happened and it still makes my eye water.

Anyway, I know, I’m a cry baby, but thought it was important sharing this experience with you guys. Now, back to the future; sorry the present. So after spending some significant time without hunting, I one day felt the inspiration to look at the application again; probably to check if the bug was fixed. As always instead of checking for what brought me there, I found myself chasing down something that looked particularly interesting.

I had briefly described the application in the previous article, and would ride on assumptions that you read that one before arriving here. So the application once you log in, you land on your workspace where you can invite other people, probably members of your organization through a ‘sendWorkspaceInvite’ functionality. Alright, what can we do with that. Rate limiting. After intercepting the POST request to a graphql endpoint with the SendInvite functionality, I sent it over to the repeater tab and manually tried resending the same request multiple times and observed an error. What was I doing wrong, I thought? Analyzing the request and the corresponding result, I wasn’t able to figure it out until I went back to the application to try and achieve this on the browser.

I used the `sendWorkspaceInvite` functionality by inserting the target’s email and clicking on send invite and monitored the request. It was the same one I was dealing with before. But back on the browser, after sending the invite, the button changed to resend invite, and upon clicking it, I noticed that a different request was used to resend the invite. What do I mean by a different request? The functionality used here, was not `sendWorkspaceInvite` but `resendWorkspaceInvite` and this was now the request that became of interest hence sent it to the repeater.

Over on the repeater tab, I sent it again to confirm if the target(an email I control) would get another invite email sent and Indeed an email arrived at my inbox. There and then an I remembered a report by Zseano to hackerone that I had seen a while ago that saw his rate-limiting bug accepted due to the impact he showed. My eyes sparked but wait, looking at the response keenly, before launching my ‘attack’, I noticed some headers in the response that made my heart sink abit: `X-Ratelimit-Limit` and `X-Ratelimit-Remaining` headers. This meant that the application was in theory protecting itself against rate-limiting on this functionality.

What did I do? Give up? no. I said I might as well just check it anyway and go to bed when I start seeing 429’s. So I sent the request over to Intruder. Over there I analyzed the request for a numerical value that didn’t have any impact on the response and set it as a the position for my payload. The idea was to find a way to send more than the 1000 requests that was defined in the `X-Ratelimit-Limit` header but as well be mindful of my actions; this is a production environment. So I settled at 1200, this was enough to prove that the rate-limiting measures are not implemented correctly. I set the payload type to increment all the way from 1 to 1200(on a value in the request that had no impact on the response — sterile I might say) then started the attack and went for cup of water: just incase it didn’t workout.

Coming back, to my screen, I scrolled all the way down to the final request and saw response code 200. They were all 200's.

Nice. So it was time to check the target email(again an email I control). I realized some funny behavior, the first 100 emails came in with almost negligible time difference. But as the emails went on, I started noticing significant time differences between the emails and it reached a point where the I wasn’t receiving any more emails. It was like their email server had hanged or something.

You see where I’m going with this, right? Well I hope you are. If not, let me spell things out then. The impact of this bug is something that is usually out of scope, Denial of service. But that report ringing in my head, I just had to report it. By me choking their email server to send such an enormous amount of invite emails, the availability of this functionality was impacted. Legitimate users would experience delay in inviting other members to their workspaces and the SaaS company cared about their customers enough to see this as an issue that would perhaps cost their company. The company therefore rewarded my responsible disclosure with a small bounty b$$$ty and we both lived happily ever after.

Read Entire Article