As usual, I will try to release this write-up with two different approaches, which are:
Please kindly note: this write-up will probably be quite a long write-up. Because in addition to trying to tell readers about where I started getting positive results from this activity, I also tried to link it with one of write-up I had previously released. InshaAllah, I will try to continue to improve this write-up (because I find it a bit difficult to collect stories with a certain time). There is a possibility if I might miss something.
Apart from those difficult things, enjoy the story.
Note: by the way, not many screenshots here. I hope you are not sleepy when you read it. But again, enjoy the story.
Let’s just say the main target discussed in this ticket is mainredacted.target.tld (bounty program). So, here are simple points on the matter:
Note: I keep all hunting results for some consideration, namely because InshaAllah it will be useful one day, and because there is no provision to delete the test results (as is generally done in formal PenTest jobs).
Here is the general “timeframe” about this:
No exciting new techniques here. The only thing I do is gather one piece of information with another and try to use it on the in-scope (bounty) target.
2.1. The story begins with the report I submitted in May 2018
At that time, I was refreshing to find bugs in a (points-only) program because of its wide coverage. In short, I found a subdomain with the name “Jira” (and yes, a Jira App) that doesn’t require authentication in order to see enough tickets on it. Although at first glance it looks interesting, unfortunately most of these tickets were made by the end of 2016 (it seems that the latest tickets have been made in a mode that the public cannot see).
Of course, reporting findings like this would not be sufficient to increase the impact. Therefore, I tried to look at some ticket content that has a specific keyword (such as password, admin, root, email, database, etc.) in hopes that I can show the impact further.
After looking for a while, I finally found some interesting things, such as:
After submission, a few days later the program owner considers this issue valid and assigns P2 for this finding and stated that it was fixed 5 months later.
A short note:
Note: but when I reanalyzed this finding (1 year 5 months later — October 2019), Alhamdulillah, I finally found my first paid P1 in this program. And this continued until Allah willed me to get another 5 paid P1s between December 2019 and September 2020.
2.2. Story reopened in October 2019
On one occasion from August 2019 to September 2019, I was focusing on one of their subdomains that was in their bounty program (let’s call sub2.target.tld — I have written a write-up about this, but I deleted it few months later because it really messed up) and few subdomains that was in their points only program. After achieving results that I thought were good enough for that target (and I don’t have any more ideas about what I can do with this target), I tried to turn my attention to their other assets (let’s call mainredacted.target.tld) in October 2019 (which I finally realized if this asset was connected to one of their SSO service).
So, what do I do to get started?
One of the things I did to get started was to go back to seeing the results of my hunting in May 2018 (related to the information I got from Jira’s results). The reason is quite simple, namely because the subdomain I was aiming to at that time seemed familiar to me and because I believe I haven’t optimized my tests on this subdomain before.
2.2.1. Take a Look (again) at the Credentials and Endpoints that have been Obtained
After decided to look at the information I got from (some) tickets on their Jira, I started learning the credential and endpoints mapping I had created.
Unfortunately, out of the 5 credentials I got (excluding FTP), only one valid credential is left (and it’s not using their official domain — more like a normal user email). But of course, it’s better than nothing, right?
After trying to play for a while with this account, I finally found that this account is connected to their SSO service. More or less the situation is like this:
The picture above is just a simple illustration to make it easier to understand the situation. I personally don’t really remember how many subdomains are linked into this asset. When I found that there was a subdomain that was out-of-scope (bounty program), I passed it — because I tend to focus on targets that are in the scope of the bounty program.
After trying to visit every menu and every subdomain, I finally came across a subdomain that had a menu labeled “Internal Resources” in it (mainredacted.target.tld). From this situation, I tried to compare it with the account I have.
A short note:
2.2.2. Comparison between Access the Site with “Internal” and External Account (Special Privilege)
When I first saw the menu labeled “Internal Resources”, I was quite surprised. Because as I have said, this account does not use an official email address from the target. So, I started to assume several things, namely:
But regardless of the reason, to make sure that it is not intended for the public, I tried to compare it with my personal account. In short, it turned out that one of my assumptions was correct, the internal users had registered his/her personal email addresses to be able to access this “Internal Resources” menu.
Initially I was quite happy to find this. Not long after, I tried to discuss with the program owner about this thing and got the decision that this did not qualify for the bounty (issues like this qualify for points only). Yes, the information in this menu is less dangerous even though it is intended for internal use (and after I opened it one by one, there were no signs of documents showing sensitive matters such as user data or the like. This is like a general operational manual document intended for internal use). They acknowledged that, but not for their bounty program.
2.2.3. Take a Look (again) at the Screenshots that have been Obtained: An Endpoint to Retrieve Customer Data.
Did I stop? No. Remember, I still have the 3rd thing besides the credentials and endpoint information, which is the screenshot I saved of some of the tickets in their Jira. From about 16 screenshots that I have saved, there is one screenshot that really catches my attention, which is a subdomain — mainredacted.target.tld (which I am focusing on) with an endpoint containing customer data.
More or less, the screenshot looks like this:
After making a simple comparison between the account I have with the one I found on Jira, it turns out that my account does not have an “interesting feature” that displays a “commercial accounts” column. Simply put, accounts that have access to this internal resource also have access to this interesting feature.
So, what’s next? From here, I tried to enter the email address that I found in the screenshot, and it turned out that I was able to retrieve customer data from the company’s email address.
A little note, the execution of this interesting feature will generate a request to the endpoint via the API.
What else? If I encounter such a situation, then there are several things that can be done, namely:
Short lesson:
But there is another good thing from this is, in 2019 they increased their reward range, so I also managed to get a reward that was much better. There is always a good lesson in everything. Alhamdulillah.
2.2.3.1. Broken Access Control Issue — Access a Private Endpoint (Internal Use Only) without needing to Have a Valid Account.
In the previous section, I have explained a little that we will try to access that interesting feature with a general account that we have or even without an account.
At the time of execution, I tried to access this interesting feature without an account first. Because of course, the impact will be different when you are able to retrieve customer data without a valid account or with a valid account (although personally, I don’t know whether Bugcrowd and Program Owner will agree with this point of view or not. However, it’s worth to try).
As a simple illustration, here is an example of an API request — which I have censored of course:
POST /api/1stRedacted/2ndRedacted/1stendpoint HTTP/1.1
Host: mainredacted.target.tld
X-CSRF-Token: unique_token_of_valid_session_here
Cookie: valid_user_cookies_here[email protected]
The simplest step we can take to execute this scenario (access the feature without a valid account) is to delete everything associated with the session in the request (such as cookies or unique tokens in the header). Unfortunately, that didn’t work.
On that occasion, I tried to look back at the request sent by the application when we wanted to access several menus without using a valid account. From this situation, finally I realized that even though I wasn’t logged in, it turned out that this application still sent requests with a (non-login state) unique token in the header.
Not long after, I tried to retrieve the unique token and cookie (in this non-login state) to reuse it to that endpoint. In short, I managed to retrieve customer data without needing a valid account.
POST /api/1stRedacted/2ndRedacted/1stendpoint HTTP/1.1
Host: subdomain.target.tld
X-CSRF-Token: unique_token_in_non-login_state
Cookie: user_cookies_in_non-login_state[email protected]
After I reported this, Bugcrowd ASE and Program Owner decided that the severity of the issue was P1 and put it in the “authentication bypass” category (for your information, I selected the Broken Access Control category without any severity).
Alhamdulillah, this is my first paid P1 in this program.
And after that, the hunting stopped here for about 2 months because I didn’t know what to do.
I explained most of this in one of my writings earlier in the year — “From Recon to Optimizing RCE Results”. But there are a few things I want to add to this point so that readers can see the flow of the paid P1 issue that I got in September 2020.
3.1. A Little Recap
As I have explained, from these activities I found quite a lot of issues with the severity of P1 (and 4 of them touched the mainredacted.target.tld asset which led to paid P1).
For 3 paid P1 issues, the flow is quite the same as the previous one, namely I managed to log in with some of their internal company accounts (no longer an account that looks like a normal user with a public email address) that uses the credential pattern I found, which have access to the interesting features discussed earlier.
Note: They see this as an issue because the account I found uses company email and has access to that feature (API) that can be used to retrieve customer data.
Then, what about the other one? When I managed to log into one of their other dashboards (which also critical enough but is not included in the scoped bounty assets yet), I found an email with the pattern [email protected] (replace the x with numbers). At that time, I tried to log in using this email (on mainredacted.target.tld) with the password pattern I found, and Alhamdulillah, it worked. And again, this account also has access to the feature (API) discusses earlier — and the total test accounts found were about 20 accounts. So, all of 4 paid P1 story is over.
How did they mitigate at that time? From what I can see, they are focused on fixing the account that is the problem. In other words, they changed the password or deactivated the account. I have recommended to them to blacklist any password patterns I find. But it looks like they didn’t do it (at least, as far as I know, until September 2020).
How do I know? Simple, because one of their applications (which is connected to their SSO) notifies from the message displayed when it fails to login. If the account exists but the password is wrong, it will say that the password is wrong. Meanwhile, if the account and the password are correct but the account has been deactivated, it will say that the account has been disabled.
3.2. They Changed the Passwords of the Affected Accounts and Deactivated the Test Accounts, So What to do Next?
To be honest, at that time I was a little bit unwilling if this hunting activity stopped here (even though at the end of this hunting activity, Allah willed me to find an RCE in one of their public assets and successfully access their internal network). So, what do I do?
Remember, in 2018 I have enumerated the subdomains of this target. From these results, I found that there are several subdomains that contain the names test, stg, uat, and the like. In short, after repeating the subdomain enumeration activity at this period, I tried to find a test version of the application I was testing (contain the names of test, stg, uat, and so on), and tried to login through that asset.
Surprisingly, it turns out that test accounts that have been deactivated in production area, can be reused in the development area.
After reporting it, I got another P1 again. But unfortunately, even though the impact is the same, they consider this subdomain not to be included in the in-scope assets of bounty program. However, at least this is much better than being considered a duplicate.
There is one interesting thing here. Do you know what that is? Accidentally, I showed a screenshot equipped with an HTTP Request view in Burpsuite (on that report) which I was aiming for to show that it is not reproducible in production but reproducible in the development area.
Please keep this in mind, because in the September 2020 story, we will return to this point.
In general, in September 2020, I came across one more account using the credential pattern I found (I’ll tell you how in another section) and came back to see the exact same interface I had found earlier (in October 2019). But when I try to enter an email address that I know has user data, it turns out that the application no longer displays user data in it. After I analyzed the request used, it turned out that the API had really changed.
With this situation in mind, I finally tried to do further analysis and went back to looking at some of my previous reports. In short, I’ve found a way to “bypass” the “protections” implemented by developers to prevent users (even with special privileges) from retrieving customer data (via previous API).
And the journey to reach this point requires at least 4 chains of vulnerability namely:
I’ll paste my report here and redact anything associated with the company name, endpoint and any sensitive data. And of course, I will add in certain sections to strengthen the explanation of this flow.
4.1. First Step — Try to Find an Endpoint that is not Well Protected
As we know, there are several sites on the target subdomain that are connected to SSO. In simply, by only using one account created on one accountcreationsubdomain.target.tld, we will be able to login to other several sites (of course as long as we have the correct access rights on these other sites).
From most of the endpoints found, it can be seen that most of the endpoints are CAPTCHA protected. That means we definitely can’t carry out an automatic brute force against them. But after a little exploration, finally I found that one portal — https://weaksub.target.tld/ is not protected by CAPTCHA. It only enforces a limit on login attempts (which is 6 attempts).
As a side note, this weaksub.target.tld asset is decided as a part of their points-only program. And this asset cannot be found in the main domain as I described earlier in section #2.2.1. I found this one by looking at my subdomain enumeration results (from the screenshots — since we can recognize it from the similar interface).
4.2. Second Step — Found a not Well Protected Endpoint, then what? Try to Find the Valid Accounts!
And as we know from one of the reports I have submitted (story in December 2019 to January 2020 period), I have collected many credentials via GitHub Recon (is the password valid / invalid). From this recon activity, I finally found a pattern of credentials that show up frequently. Based on this activity, I can assume that these are the default credentials provided by the administrator for each user (and the assumption is correct).
From here, then I use all of those credentials for the set of accounts I have gathered from extraction from SubW, SubX, SubY, TargetXYZ, and also from GitHub Recon.
4.2.1. So, What Exactly is SubW, SubX, SubY, and TargetXYZ?
Simply put, these four subdomains are subdomains that allow me to get all the emails listed on them.
As we can see, the 3 targets above are a points program only. However, from these targets, I got optimal results in extracting the data contained in the mainredacted.target.tld (listed in their bounty program).
4.2.2. The Result from Brute Force Attack in https://weaksub.target.tld/ (that not Protected with CAPTCHA)
So, how is the result? Alhamdulillah, the results of this attack produce good output. I was able to find several valid accounts using the password pattern that I found.
Note: out of 6 “available” login attempts, I only use 2 password patterns they use the most. So, we will have no trouble being blocked. After all, blocking only lasted 15 minutes, so it’s no big deal if it’s blocked.
4.3. Third Step — I Found Several Valid Accounts, then what? Try to Find out the Account that can Access Internal Menu in the mainredacted.target.tld Portal
Well, this is the challenge. Even though we have found valid accounts, we must find among these accounts that have certain access rights on the mainredacted.target.tld (that has an interesting feature via API that discussed earlier). To make it short, from those several valid accounts, I finally found one account that has special access to the Portal. (Sounds familiar? But this time it’s not as easy as before because their Developer has changed the application flow to prevent customer data extraction).
So, before we go any further for the “bypass” trick, then let’s try returning to the situation on this mainredacted.target.tld.
4.3.1. Back to Story in October 2019 (Section #2.2.2. on this report)
From one of my old report related Broken Access Control in mainredacted.target.tld Portal, we have learned that in order to be able to extract customer data via that interesting Feature, we must have access rights to /api/1stRedacted/2ndRedacted/1stendpoint Endpoint. Basically, this endpoint will be responsible for providing detailed customer data by entering the correct email address.
Note: in my original report I showed them a screenshot of the HTTP request, response and also the interface. But I can’t show it here. Just remember the endpoint context in this section.
4.3.2. As Said, Their Developer has Changed the way of the mainredacted.target.tld Portal Accesses that Interesting Feature
If from the previous section we saw that we will immediately be able to see customer data by entering a valid email address, but at this time, the mainredacted.target.tld portal no longer displays customer details. In short, the features, the name of the features and the interface are similar, however, the results were very different. Instead of showing customer data, now this feature only shows date and some insensitive information.
After looking at the request carefully, I found out if the endpoint was really different from the one, I previously mentioned.
Previous API Request:
POST /api/1stRedacted/2ndRedacted/1stendpoint HTTP/1.1
Host: mainredacted.target.tld
X-CSRF-Token: unique_token_of_valid_session_here
Cookie: valid_user_cookies_here[email protected]
Current API Request:
GET /api/vx/3rdRedacted/4thRedacted/5thRedacted/2ndEndpoint?ParametercontainUserEmail= [email protected] HTTP/1.1
Host: mainredacted.target.tld
X-CSRF-Token: unique_token_of_valid_session_here
Cookie: valid_user_cookies_here
As we can see, now they use version x for a very similar feature (with different path and endpoint). However, in this case, the flow totally prevents the user (with special access rights) from being able to extract customer data again.
Yes, I had put back the /api/1stRedacted/2ndRedacted/1stendpoint (the API that used in October 2019) endpoint in hopes of getting customer data, but it’s failed. This endpoint doesn’t work anymore.
So, this one will be another challenge.
4.3.3. Remember about My Report about the Test Version of this Target Portal? Yes, Test Version! (section #3.2).
At the end of section #3.2, I said: “Accidentally, I showed a screenshot equipped with an HTTP Request view in Burpsuite (on that report) which I was aiming for to show that it is not reproducible in production but reproducible in the development area.”
Why is this interesting? Because it turns out that they send requests to different endpoints to collect the exact same data such as flow in October 2019 and flow in December 2019 to January 2020, but with different endpoints.
In short, from the screenshot of my report, I realize that another API request has been made, which is:
POST /api/vx/6thRedacted/3rdEndpoint HTTP/1.1
Host: mainredacted.target.tld
X-CSRF-Token: unique_token_of_valid_session_here
Cookie: valid_user_cookies_here[email protected]
From here, then I try to put this endpoint (API vx) to the request and send it into the POST request with ParameterContainUserEmail POST Data. And surprisingly, I was able to extract customer details again via this endpoint. In short, we will be able to “bypass” the protection of this feature by using the OLD API requests. (Now you will understand why I quoted the word “bypass”, because this is not really a pure bypass, it just uses the old API in the development area — which their developers hide in the production area).
WAIT, so what’s the point of me saying about the set of accounts I have gathered from extraction from SubW, SubX, SubY, TargetXYZ, and also from GitHub Recon? Well, the fourth step will be the answer.
4.4. Fourth Step — Rate Limit Issue in API Endpoint that allows Attackers to Determine which Internal Account is having Customer Personal Information.
So, at this point, we already know about the Old API (which was hidden by their Developers to prevent data extraction from happening again) which can still be used. Here is a sample request:
POST /api/vx/6thRedacted/3rdEndpoint HTTP/1.1
Host: mainredacted.target.tld
X-CSRF-Token: unique_token_of_valid_session_here
Cookie: valid_user_cookies_here[email protected]
From here, we just need to change the “ParameterContainUserEmail” value to something else. Maybe the question is, what values am I currently using?
As mentioned earlier, I use bunch of accounts I have gathered from extraction from SubW, SubX, SubY, TargetXYZ, and also from GitHub Recon. So far, it has given around 10,000 unique email addresses.
In short, by using these 10,000 email addresses (it only took about 10 minutes), I finally found several accounts that have personal customer information. (In this section, I show them some proof of this).
4.5. The Submission
Not long after I submitted this report with some recommendations, they responded quickly and immediately followed up on the issue.
How about the bounty? Alhamdulillah, they also give the maximum value from the range in P1 which they have defined.
As a little information, I have obtained their permission to release this write-up by censoring their company name.
So here we are, almost at the end of the write-up. In this section, I want to add a simple recap (which I actually tucked into some of the previous sections) to make it easier for readers to understand some of the lessons from this simple journey:
But there is another good thing from this is, in 2019 they increased their reward range, so I also managed to get a reward that was much better. There is always a good lesson in everything. Alhamdulillah.
I tried to learn many technologies (that I had never face) from the target that didn’t offer bounty (but open the responsible disclosure program). In this point, one thing that I can say is, those used technologies aren’t always the technology that we face every day. In other words, we need an official “land” (legal target) to learn it and make us familiar with it.
Well, finally my simple write-up ends here. See you next time, InshaAllah.