Live data from Hacker News

Remote Code Execution on a Facebook server

blog.scrt.ch

31–40 of 207 posts

Re: Remote Code Execution on a Facebook server

#31

This is a great concrete example why you should never run debug mode on a public server. Django can only do so much for redacting private info. This is also a great example of how insecure pickle is!

Luckily, Django provides checks to avoid this kind of leakage before hitting production with https://docs.djangoproject.com/en/2.1/howto/deployment/check...

wow thanks - just ran this on some production servers and caught some intersting stuff! had no clue this command existed.

Re: Remote Code Execution on a Facebook server

#32
post #28

Wow, a fix in <24 hours, that's pretty impressive.

I mean the fix is toggling a single environmental variable from True to False, on a system that isn't normally accessed by customers, so the risk is really small in rolling out the change.

Sometimes you’re lucky if a company reads your report in this time but of course I would expect and we generally see much better from the likes of Facebook etc

Re: Remote Code Execution on a Facebook server

#33
post #2

So, this was simply taking advantage of a crash-prone webapp running on a debug-enabled Django instance using Pickle session serialization, and more specifically this was only possible because _Django didn't redact the stored secret key used to sign serialized inputs out of the crashdump information!_ Did the author tell Django about this yet, or is this a (possibly unintentional) 0-day? Besides the above interesting…

Maybe I misunderstood the article, but I thought it said that Django does strip this information, and the Sentry app went out of its way to store the secret key in the SENTRY_OPTIONS payload. This custom, non-Django code effectively circumvents Django’s protections, making the bug the responsibility of Sentry, not Django.

Ah. You're right, I completely got this bit wrong. Thanks.

Wait, so that means Sentry kind of has a vulnerability.

Re: Remote Code Execution on a Facebook server

#34

Earlier quoted context omitted.

I tend to agree w/ the FB security team here. Don't list email addresses owned by an adversary in your account. :-/

> Don't list email addresses owned by an adversary in your account. I mean if you're delegating your email address, your staff aren't adversaries. But they shouldn't be able to, say, drain all your retirement accounts either. Just because I want people who search for alex.krupp@gmail.com to be able to find my Facebook account doesn't mean I want password reset requests sent there. It wouldn't be at all unreasonable t…

Even if they changed it so that you could select where to send the password reset, rather than having it go by default to all accounts, that still means anyone with delegate access to the email address could go and request a reset on your behalf.

Re: Remote Code Execution on a Facebook server

#35
post #23

Other than fixing the Django source code , is there any OS level mitigation techniques that can detect and prevent such security vulnerabilities? I am thinking something like selinux, docker or chroot - a bit like internal firewall for Django (or any other webapp). Any suggestions on the links to latest best practices?

It seems unlikely. The application has a feature to use a secret key to secure everything. The same application then prints out the secret key to anyone that asks. Your OS can't do much about that.

Maybe if you tell your OS "never let any data containing this string leave the machine" you can kind of mitigate this, but it's unlikely to work. The HTTP response is probably compressed. Someone probably base64-encoded the thing and stuck it inside some JSON, which is then base64-encoded again.

Ultimately, it's about managing complexity. Django and the extension punted: Django says it will print anything and everything it has access to, and the extension has a documentation caveat about how bad that would be. One could imagine an API that tries to be resistant to this sort of thing; when the extension is initialized, it deletes the key from the environment dictionary (only partially possible), stores it in a private attribute, and only provides public EncryptAndSignCookie and DecryptAndVerifyCookie methods. This will be better than a documentation caveat, maybe, but the truly ambitious debug mode will probably get the key and print it out.

