So nice I did it twice. “Hacking” the OnePlus reservation system, again.

Jake Cooper
Aug 4, 2015 · 5 min read

Studying for finals is overrated right? Yea it is.

Preface : If you haven’t, you’re probably gonna wanna read my other article ( before you read this one. Also, I’ve open sourced the script from the first article as it appears to be patched. Hopefully people can learn from it, or even just understand how I did it.

This morning I received an email from OnePlus saying that they were going to patch the exploit I detailed yesterday. Guess it’s time for round 2.

Amidst my search for hacks in my previous article, I discovered another trick that lead to a bigger and better hack. Gmail has what is called “Email aliasing”, which allows emails sent to a permutation of your Gmail to be forwarded to your Gmail. There exist 2 rules to this that I have heard of. The following 2 emails both forward to

  1. (Courtesy of /u/pyronautical on Reddit)

The first one is relatively simple, as it just truncates everything after the +. This was the first one I checked on OnePlus, but no dice, I was blocked by the OnePlus web client. I even tried to request straight to the server like last time. Again, no luck.

The second one proved to be a little more fruitful. OnePlus had done SOME validation, but had let some slide through. It turns out OnePlus WILL accept emails with periods (Which I knew, because mine has a couple), but there are again a couple of rules.

  1. The periods cannot occur at the start or end of the email.
  2. Two period cannot occur adjacent to one another in an email.

Now let’s this about this for a second : Given a N sized string, we know that, with (n-1) spaces in between the letters, there are 2^(n-1) permutations where the space between characters can be filled and produce unique strings. Take the string “test” :

test t.est tes.t te.s.t t.e.s.t

2^(4–1) = 8. I’d prove this by induction, but I said I wasn’t studying for finals, so let’s skip that (Sorry CSC225 prof).

My email actually has 16 characters not including periods. That means 2^(16–1) = 32768 possible combinations.

I’m fairly certain 30000+ referrals would put me at #1. For the purpose of this article I’m going to use a burner email with 8 characters, so 2^(7) = 128. Less, but still a shitload. Actually 127 because I need to use one to get my referral link.

Let’s start with some code to build the permutations :

Recursion is hard.

The above works. @SamuelMaskell on Twitter beat me to figuring it out, so he gets credit for it.

Now onto the fun part. So now we want to send an email to each of those emails. We can reuse the code from last time :

Last time I forgot .format, this time I did not.

Use sleep(5) because OnePlus’ servers run on hamsters and I’m against animal cruelty.

This is why we can’t have nice things

I ran my code twice, and about 50% of the requests timed out at sleep(2). I’m not gonna re-run it with sleep(5) because it’s late, but you get the gist of it : All the emails filter right into a single inbox. Isn’t it beautiful?

So now you have 2^(n-1) emails in your inbox ideally. You COULD click through them all, but if you’re anything like me, you’re probably incredibly lazy.

You know what time it is?

Enter Python, again. Specifically, the IMAP library.

So this is the basic structure of the IMAP application. Line 1 sets up the IMAP gmail, line 4 sets your username and password, and the rest is mostly error checking. Lets move on to processMailbox.

Now this was a pain in the ass. We use the to initialize the mailbox, then we use to set the filter to only show emails with the Subject set to “Confirm your email”. We then iterate through each of these emails in the first for loop. There’s a crapload of encoding and decoding that goes on in the following lines, but msg ends up useful at the end of it.

The responses are stored as “payloads” : Some emails have multiple payloads, others have one. Using the if statement we can accurately break it down and process the two possibilities. For our purposes, you’ll never actually hit the else statement, but it’s there if you need it.

manipulatePayload is where the magic happens. The 2nd variable (True) in get_payload() is actually a built-in decode function, which saves me from doing .decode(). For the record, either works here. Using the regex, I’m able to pull the confirmation URL out of the email, and then send a request to it, exactly like last time.

The end result :

I am why you can’t have nice things

It’s not as low as my other attempt, only because I don’t want to run the script for longer as it’s already 4AM and I need to get up earlyish tomorrow to demo an app for the aforementioned 225 prof.

That’s about it, thanks for tuning in again!

Jake Cooper

Written by

Hi I'm Jake, I build things. Caffeine connoisseur, nerd shirt enthusiast, and craft beer snob.