To get started about the whole bug bounty topic I want to tell you about my first bounty and how I got it.
Even though the bug was not spectacular and the bounty was not thousands of dollars, it was an important milestone for me.
Before I started doing bug bounty programs I did a lot of security challenges and CTF´s for fun. In addition to these activities, I was able to get a job in IT security.
The challenges and CTF´s definitely helped me to get started and played an important role to get my first professional job in ITSEC.
If you are interested in how to get started take a look at my article How to get started in cybersecurity part1.
I always heard of bug bounty programs and websites like hackerone and bugcrowd but never got to create an account. I made the standard excuses like, I don´t have time for this, I won´t find anything or this won`t be fun.
After a while of hearing friends and fellow hackers talk about it and that it is a lot of fun, I decided to give it a shot.
The first platform I created an account on was bugcrowd and after a while of looking at the different programs, I decided to pick one that uses technologies I´m not familiar with. That way even if I´m not finding anything I will learn a thing or two.
Unfortunately, the program I picked does not have a public disclosure policy,
so I´m not allowed to disclose the name of this company.
The companies platform was build an Ruby On Rails, something completely new to me and wich I had no experience with at all.
The next thing I did was to scan for potential assets like subdomains.
A good guideline was the Bug Hunters Methodology by Jason Haddix (@jhaddix).
Currently, Jason is at version 4 which you should watch, The Bug Hunter's Methodology v4.0.
I started up Sublist3r which I used to use back in the day.
The subdomain brute force showed about 15 subdomains, after a while I noticed a subdomain that looked like
old.site.com. After some initial recon on this domain, I concluded that this has to be some sort of legacy customer portal.
Old but gold
The site had a search function to search the site's content, when searching for the term
BountyPls the request below is sent to the portal.
result_page was urlencoded, for easy reading the snipped below shows the decoded value.
POST /index.php HTTP/1.1 Host: old.site.com User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: de,en-US;q=0.7,en;q=0.3 Content-Type: application/x-form-urlencoded Accept-Encoding: gzip, deflate ACT=53&result_page=/search.php?q=BountyPls
The response was a
302 Moved Temporarily redirect which can be seen below
HTTP/1.1 302 Moved Temporarily Content-Type: text/html Connection: close Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Location: https://old.site.com/search.php?q=BountyPls Content-Length: 0
By investigating the response we can see that the content of the
result_page parameter is used to create parts of the redirection url.
When changing the
result_page parameter to something else we can see that the redirect target is changing as well.
result_page=/randomString.php?q=BountyPls the redirection target was as follows
This resulted in a
404 Not Found as the file
randomString.php was not present on the server. However, we successfully changed the redirection target to a different path on the host.
After playing around for a bit, I noticed that I can trigger a redirection to a different site if I prefix the parameter with
ACT=53&result_page=https://attackersite.com as the
POST request body, the responding redirect will lead to the submitted domain
So yeah this is an open redirect vulnerability according to Bugcrowd´s Vulnerability Rating Taxonomy a POST-Based open redirect is considered a P5 which is not in scope of the program. 😭
It´s not over yet
Since I have a development background I remembered that devs are lazy and it was common to use constructs like PHP´s $_REQUEST variable.
By using this it doesn´t matter if the variable is located in the body of the request or the url.
In short, it is possible to move the parameters from the
POST body to the url and use a
GET request instead.
The changed request can be seen below
GET /index.php?ACT=53&result_page=https://attackersite.com HTTP/1.1 Host: old.site.com User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: de,en-US;q=0.7,en;q=0.3 Content-Type: application/x-form-urlencoded Accept-Encoding: gzip, deflate
This request resulted in a
HTTP/1.1 302 Moved Temporarily Content-Type: text/html Connection: close Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Location: https://attackersite.com Content-Length: 0
The first bounty 🤑
With this I was able to create an open redirect via
GET, the link
https://old.site.com/index.php?ACT=53&result_page=https://attackersite.com will now result in an open redirect to an attacker controlled site and can be used for phishing and fraud purposes.
With this now being
GET based it is considered a P4 according to Bugcrowd´s VTR which was in scope of the program and I was able to submit my first valid report.
It wasn´t much and the bug was kind of lame but I was hooked!
From this point on I considered bug bounty hunting a passion and spend a good chunk of my free time learning new technologies and attack vectors.
One more thing
To make the world a safer place let me say a few words about the vulnerability and how it could have been avoided.
The vulnerability lies in the server to trust arbitrary redirect targets defined in the parameter
result_page. This parameter is sent by the browser and thus comes from an untrusted source, because it could have been manipulated. Which I did.
I see two solutions for the problem:
- Since the value of the parameters seems to be completely static and thus never changes, it could have been hardcoded on the server side.
- If there is a dynamic nature to this parameter the devs should make sure that only trusted redirect targets are allowed.
A simple input validation with a regex like
*\.site\.comwould prevent this attack.
A nice checklist for devs can be found over at the OWASP Foundation.
This guide is a comprehensive and slim checklist to make sure the implemented software meets modern security standards.