One thing that confused me was that the author talks about using "Good Boy Ninja’s method for talking to Gumroad’s API," which I thought meant that they were relying on undocumented behavior of the API. That would explain why Gumroad was so cavalier about breaking existing clients who relied on this method.
I checked Gumroad's API documentation[0] and found that the product_permalink and increment_uses_count parameters weren't documented. Then I checked the Wayback Machine for the documentation at the time the exploit was discovered[1], and those parameters were documented, so the author was relying on documented, supported behavior.
Given this, Gumroad breaking all their clients with only two weeks' notice over the holidays and offering only a $500 bounty feels pretty disrespectful.
I obviously don't know about Gumroad's internals, but nothing about the original API semantics seems inherently insecure to me. Why couldn't they have just verified that the entity that owns the license key also owns the permalink? It feels like Gumroad just chose the fix that minimized work on their end while pushing a lot of work onto their API consumers and those consumers' clients.
Huh. So gumroad verification is a simple call to the verify endpoint and I'm guessing if it returns "success": true that's good enough to enable usage of the product?
I guess it would be an interesting experiment to create a proxy that captures any values going out to gumroad's license verification api endpoint and change all server responses to be true instead of false. Ditto for altering the number of uses of a product in case there is a limit there too.
Also for anyone who is new to this topic, intercepting and altering server responses can yield fascinating results in today's client side heavy code web apps.
> I guess it would be an interesting experiment to create a proxy that captures any values going out to gumroad's license verification api endpoint and change all server responses to be true instead of false. Ditto for altering the number of uses of a product in case there is a limit there too.
I built that proxy server years ago and created fake responses for multiple licensing APIs provided by companies like Paddle, Setapp, MacPaw, Devmate, MacRabbit, GitTower, Gumroad, OmniGroup, among several others.
The proxy allowed me to use over 200 apps for free over the years. I tried to report this “vulnerability” (if we can call it that) to both Paddle and Setapp the same year I discovered them, but they never bothered to reply nor fix the problem. A couple of years ago, Paddle implemented a newer version of their API (v3) that uses SSL certificates and HTTP signatures to improve the security of their SDK, but I quickly found another way to bypass that protection.
To this day, even though I can easily pay for all those software licenses, I keep the proxy running because it makes it easy to visualize outbound network traffic and block unwanted HTTP requests from all the apps I use.
For example, how do you know that the setting to disable telemetry in that app you just installed actually disables telemetry? Even with a firewall like Little Snitch you can only allow/block domains/hostnames/ports but not individual API endpoints.
Sounds interesting. Did you publish the source code? I have no idea how something like this would be built, especially in a way that it allows checking on telemetry; would be interesting to look at it.
> Sounds interesting. Did you publish the source code?
Thanks, but no, I did not.
At the risk of sounding like a hypocrite, I do not want to enable other people to “steal” from these companies.
These companies surely do not care if I use their apps for me, because I am just one person among several thousand potential customers. However, if I publish the code, many of these potential customers may stop purchasing their software licenses or subscriptions, and I do not want to be responsible for their loss in revenue.
Also, I spent a lot of hours reverse engineering these apps and their corresponding APIs. I would not get anything out of publishing the code: it will not get me a better job, it will not get me clean money, it will not get me good publicity, it will do no good to anyone other than the people who want to use these apps for free without doing any work.
---
> I have no idea how something like this would be built, especially in a way that it allows checking on telemetry; would be interesting to look at it.
For the sake of learning, I will give you some hints: I originally used nginx, then I wrote my own Go program, and nowadays I use envoy proxy, but pretty much any proxy server will do the trick. Then, I created and installed my own Certificate Authority to automatically trust any self-signed certificate. Maybe you can use mkcert for that. That is the easy part. The difficult part(s), and the meat of the solution, is to reverse engineer every app to understand what and how it does things. I have used several disassemblers over the years but the one I like the most is Hopper Disassembler (https://www.hopperapp.com/). You may find API keys, public SSL certificates, JSON field names, form field names, etc. and you simply need to put the pieces together to re-implement the API endpoint(s) that the app expects to use.
Sometimes it is very easy, sometimes it is very difficult. You will learn a lot for sure.
> At the risk of sounding like a hypocrite, I do not want to enable other people to “steal” from these companies.
I can almost guarantee if you know about this others do too and will potentially sell or exploit it. I'd try reporting it again. Publishing it might ultimately get them to fix it, but is kind of the nuclear option.
"Everybody" (i.e., everybody who thinks about this for 20 seconds) knows about this. Licensing is a matter of throwing up enough roadblocks to prevent the majority of users from easily bypassing your checks. There is no way to stop a determined attacker. That effort is likely better spend on developing new features.
I wrote several 'licensing systems' over the years. It's a honey trap for developers - it's so easy to overthink it and spend months on 'hardening' your licensing, to the point where you have to check the generated assembly to see if your compiler doesn't do something clever where now all of a sudden 'cracking' your software turns into replacing a single JNZ instruction with a JMP. If you really 'need' protection against this, you use a 3rd party product which essentially converts your program into something that runs on their proprietary virtual machine.
But if you do online license checking - how do you even 'fix' this? It's trivial to MITM all requests. So now you have to obfuscate your API calls, put in extra layers of crypto, hide your private keys for that will enough in your machine code, ... All of which will be cracked by someone halfway experienced in a matter of days. I think it's most likely the companies the GP reported this to just decided it's best to not bother until they have actual proof that this is a wide enough spread problem for them to make it worth putting in significant dev resources (because it does require significant resources).
One thing I'd find very interesting is if you report somewhere any apps that send telemetry even though the telemetry option is disabled. As you say, little snitch can't completely help with this since we're still often forced to let the app verify it's registration information.
I wonder how many bad actors there are or if the vast majority of apps are trustworthy.
> That is an interesting moral code you have. You will help MindGeek improve their efficiency sexually exploiting children but you draw the line at publishing code for a proxy server. Fascinating! Thanks for sharing.
I do not work and have never worked at MindGeek. I do not know where you got that from.
You worked on analytics on MindGeek. I saw your username and name in a list of current and former MindGeek employees. You have written about it on your blog.
You’re right, you do sound like a hypocrite.. especially if you use any freely shared, open source software (in addition to the pirated software you proudly proclaimed to use).
Gumroad is part of a movement of “friendly” drm. You’re paying for support and updates. Intercepting a tls call is easier said than done, but the ethos is around accepting pirates gonna pirate.
Intercepting a TLS call is dead easy if you are one of the endpoints, namely the client. You can just add your proxy's certificate to the machines valid certs and bobs your uncle. Cert pinning is a thing but it can also be defeated, especially if all the app is doing it to pin cert is asking the OS TLS facilities nicely to pin a cert, because OS TLS facilities are also user-controlled.
Any shop worth their salt is going to embed the cert chain in their app. In fact, you get that for free with pretty much every drm lib, such as the ones major providers like steam, gumroad, etc suggest
Cert pinning can defeated, but like I said, easier said than done. Not super advanced, but still requires specialized knowledge and a willingness to put the effort in.
>I guess it would be an interesting experiment to create a proxy that captures any values going out to gumroad's license verification api endpoint and change all server responses to be true instead of false. Ditto for altering the number of uses of a product in case there is a limit there too.
You don't need to create a custom proxy for that.
There are many general-purpose tools that will let you inspect/modify HTTP/HTTPS traffic between your browser and a remote server:
> You don't need to create a custom proxy for that.
Wrong, you still need a custom proxy server for this to work.
The programs you suggested only help to (temporarily) inspect the Request/Response, as you say, but you would need to manually modify the responses every time they come through the proxy, which could easily translate to hundreds of requests per day while using a single app. Surely no one wants to have to sit there modifying every single HTTP request while using an app like Adobe Photoshop.
Instead, what you want is to inspect these requests/responses once using one of those programs you suggested, and then immediately translate your findings into a permanent API endpoint in your custom proxy server, which is constantly running in the background. This way you can use the app as any other user and the app will think that it is communicating with the real (remote) API.
Your suggestion to use either Burp Suite, Charles Proxy, or mitmproxy only helps if the app you are trying to crack checks for a valid license once in its entire installation lifetime. Unfortunately, the great majority of apps out there try to validate the license every few days, hours, and even minutes, for example, Sublime Text sends a request to license[.]sublimehq[.]com/check/<license> several times in a day.
>The programs you suggested only help to (temporarily) inspect the Request/Response, as you say, but you would need to manually modify the responses every time they come through the proxy, which could easily translate to hundreds of requests per day while using a single app. Surely no one wants to have to sit there modifying every single HTTP request while using an app like Adobe Photoshop.
The tools I mentioned all support rules for automatically modifying requests/responses. Most of them support custom scripting as well.
>Wrong, you still need a custom proxy server for this to work.
Not sure why the rudeness here. I'm just sharing some useful tools that would be easier to use than writing an entire HTTP proxy from scratch.
You'll certainly have more power writing a custom proxy from scratch, but off-the-shelf HTTP proxying tools are a good start for someone exploring this space.
I suppose there could be a challenge token from the product that compares the server response token to an internally generated token, but at the end of the day the product is in the hands of the user, and someone determined to steal it is going to steal it. The only way to really ensure the license is not broken is to do essential work on the server. What am I missing?
In this case, I don't know what Gumroad could do given that it's ExtendScript. But I can totally see Gumroad making a library for more supported ecosystems and an api endpoint that makes use of public/private key encryption to create a "signed" response. Naive possibility:
Gumroad receives request from app -> Gumroad crafts response, encrypts with private key (could be Gumroad key or a dev generated key), base64 it, returns to app -> Local library decrypts with public key and then verifies response.
This of course doesn't stop someone from messing with source code and "cracking" the app, but in the case of a binary based app, that's not as straightforward.
That said, another commenter did mention that pirates are gonna pirate, so friendly easy DRM for the dev also makes sense.
At the end of the day the scripts being sold are extend script which is interpreted, so pirates can always just open the script with a text editor, go to the "verifyLicence" function and trucate it to "return true". I think it's just not part of the threat model.
I love these types of hacks, it's super simple and easy to understand, yet it goes undiscovered for a long time because no one wondered "what if?". Great work!
On a slightly unrelated topic, I clicked through to the 'Type' page out of curiosity. The 36 second sales pitch is absolutely amazing, 0 filler content or sales speak. Makes me sad that I have absolutely no need for it.
Still, how much they pay their developers a year? Would be over $150k I imagine, drop him $10k which he deserves and a sincere apology and we never would have seen this article, this would definitely cause a larger loss for them.
I'm not too surprised. Gumroad was bought by venture capital, found not profitable enough. Bought back by the founder. And maintained by a lightweight team.
> Fees on Gumroad are simple: When you make a sale, we charge a 10% fee. This does not include credit card processing or PayPal fees. There are no monthly payments or other hidden charges.
https://backed.by launched yesterday. It's a decentralized Patreon competitor that only takes 1%
I actually want to make a dedicated post about it cause it seems like an actually interesting utility of web3, but I also know a lot of people might just see web3 and automatically downvote.
Does it support real currency too? Doesn't matter what the cut is if it's a percentage of $0/month
E: the getting started page could do with being whittled down, linking someone to this and still expecting donations is ambitious! https://backed.by/pages/get-started
Indeed. I think it should be $1250 minimum, which would be a week's pay at a $65000 salary.
I think they might have kept it below $600 because of the IRS's $600 threshold* which to me is tantamount to them deciding not to pay a real bug bounty.
That is still low because of the unpredictability. It might take weeks of work across many sites to find a bug. So the bounty needs to be high to compensate for that, if it is to be a career.
I think you're vastly overestimating the sophistication of the average (and even above-average) plugin (eco)system. Most are just DLL's that call some predefined functions.
Besides - network access is one of the most basic functionalities of any scripting in 2023 (it was in 2013, too). How would one disallow a simple call like in the OP? I mean, they use curl to make it (even) easier to craft an HTTP call, but doing the same from straight system calls is trivial, too.
The high end VFX industry has some of the most hostile DRM one can think up, to the point that moving on from x86 macOS is going to be a major pain because half of the DRM rootkits will stop working.
The bug and low bounty are unsurprising given that their largest sellers probably don't use the API, and Sahil does not seem to take Gumroad that seriously as a company (More like his personal playground which happens to throws off crazy cash).
One of the best things about this article, aside from confirming that the Gumroad API has always seemed surprisingly fragile for a company that’s so widely used, is the link to a possibly better alternative service.
All of the “suggestions” involve letting a pretty nasty bug persist in the wild. I can see why time was of the essence for them. Backlash from knowingly letting a bug be in production and exploitable would probably mean even bigger problems for them. Holidays? Too bad so sad. Maybe the author here should have waited until January to tell them about it… asks for urgent attention to a bug right before the holidays. Gets surprised when the urgent bug is fixed urgently. I don’t understand people anymore.
It was a month after I reported it. So not actually fixed urgently. And I didn't mind fixing it over the holidays, but a pain to explain it my end users over the holidays.
I moved away from Gumroad for various reasons, it seems like most of their efforts are going towards the marketing side (rebranding/landing page) and the product is good to get started with, but in the end it ends up being too limited/simple for more serious stuff when compared to Stripe or Paddle.
I checked Gumroad's API documentation[0] and found that the product_permalink and increment_uses_count parameters weren't documented. Then I checked the Wayback Machine for the documentation at the time the exploit was discovered[1], and those parameters were documented, so the author was relying on documented, supported behavior.
Given this, Gumroad breaking all their clients with only two weeks' notice over the holidays and offering only a $500 bounty feels pretty disrespectful.
I obviously don't know about Gumroad's internals, but nothing about the original API semantics seems inherently insecure to me. Why couldn't they have just verified that the entity that owns the license key also owns the permalink? It feels like Gumroad just chose the fix that minimized work on their end while pushing a lot of work onto their API consumers and those consumers' clients.
[0] https://app.gumroad.com/api#licenses
[1] https://web.archive.org/web/20221107215637/https://app.gumro...