Bruteforcing coupon codes for discount

I sometimes buy stuff from Chinese webstores because of their low prices. Now the yuan value is dropping it is now cheaper than ever to ship products from China.

Banggood.com is one of the more popular Chinese webshops. I was looking around on their website and comparing prices when I found the coupon code b185f7 by googling for 5% off.

I noticed there were more coupons of form b185f7: six characters long, only letters and numbers. I tried them with caps and without caps; it didn’t matter. That means there are only 36 possibilities for every character (0-9a-z) which gives a total possibility of 36^6. That’s not very much: enough to try a bruteforce (a full bruteforce will still take some time; I’m trying it randomly in this post).
Edit: possibly it’s in Hex, which limits the possibilities to 16^6 (0-9a-f), which is even lower and much faster to bruteforce. I didn’t test it, however.

A further thing I noticed that it is unfortunately not possible to enter more than one coupon on a single order. You can only use one at a time. That is a bummer because now two coupons with 5% off won’t give you more discount.
One thing that is good in my case, is that you can endlessly try to enter coupons. It doesn’t matter if they are valid or not; it won’t disable the field after a few wrong tries. And it doesn’t give a captcha to solve.

I wrote the little bash script below to try many coupon possibilities by randomly generating them (not really bruteforcing, just hoping we’re lucky):

#!/bin/bash

while [ 1 ]
do

  couponcode=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 6 | head -n 1)
  curling=$(curl -sS --data "com=shopcart&t=useCoupon&coupon_code=$couponcode" -H 'Cookie: banggood_SID=0f18fd4cf40bfb1dec646807c7fa5522' "https://www.banggood.com/index.php")

  if [[ $curling == *"Coupon is only allowed"* ]] || [[ $curling == *"Invalid"* ]] || [[ $curling == *"expired"* ]] || [[ $curling == "" ]]
then
    echo "$couponcode invalid";
  else
    echo "$couponcode => $curling" >> win.txt;
    echo "$couponcode VALID";
  fi

  sleep 5
done

As you see, it sends a curl request to the banggood website with my session id connected to my cart. I’m trying a infinite amount of time if a random coupon code I get is valid or not. If it gives the message “Coupon is not allowed” or “Invalid Coupon Code” if the code is invalid.
I’m using /dev/urandom as a randomness source and with tr and fold I make sure it is 6 characters long and only contains numbers and letters. As mentioned, caps or not does not matter.

I ran the script for a few hours and it didn’t take long to find valid ones. Unfortunately, they are either only 5% off or only for a specific user account. My hopes were I found more than 5% discount but that wasn’t the case.

I contacted banggood customer service (with only mail address on their site) on the 17th of August but they did not respond. I explained to them what was wrong with their coupon code system and how to fix it. I explained that 6 characters case insensitive isn’t cryptographically secure enough to prevent people from cheating. As a solution I told them to set a maximum on the amount of wrong coupon codes that can be entered. That would solve the problem without breaking functionality.

Unfortunately they didn’t respond. Here are some coupon codes I found while running the script for a short period of time. They are valid coupon codes for 5% discount each:

5bf7bb is 5%
edb44d is 5%
533876 is 5%
e7e744 is 5%
cc9ec5 is 5%
25d342 is 5%

If you are a website owner or developer and you run a webshop, make sure your coupon codes are not easily crackable. Many webshops use original names for their coupon codes instead of generating them, like ‘christmas5off’ or something. These are more difficult to bruteforce (but dictionary may have small chance of success) and therefore more safe to use.

 

How to not implement Premium features in Android

I love to regularly watch new episodes of American series and I prefer to watch them with English or Dutch subtitles. I use a script called subliminal to download them right after downloading an episode or movie from usenet (my Cubox-i4Pro handles this automatically, I can much recommend it as upgrade for your Raspberry Pi!).

