Reverse-engineering the Starbucks ordering API
blog.tendigi.com
blog.tendigi.com
1. Android typically is easier for this kind of work (you don't even need a rooted/jailbroken device, and it's all Java/smali),
2. That said, instead of installing an entire framework like Xposed that hooks the process to bypass certificate pinning, you can usually just decompile the APK and nop out all the function calls in the smali related to checking if the certificate is correct, then recompile/resign it for your device (again, easier on Android than iOS),
3. Request signing is increasingly implemented on APIs with any sort of business value, but you can almost always bypass it within an hour by searching through the application for functions related to things like "HMAC", figuring out exactly which request inputs are put into the algorithm in which order, and seeing where/how the secret key is stored (or loaded, as it were),
4. There is no true way to protect an API on a mobile app. You can only make it more or less difficult to secure. The best you can do is a frequently rotated secret key stored in shared libraries with weird parameters attached to the signing algorithm. To make up for this savvy companies typically reduce the cover time required (i.e. change the secret key very frequently by updating the app weekly or biweekly) or by using using a secret key with several parts generated from components in .so files, which are significantly more tedious to reverse.
While reversing Android apps, usually they are obfuscated ( I think it is included in the standard build process ), but when you are start to be familier with objective C (or swift) binaries there are really straight forward, with a nice disassembler and script, in my experience much faster.
Request signing, certificate pinning etc are not actually target at reverse engineers, more like to snoopers, replay attackers etc.
Also I agree with 4 totally, there is no point there, you should do your security on server side, instead of client side. (Except games I guess, which they can ban players etc, making it a cat and mouse game there can work pretty good actually)
Much harder targets, like obfuscated c++, or VMs (bytecode interpreters etc) usually helps with #4, but still then, it just slows down. (This slow down combined with regular changes in protection is basically targeted to make reverse engineers to give up)
Obfuscated control flow is like hell especially in c++ (ex: pokemon etc) but as I said I am comparing average android vs IOS. Once you have rooted platform you have much wider tool set of course.
I remember reading something years back about Java decompiling, and I believe it said that all Java code is decompileable except for inner classes and nested try-catch. Assuming my memory and the source are correct (which might not be the case), why hasn't it become standard practice for developers who don't want their app reverse-engineered to just put every class inside a wrapper class? I can imagine there could even be tools for doing this at compile time so that you wouldn't need to manually deal with the indirection when writing the code.
In general I have found that most smaller app developers don't obfuscate at all, and often you can find hardcoded keys/secrets in these smaller applications.
[1] https://developer.android.com/studio/build/shrink-code.html
https://www.acloudtree.com/hacking-java-bytecode-for-program...
As for nested try-catch... I don't see how that would be an issue unless the compiler somehow merges them into a single block. Which, as long as it's semantically equivalent, doesn't matter at all.
I could probably have gone deeper and found more functions to patch, but I don't know smali so everything was guessing and matching up to the java decompiled source (and the original source which seems to have been Moxie's?)
(>$100 billion company making the app with >1 million users.)
Edit: oh another trick usually works is to change transport to HTTP from HTTPS, just changing endpoint to something you control and changing it to http (with little hex editing the endpoint), and reverse proxy with mitmproxy/charles to the target, you can speed up process.
So basically for app endpoint will be charles/mitmproxy machine, then from there, you will make https request to real API server
https://casper.io/ is an example of doing this (for SnapChat) - they used to take registrations for their own API. Not sure how it's working out for them these days.
(but it was definitely easier than in the blog post!)
If you don't feel like RE'ing the API, you can always just supply the inputs to the app yourself from somewhere else. ("All problems in computer science can be solved by another level of indirection", as the saying goes.)
But...
Security depends on ‘sense of security’, when people think platform is more secure, they tend to ignore/skip a lot of parts on security. Developer tend to skip edge cases (such as pizza API in this thread). When they are developing on secure platforms, they tend to skip more.
For example if you are developing for not jailbroken platform, you trust platform DRM (mostly consoles), and skip a lot of parts, you put the certificate pinning, and call it a day. When platform is broken, you are totally exposed.
But when you are developing for web, you are exposed from the beginning, you dont have that sense of security anymore, so you try to fix all edge cases.
It's a very simple principle: the relevant data must necessarily be exposed, even if only in memory, at some point. Like any other DRM, it's imperfect.
It definitely didn't have 50x worth of bacon, but it did have more than 3x, maybe 5x-6x. The receipt was hilariously long though.
1. Our API had a hidden "tip" feature; we hadn't exposed it in the storefront yet, mostly because the developer in charge of it had left with it halfway finished, and nobody had picked it back up yet
2. But the API itself was perfectly functional. If you manually submitted an order to the API with a tip set, it would be reflected in the total, would bill your credit card, etc.
3. Except (I'm sure you saw where this is going...) the now-departed dev hadn't added any validation yet. So if you ordered $40 worth of pizza and added a negative $39 tip...boom, nearly free pizza.
We learned a few valuable lessons for the cost of buying a college student a couple of pizzas. :)
1 pizza with bacon, -1 pizza (without bacon?)
Then what, hope the employee reads -1 as 1 and doesn't cancel the order and call you to find out what you wanted?
I must be missing something...
One evening I ordered a pizza on-line to the office. I was too lazy to go out to the nearest grocery store (even if I knew which will be open at those hours) to buy a ketchup bottle, so in the form I added ~16x sachets of ketchup (figured it'll last me a while). I don't think it was more than 5 minutes after submitting the form that my phone rang, with the pizza guy on the other end asking if I really, really want 16 bags of ketchup?
1. First a payment collection flow is initiated from the browser (asking Credit Card details, pin etc)
2. The payment confirmation comes to the browser
3. The browser then places the order(the pizza information) to another api end point, marking the payment part as 'Paid'
The thing is, one could add as many pizzas to the cart in a different tab, while the original tab proceeds to payment. The end result is, you get to pay only for pizzas that were initially in the cart, but could get any number of pizzas. For literally Rs100 one could order thousands of rupees worth pizza.
I discovered it accidentally and did report to them. Neither did they acknowledge nor did they send me a free pizza :(
They later fixed this, by not allowing to load the cart in a different tab. But there is a high chance that there could be another hack even now. Since I had wowed not to eat junk food anymore, there was not much incentive for me to spend any more time on it.
There used to be some "secure pendrive" which worked similar way: an app asks you for password, checks if it matches hash stored on the drive and optionally commands the drive to unlock itself. What could possibly go wrong? ;)
I have to take issue with the "Starbucks app is great" line, though. I think I've had more problems with it (on iOS) than any other app. It's the only app that (for a period of many months if not a year) was regularly unable to find my location. Even if I opened up Maps or some other location enabled app and found my location before launching Starbucks, it would just bomb out.
Overall the app seems to have tons of 'issues'. It's been better the past few months though. And it beats the hell out of standing in a 10 minute line. I honestly wouldn't stop at Starbucks anymore if it wasn't for the app.
I spent like 20 minutes trying to order 5 drinks the other day. It was also annoying because when I left the app, all my selected items disappeared.
Additionally, if you think about the feature set that would be required to facilitate bulk orders then you will quickly find that it would be quite large feature set and require it's own flow. The app does has new-ish features that allow you to re-order prior orders and save drinks, which would help for these bulk orders, so they are making progress. If you are consistently ordering drinks for a large group of your co-workers then you can save their drink preferences and boom.
Whenever I try to order something through the starbucks app, I have to try multiple times because at some point in the ordering process the message, "unfortunately starbucks has stopped," or something like that will pop up and the app will close. Usually no progress is saved. Often it will crash right as it is processing the payment, and when I open it back up I have to go to the order history to check to see if it went through. Usually if I make it that far before it crashes then my order will have been submitted successfully.
I would love to be able to skip the UI and just submit my order an alternate way, but maybe the answer is to just stop being so cheap and to get a new phone.
I was ordering coffee and my balance wasn't quite sufficient. I reloaded it via PayPal, but the balance didn't update so I tried again (it did error out). The app crashed, I reopened it and found it had added both transactions to my account. Open dispute on PayPal for just one of the transactions, got a refund but my card was completely locked out - $0 balance, couldn't reload it (the dispute was after I tried contacting support). So now I don't go to Starbucks.
And yes, it makes the coffee taste better.
Oh btw, here are the auto-gen'd docs, hope those are enough"
That seems like it'd be both developer friendly and no more maintenance than they're already putting into it. The alternative is basically things like this, where someone figures it out anyway, and we have to wait and see if they play it cool, or take it badly and make the author take it down.
All you have to do is to say: "this is our internal API, we're releasing endpoint documentation for curious developers, but be warned, that the API may, and will, change without any notice".
I.e. when you're releasing something in the open, you don't have to take social responsibilities if you don't want to. It's not a binary choice between "release a fully supported product" and "don't release at all".
It would only really be used by enthusiasts and techies who are used to this sort of thing.
Remember the Snapchat leak from a few years ago?[1] I'd bet almost everyone who heard about the leak thought that Snapchat got hacked, and many then thought that their personal photos are not safe on Snapchat. But the reality is different. Users logged into a site called "Snapsave", many probably thinking it was part of Snapchat. It was Snapsave that used the private Snapchat API and got hacked... not Snapchat.
[1] http://www.huffingtonpost.com/2014/10/10/snapchat-leak_n_596...
"Underprotected APIs" is actually number 10 on the OWASP Top 10 for 2017.
Conceptually, it's just a listening server on the public Internet, and will be subject to arbitrary data anyone willing to connect to it can send.
With so many IoT devices out there relying on 3rd party web services that may or may not be around a year from now, I expect that the right to inspect and understand these APIs will become more and more important. Not to mention wanting the ability to build interactions between devices where the manufacturer may not have interest (IFTTT, etc).
I know of one website (site A) that sells items for sports and uses an API of a sports website (site B) to provide current statistics and other information.
Thing is, that sports website's API is now deprecated for public use, there's no way to request a token, and from what I can tell it's only to be used for commercial purposes/paid for by companies.
But, I can easily find the API token being used on site A, dig through the private/deprecated docs for the API of site B, and use any of their endpoints and data for pretty much whatever I want.
At least, this was the case roughly 4-6 months ago and I haven't looked into it since; perhaps they've changed it since then.
But I wonder how this works. Wouldn't it be a misuse of their API and something they wouldn't want allowed? Usually sports statistics APIs are fairly expensive, and the fact that some random person like me can get access easily for free seems unfair to site B, especially when they don't want normal people using their API anymore.
Generally, it’s a good idea to be protective, but between cert pinning and that encrypted device fingerprint and the time based signature, this adds a lot of points of possible failure to an app you want to be as available as possible to as many people as possible.
What information this API has access to is so precious to warrant all of this?
A real method of securing APIs would be a godsend, but in current tech it's just not possible. This is the one place where mediocre security-by-obscurity is your only choice =(
It's magically possible when tying it to a payment processor, though.
I might be slightly off because thinking about it the app probably requires up-front payment. But either way, fully open APIs can cause problems if they're more meant for internal processes
The problem is that their site TOS forbids reverse engineering, and I am afraid their lawyers will go after me instead of fixing the security issues (even if I just contact them), any tips for me ?
And yes of course you can also use Tor to contact them anonymously before disclosing.
Once you're in there you can just use the Tor browser to create an email account at any email provider (make sure you give them fake details though) and send your email.
Do not do anything without gaining permission, as there's a very good chance you're going to run into their legal team.
You mean, no TLS, JavaScript crypto and credit card info?
Are there no authorities to report that kind of garbage? No certification they are supposed to pass? I would research that angle first before hacking. It doesn't take any reversing to realize everyone can pwn you on a public WiFi.
Otherwise, at the very least use tor...
We experienced this at Honeywell, when I first started here we were blocking users that scraped the app instead of giving them public access and teach them how to use it correctly.
> Once you've obtained your client_id, client_secret
I'd like to use this module. Question for author: what's the fastest way to get a CLIENT_ID and CLIENT_SECRET?
The best part was when I contacted them afterwards and warned them about the extra pieces of info they had baked in, their response was basically "yeah, we're aware that there's more in there than there should be, but it's not a priority." Oh well, they just have all of my personal information.
- your old downstairs guy
CharlesProxy is a must-have whether you're a dev or reverse-engineering.
JADX is the best for reversing Android because it produces readable Android code which is fantastic for current Android developers who expect things to be organized like Android Studio.
If they pin certs it can be harder but not impossible.
If you want to get started, start by poking at something simple (e.g. your own app). Then google as you run into specific issues.
Well, now how am I supposed to tell him that Tully's is better?