• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar
Craig Hays

Craig Hays

  • Cybersecurity
  • Principles
  • Newsletter
  • Learn Cyber Security
    • Hacking and Defending User Accounts
    • Learning Guides
  • Contact
  • Show Search
Hide Search
You are here: Home / Archives for bug bounty writeup

bug bounty writeup

How I Bought a £240.00 Annual Subscription for Bargain £0.01

August 11, 2021 By Craig Hays Leave a Comment

Reading Time: 3 minutes

I found a way to alter a premium subscription service price and bought it for a penny. This is how I did it.

Photo by Polina Tankilevitch from Pexels

Whenever I’m bug hunting on a target that takes payments, I always try to buy something using a test credit card number as described in my write-up on Cracking Encrypted Credit Card Numbers. When the payment fails (or succeeds!) I look through all of the requests and responses for the entire process, searching for anything which looks interesting.

Look Out for Numbers

While hacking on a private SaaS bug bounty program, I went through the new user sign-up funnel and entered a test card at the payment page. The payment failed, of course, and so I went back to look at all of the requests and responses captured in Burp through this process. The subscription I had attempted to purchase via the website was the platform’s premium service at £19.99 per month.

I noticed that the request to buy with my credit card transaction token included the string “package_id”:”target:payments:packages:1205″. In the response I received the string “term”:”monthly”,”price”:{“amount”:1999,”currency”:”GBP”}. The amount was the monthly value of the subscription, £19.99 in pence. It also confirmed that the subscription was monthly. The thing that caught my attention was the numerical ID in the package_id parameter. I was curious to see if I could find any other valid package IDs and, if so, what prices and payment terms they were linked to.

Thousands of Failed Payments Later

Using Burp Suite Intruder I repeated my failed payment request 10,000 times, starting from “target:payments:packages:1” and incrementing the ID up to “target:payments:packages:10000”. While many of the requests errored out with a “no package found” message, I was able to find hundreds of past and future prices still listed in their pricing table,

The most expensive was £49.99 on a monthly term. The cheapest was £0.01 on both a monthly and annual term. Bingo. Now all I needed to do was confirm that the payment would actually work and I could create a real subscription with the identified package number.

Making the Payment

Armed with a package_id number priced at £0.01 annually, I went back through the web-based new user sign-up process and enabled Burp Suite proxy intercept just as I was about to enter my payment details. This time, however, I entered my real credit card details and manually forwarded on the resulting requests until I saw the string “package_id”:”target:payments:packages:1205″ again. At this point, I changed the SKU 1205 for the annual £0.01 SKU and hit forward, then switched off Burp Suite proxy intercept.

To my surprise, it worked and I had just bought a £239.88 annual subscription for a penny. I went back into my account and reviewed my subscription and confirmed that I was a premium subscriber. The end date for my contract was 12 months later.

Why Companies Use Test SKUs

craighays.com barcode sku

The package_id for this SaaS is the digital equivalent of a barcode SKU (stock-keeping unit) on the side of a box. By listing multiple SKUs and changing the sign-up form to switch between them, the target company can change prices at any time without losing the ability to renew subscriptions at the previous price.

In this case, it looks like the target company created a monthly and annual subscription SKU priced at £0.01 each to allow employees to test the live payment system after code deployments. While this is quite common, these penny SKUs are not usually publicly visible or easy to guess and are reserved for employee usage.

Impact

This bug has the potential of a big financial impact in terms of lost revenue. If this became public knowledge, all of their existing customers could cancel their subscriptions and renew for £0.01 costing the target £239.87 per customer per year. New customers could sign up for a penny losing all future revenue until the SKU is disabled. The 1p charge probably doesn’t even cover the credit card transaction fee.

Recommended Remediation

The best way to fix this while keeping the ability for testers to test their payments system is to add a third value to each SKU for Enabled: True or False. That way, the team can enable the £0.01 SKUs for testing, make a purchase, then set them back to False in the application database so that they cannot be abused by people like me.

The payment processing code would need to be updated to read the value of the Enabled property from the database and cancel any transactions trying to use a disabled SKU, advising Stripe not to complete the payment for the presented token.

Pre-Account Takeover by Reversing a Weak Email Verification Token Algorithm

July 22, 2021 By Craig Hays Leave a Comment

Reading Time: 6 minutes

I spoofed access to other people’s email in order to pre-steal user accounts before they are first registered. Here’s how I did it.

Pre-account takeover weak token algorithm
Photo by Markus Winkler on Unsplash

One thing I always test while hacking on bug bounty programs is how applications generate tokens. Tokens are used for things such as password resets, email address verification, one-click sign-in, etc.