Unfortunately subliminal can’t always find the right subtitles, and especially not for downloading an episode that has just been broadcasted in America. This made me look for a way to directly download subtitles from my couch, and I came across this Android app called ‘MightySubs‘ which let you download subtitles from all popular subtitle sites to your samba or ftp share.

MightySubs has a free version and a premium version that costs 99 cents. The free version has some limitations including:

  • There are only two languages available: English and your device’s language setting (premium version has 22 languages).
  • Not more than 10 daily downloads allowed (premium version increases this limit by providing custom account details for addic7ed).

 
When trying to edit a premium setting it gives a toast message like in the picture above, stating it is not available in the free version and the premium version must be bought to enable this option. That got me thinking whether it only blocks the settings panel or actually blocks the functionality inside the app itself. I figured it’s only blocking the option and that it must be possible to change this directly in the saved settings.

Most of the time, an app saves user’s settings by using the Android SharedPreferences class. It writes saved data to an xml file stored inside the ‘shared_prefs’ folder located at /data/data/com.yourpackage where com.yourpackage is the package name of the app.

This is most likely also how MightySubs works. The only thing we need is the package name. That is easy to find by looking at the Google Play store URL: https://play.google.com/store/apps/details?id=info.toyonos.mightysubs. So the app’s prefs data is stored at /data/data/info.toyonos.mightysubs/shared_prefs.
The device needs to be rooted to get inside this dir. Mine is, so I browsed to /data/data/info.toyonos.mightysubs/shared_prefs and there was indeed a file named info.toyones.mightysubs_preferences.xml with the following contents:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="PrefCurrentProfileIp">192.168.1.10</string>
    <string name="PrefSubtitlesFetchersList">{&quot;activeFetchers&quot;:[2,1,6]}</string>
    <string name="PrefDailyDownloadCounter">20150814:0</string>
    <boolean name="PrefOnlyWithoutSubtitles" value="false" />
    <boolean name="PrefCurrentProfileDownloadPathEnable" value="false" />
    <string name="PrefSubtitlesManualSelection">1</string>
    <string name="PrefAdditionalExtensions"></string>
    <string name="PrefAddic7edPassword"></string>
    <string name="PrefAddic7edUsername"></string>
    <string name="PrefCurrentProfilePath">/path/to/series/</string>
    <boolean name="PrefFullLanguageExtension" value="false" />
    <string name="PREF_VERSION_KEY">1.5.0</string>
    <string name="PrefCurrentProfileName">Local profile</string>
    <string name="PrefHearingImpaired">2</string>
    <string name="PrefCurrentProfileType">1</string>
    <boolean name="PrefKeepSubtitleFilename" value="false" />
    <string name="PrefActiveProfile">1</string>
    <string name="PrefDefaultLanguage">EN</string>
    <string name="PrefLanguageExtension">0</string>
    <string name="PrefCurrentProfileMediaType">0</string>
    <null name="PrefCurrentProfileUsername" />
    <null name="PrefCurrentProfilePassword" />
</map>

This is the file where all the settings are stored. And it is possible to edit them thanks to our root access. Looking at the names of the strings, it seems like PrefDefaultLanguage is the one that contains the enabled languages. It is currently set to “EN”.

Editing this string should give us more languages. My first try was to change it to “EN NL” to enable Dutch subtitles, but that made the app crash. I tried “EN,NL”, but same result. My last try was “EN;NL” and that worked. It unlocked the premium feature.

 
I also entered my addic7ed account details, which also bypasses the daily download limit. There is no need to buy the premium version anymore.

Contacting the developer

I sent an email about my discovery to the MightySubs developer on 31th of July, to the email provided in the Google Play Store. Unfortunately I have not received a response and the app has not been updated. (article updated, see below)

I would still suggest buying the premium version of the app if you are going to use premium features. It’s a great working app and well worth the 99 cents.

If you make premium features and you want to make sure people aren’t directly editing your settings, do not just disable the settings dialog, but also confirm in the app itself whether the right options are chosen. Even better would be to completely remove unused functionality: this would also decrease the app’s download size (only removing is probably a bit more work).

