The Info Op is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.
Looking for something fun to do in 2023? Why not learn how to hack mainframes ?
This container was built for our DEFCON 30 workshop. It will walk you through three challenging buffer overflows on a real mainframe OS. The first challenge is a simple C program buffer overflow, the second a buffer overflow and privesc and finally remote code execution over FTP.
It's trivial to determine the real IP of a Mastodon server behind Cloudflare. All it takes is one well-crafted request:
Detecting the real IP of a Cloudflare'd Mastodon instance
NB: This will not work for instances that proxy outgoing requests!
Reading the docs
I wanted to find a way to detect the real IP address of a Mastodon/Pleroma/Misskey/etc instance hosted behind Cloudflare. How to do that? Well, it's federated, which means I can probably get it to send a request to a server of mine! And how to do that? I tried reading the ActivityPub spec. The following caught my attention:
Servers should not trust client submitted content, and federated servers also should not trust content received from a server other than the content's origin without some form of verification.
It doesn't say anything about how servers should verify it. Naturally, you'd think verification has to involve a request to your instance, because how else could you prove that it's really mastodon.example.org sending an activity and not just some girl with curl? Mastodon docs elaborate on that. (sigh ActivityPub seems kinda pointless to me, given how almost everything you have to work with is a Mastodon/Pleroma/Misskey-specific extension.) Indeed, they tell us that each request is signed (using RSA-SHA256), and keys are fetched from remote servers. The Mastodon blog has a nice article with some details!
Now, it would be easier to do this with a GET request, since you don't have to deal with signing the body if you don't have one. I tried that, and Mastodon verifies the signature even if it doesn't really have to, e. g. for requests to publicly available data. But Pleroma doesn't, so I decided that POST requests are more reliable.
Applying our findings to the real world
The plan
Let's see what we need:
a Mastodon instance hosted behind Cloudflare,
a POST request that would require signature verification and
a server to which our target instance would connect to.
For the latter, anything that can store the request details will do. Note that we don't actually care about hosting real public keys, or providing signatures that make any sense: the instance won't be able to verify the signature before it fetches the key, so it will make a request regardless of whether the signature looks correct. And we don't care about anything that happens after.
A simple search led me to http://req, so I'll use it. It gives you a URL like https://httpreq.com/cutiful-trying-to-uncloudflare/record, requests to which will be logged and visible to you.
I decided to try to use that. I know, I'm silly, but Mastodon is forgiving. It tells me what to fix when I do silly things:
$ curl $ALL_THE_PARAMETERS_I_USED_IN_THE_PREVIOUS_COMMAND -H "Digest: SHA=thvDyvhfIqlvFe+A9MYgxAfm1q5=,unixsum=30637"
Mastodon requires the Digest header to be signed when doing a POST request
Wait, again? Oh, it is probably asking me to add the digest header to my signature: headers="(request-target) host date digest". Makes sense, because what is a signature worth if it signs the request headers but not its body? And then I got this in response: Mastodon only supports SHA-256 in Digest header. Offered algorithms: sha, unixsum. Well, guess I'll have to do a SHA-256 sum correctly instead of just taking examples from the RFC and hoping they'll work.
The only command line tool for calculating SHA256 hashes I know is sha256sum, but it outputs a sum in hex, and I need base64. This means I need to decode hex and send the binary data into base64. xxd can do just that, with -r. For some reason it wouldn't work, saying, sorry, cannot seek backwards., until I added a -p. I don't know what it does, and I don't really care.
This is how I'll generate the digest of my request body:
Yay, I got it to error! Probably has something to do with the fact that I don't actually serve any public keys at the public key URL. And now let's check http://req logs:
I wonder how many instance admins using Cloudflare know about this? My hunch is most do not, because the primary justification I see for using Cloudflare here is DDoS protection.
Cloudflare won't help if the attacker knows your origin IP, and you can't hide that with Cloudflare alone, due to the nature of ActivityPub.
Contrary to the popular opinion that algorithms are purely objective these models are opinions embedded in mathematics. ~ Cathy O'Neil's Weapons of Math Destruction