While hacking on one private program I discovered an application with a weak algorithm for generating email verification tokens. This is how I approached the problem and how I found a way to generate valid tokens to verify ownership of any email address, even those I didn’t actually have access to. This enabled me to pre-register accounts on any email address with a password of my choice which leads to an account takeover when the real owner eventually registers.

Analysing The Token Generation Algorithm

The first thing I test while attacking any web application with a bug bounty scope is the account creation and authentication functionality. On this occasion, I discovered that each time I created a new user account, the application wouldn’t let me do anything until I had verified ownership of my email address. The target application would email me a verification link and prompt me to check my inbox and that was as far as I could go

By forcing me to validate my email address the application owners can prevent pre-account takeovers.

Pre-Account Takeovers

Modern web applications often have multiple ways to log in to a user account. These can include:

  • Username and password
  • Email address and password
  • Oauth such as ‘Sign in with Facebook’ or ‘Login with Twitter’
  • SAML Single Sign-On from any SAML compatible Identity Provider (IdP)
  • Passwordless using tokenised ‘magic’ links

A pre-account takeover is when an attacker creates a user account with one login method and then the victim creates another account with another login method. The application then links the two accounts together based on the matching email address. When the email address is not validated, or validations are bypassed, this can lead to pre or post account creation takeovers.

The attack happens as follows:

  1. The attacker creates a user account on a web application using an email address that they don’t own.
  2. The application doesn’t verify that they are the owner of the email address
  3. The account sits dormant for a period of time
  4. The real owner of the email address chooses to ‘sign-in with Facebook’ and Facebook provides the users validated email address.
  5. The Facebook email address matches the email address the attacker signed up with and the two accounts are linked.
  6. Now the attacker can log in to the victim’s account with an email address and password that they supplied and they can see everything the victim does inside their account each time they log in with Facebook.

Email Verification Token Recon

Checking my inbox, I found the ‘confirm your account’ email and copied the link into my favourite text editor. I always save all one-time links emailed to me along with the account name, email address, registration time, and so on, in case any patterns emerge while testing.

The link had the format https://craighays.com/verify/?P1=randomString &P2=randomString &P3=staticText &P4=staticText (without the spaces).

After generating a few verification emails for different accounts I could see that P3 and P4 were always the same things. P1 and P2, however, always changed each time an email was sent. Opening the link after removing or altering P1 or P2 resulted in an error message and the email address was not verified. Therefore, the combination of P1 and P2 together formed a two-part email address ownership verification token.

Digging Deeper

Now that I had identified the two-part token used to confirm an email address, I took a deeper look at the two parameters.

Both P1 and P2 were base64 encoded strings. An easy way to spot this is when a random-looking string ends with a single = or double ==. These = chars are used as padding to ensure the pre-encoded string meets the minimum bit length. This isn’t always the case though as a perfect-length string won’t need padding. If in doubt, always pass random strings through different decoders to see if anything interesting comes out.

After decoding multiple P1 and P2 parameters from different links I could see that P1 always had the format of four static characters followed by 12 numerical characters such as TEXT000123456789 and P2 always had the format of 9 numerical characters such as 123456789. Looking through my list of decoded P1 and P2 strings, I could see that the numbers were incrementing, going up in large steps from one email verification link to another. P1 and P2 were not correlated in any way other than that they both went up.

At first, I tried to guess the numbered strings based on the timestamps in the HTTP response, but that was getting me nowhere. Instead, I had the idea of defining upper and lower bounds within which a valid token for an email address would reside. With a small range, even a 9 or 12 digit number could be brute-forced to create a valid token.

Upper and Lower Bounds

Looking at the problem mathematically, I needed to guess two 9 digit numbers. The twelve-digit number always started with 000 so it was effectively 9 digits long. A 9 digit number has 1,000,000,000 possible combinations. Since I have two of them, I have 1,000,000,000 * 1,000,000,000 possible combinations for each email verification token. Pretty secure.

The issue with this application was that in each token generated, P1 and P2 had numbers greater than the previous P1 and P2, but lower than the next P1 and P2. If I can create a token that I can see, followed by one I can’t, then a third that I can see, I can reduce the range of possible numbers significantly. I can create upper and lower bounds on the 9 digit number which is a much smaller range than the 1,000,000,000 possible combinations.

The step by step of my token attack looked like this:

  1. Create an account with an email address I own
  2. Create an account with the email address I don’t own, but want to validate
  3. Create an account with an email address I own

Putting This Into Practice

In order to prove that I could validate any email address, I decided to validate my own name at the target company domain, e.g. [email protected]

[Read more…] about Pre-Account Takeover by Reversing a Weak Email Verification Token Algorithm

Primary Sidebar

Newsletter

Want to get smarter about cyber security? Join my growing list of newsletter readers for exclusive news, reviews, how-tos, and more.

· © Craig Hays, 2006–2023 ·

  • Phishing