(I would also point out that I'm not a fan of storing state in encrypted+signed cookies, if only because there is no way to revoke a stolen cookie without revoking every cookie ever. If you have the state on the server to store a revocation list, you might as well just store everything there and never have this problem.)

Re: Remote Code Execution on a Facebook server

#36
post #34

Earlier quoted context omitted.

> Don't list email addresses owned by an adversary in your account. I mean if you're delegating your email address, your staff aren't adversaries. But they shouldn't be able to, say, drain all your retirement accounts either. Just because I want people who search for alex.krupp@gmail.com to be able to find my Facebook account doesn't mean I want password reset requests sent there. It wouldn't be at all unreasonable t…

Even if they changed it so that you could select where to send the password reset, rather than having it go by default to all accounts, that still means anyone with delegate access to the email address could go and request a reset on your behalf.

> that still means anyone with delegate access to the email address could go and request a reset on your behalf.

That's how it should work. You shouldn't have to remember which email address you signed up with in order to request a password reset. But that's fine as long as the pin number only gets sent to an account that's locked down to a degree that's appropriate relative to the assets under protection.

Re: Remote Code Execution on a Facebook server

#37
post #23

Other than fixing the Django source code , is there any OS level mitigation techniques that can detect and prevent such security vulnerabilities? I am thinking something like selinux, docker or chroot - a bit like internal firewall for Django (or any other webapp). Any suggestions on the links to latest best practices?

There's nothing to be done at the OS level, because the OS doesn't know which things are secret and which things aren't. You can sandbox the Django process (and to a certain extent Facebook were doing this at an even higher level, by having the whole server on a separate VLAN that was (supposedly) away from the important stuff) but that only does so much because the process needs to have enough access to do whatever it was intended to do.

Ultimately the only thing you can do is not run debug mode in production, not use insecure serialization formats and not leak secret keys. If you want to be a bit more pre-emptive about it, avoid language-specific serialization formats especially in dynamic languages ("serialization" that executes arbitrary code seems more common in those) and use taint checking or, better, a type system that can avoid leaking secrets (you likely need rank-2 types to be able to have values that you can use in certain contexts but never access outside them, a la http://okmij.org/ftp/Computation/resource-aware-prog/region-... ). It sounds like Django already has some level of taint-like functionality but this plugin/addon (sentry) then didn't use it properly. So, multiple failures interacting to create this vulnerability - I guess we should take that as a sign of progress compared to the days of basic buffer overflows?

Re: Remote Code Execution on a Facebook server

#38
post #5

In contrast, I submitted a bad vulnerability in Facebook’s password reset feature yesterday that lets attacker’s send password reset PIN numbers to email addresses the user doesn’t necessarily control. The security team said to works as designed so they’re not going to fix it. Basically if someone requests a password reset on your account then the PIN number gets sent to all email addresses associated with your accou…

This does sound like a reasonable feature request to me: the "contact information" and "account recovery" use cases are different, and it's not obvious that an email listed for one should be automatically used for the other. They could have you choose for each email whether it's allowed to be used for account recovery.

As an analogous example, what if you did the "forgot my password" flow and they sent a recovery code over SMS to any listed phone number on your profile, sent a twitter DM to your listed twitter account, and sent postal mail to any postal address on your profile? (All at once, without waiting or confirmation.) That would expand the attack surface significantly, and it would be pretty easy to steal someone's account by stealing their postal mail. This case is similar: a secure email for account recovery and a less secure email for contact info, but Facebook forces you to use both for account recovery.

On the other hand, some people intentionally want multiple account recovery emails so they're less likely to lose access to their account. I imagine Facebook's hesitation with this feature is that it's hard to clearly communicate the distinction between the two use cases, and they want to bias toward simplicity.

Re: Remote Code Execution on a Facebook server

#39
post #32
post #28

Earlier quoted context omitted.

I mean the fix is toggling a single environmental variable from True to False, on a system that isn't normally accessed by customers, so the risk is really small in rolling out the change.

Sometimes you’re lucky if a company reads your report in this time but of course I would expect and we generally see much better from the likes of Facebook etc

You're right, being able to read, triage and act on something in such a massive system is quiet the accomplishment.

Re: Remote Code Execution on a Facebook server

#40
post #23

Other than fixing the Django source code , is there any OS level mitigation techniques that can detect and prevent such security vulnerabilities? I am thinking something like selinux, docker or chroot - a bit like internal firewall for Django (or any other webapp). Any suggestions on the links to latest best practices?

Doesn't seem to be a Django problem, as the author says

> wow, it looks like it’s a sort of Django SECRET-KEY override!

Sentry uses its "own" secret key, so Django doesn't know it should be stripped from the stacktrace.

A simple `DEBUG = False` in `settings.py` would fix the bug. You don't have Django run in debug mode in production.

Post reply on HN