By all means, make sure that people are not able to use a setting that you don’t want them to use. This counts for a lot of things in security though, and sometimes people tend to forget this, also often on website dropdown forms.
 
Update 16/08/2015: I received a reply from the developer. He wrote (click here for all):

“I read your blog entry 🙂 Nice job. Just one thing. The trick you explained, about the language, is not accurate. You transformed the language setting from EN to EN;NL (both English and Dutch). But it is permitted in the free version. Both languages are already here and can be selected together. A real hack would have been turning EN to DE or FR (not allowed in the free version for you).
About Addic7ed credentials, filling them doesn’t overcome the limitation (10 per day). It just allows premium users to have a better quota on this site. It could be a real pain to be unlimited on MightySubs but limited on Addic7ed.

Anyway your demonstration is accurate, the hack is real and I should fix that.”

He says that both English and Dutch are permitted in the free version, but Dutch was not available for me and it showed a message “Purchase the premium version to get more languages”. Any how, it doesn’t matter, as it is possible to change it to whatever language you want including DE;FR (I tested it).
I wasn’t aware that the account details didn’t bypass the limitation, however in the file above there is also a string called PrefDailyDownloadCounter which probably counts the number of subtitles downloaded so far. I did not test it, but resetting it to zero after ten downloads would probably work.

The developer further wrote that he will bring out a new version in September with new features. Hopefully this hack is also fixed by then.

Domain registrar Versio.nl: is it really that cheap?

For this blog I needed two new domains, thijsbroenink.com and thijsbroenink.nl. Having a few domains at TransIP already, I wondered if there isn’t a registrar that offers the same services as TransIP for a lower price. After some searching, https://versio.nl came up as competitor.

Until recently I always registered my domains at https://transip.nl. They offer a nice simple customer panel with great support for a reasonable price: a .nl domain costs €3,99 first year and €7,49 each year after.

Versio offers .nl domains for €3,24 first year, and €3,99 for each following year. They offer .com domains for €8,49 first year, and €8,99 each next year. TransIP indeed seems the more expensive one for long term: TransIP costs €3,99 (€7,49 next year) for .nl, and €7,99 (€9,99 next year) for .com. By transferring all my domains over from TransIP to Versio I could really save some bucks.

However, versio.nl isn’t as cheap as they tell you.

  1. Their prices are without 21% taxes (btw). After selecting my .nl and .com domain, the price suddenly went up with 4 euros.
  2. They charge you for each paying method. iDeal is the most common way to pay in web shops in the Netherlands, but they charge you an extra 1 euro for this. Same thing for Paypal, credit card and all other payment methods.
  3. I chose for Paypal as it had the lowest price with 80 cents. The Paypal login form said at the bottom: “You won’t directly confirm your order; you can check your order at the webshop’s website before placing it”. Well, not with Versio. I logged in and instantly payed them and registered my domains. No time for second thoughts.
  4. This one surprised me the most: I registered both .nl and .com domains at the same time, yet my .com domain suspends one month earlier than my .nl domain! Apparently each .com domain you register at Versio is only for 11 months, not for a full year.
    I asked Versio for a comment and they said it it’s their cancel-period, they need to know if it will be extended a month before experiation to discuss with their supplier.
 Versio says one year; they mean 11 months.

So folks, what do we learn here? If you go for Versio, be sure you know what kind of company you’re dealing with so you don’t get disappointed. Despite all above, .nl domains are still cheap there; just remember taxes and transaction costs are not included in the price.

For .com domains: do not register them at Versio. You won’t pay for a full year but for 11 months, and with €8,99 they are definitely not the cheapest. A better choice would be https://transip.nl: they offer .com for €7,99 (€9,99 next year) for a full year.

Oh, and if you are considering their hosting plans: make sure you read this first.

Now let’s hope they won’t suspend my domains…