OTP Bypass Account Takeover to Admin Panel — Ft. Header Injection
It looks like this year has great promises at least the starting is good. Already 3 bug bounty in the pipeline(just showing off:P) and learned a nice methodology which laid down the opportunity for me to write and share this writeup with everyone. The best thing about being a part time bug bounty hunter is the learnings that it gives.
Besides working as a security engineer, if you are also a part time bug bounty hunter then always try to implement the learning you get from it, the defense mechanisms in your full time job wherever possible & also give back to the security community through blogs and writeups.
This writeup is also about something that I learned recently so let’s jump into the technicalities.
The target was an online education platform where there was OTP authentication implemented. When there is an OTP based login, the first thing that comes to everyone’s mind — “How to bypass it?”. Firstly I tried to brute force it and found that there was IP-based rate limiting implemented. That means varying client IP or the IP presented to the upstream server would be able to bypass rate limiting for OTP brute force.
If the client is behind a proxy, the proxy forwards the IP address of the client to the server in a specific header,
X-Forwarded-For. In some cases, a client can use this header to spoof his IP address.
I tried the same here and inserted X-Forwarded-For header, gave it to the intruder to brute force OTP for a given phone number with varying IP address, and set Cluster bomb as a brute force attack type.
and as expected, I was able to brute force the OTP to get the successful OTP login. Now it’s time to perform horizontal privilege escalation. It was evident that there is header injection present, so apart from bypassing IP access control or rate limiting, there could be other possibilities also that can be exploited here. Remembering what I did in my earlier organization where we restricted our WordPress administrator interfaces to only internal IPs based on the client’s IP address. Here how it works —
So if an allowed internal IP address is put in the header value, proxy will end up forwarding the value of X-Forwareded-For header even if the connection actually originated from a non-whitelisted IP address and allow the attacker to access the restricted page or API endpoint.
If the “X-Forward-For: 127.0.0.1” header is set, the responding server assumes that it is being accessed by an internal IP and allows the user to access restricted content. But for this, you need to be lucky to find such restricted pages. Normally admin pages/panel admin/sensitive endpoint is restricted.
Tried accessing WordPress administrator interfaces on their blog page (wp-admin) and it was 200 OK!
Now it was a matter of time to directory brute force and find if there is any more endpoint that is being IP based restricted. Found some useful resources to find such endpoints and gave them to Intruder to do the rest.
Luckily out of all those, there was one admin page of their CMS catalog which gave 200 OK (/cms/_admin/logon.php) and along with 200 OK, it was well succeded horizontal privilege escalation (though I haven’t gone one level up to try to login into the portal).
Allow specifying a list of IPs (or CIDR’s) of trusted proxies and load balancers. If the request didn’t come from one of them, discard the X-Forwarded-For. Here is what Nginx does: Go through the list (starting from the last entry) and check each entry to see if it’s the list of trusted proxies. When one is encountered that’s not on the list, discard everything before it.
This is all about this interesting learning where to bypass IP based rate limiting host header injection was used (X-Forwarded-For) which was further used to access restricted endpoints.