6 ms·
How does this exploit work? Or do you have a link to a rundown of it?
by j-bos 3y ago
How does this exploit work? Or do you have a link to a rundown of it?
- tptacek 3y agoI'm guessing here, because I only read a high-level description of it, but I think it's a password reset flow endpoint that takes the email address to look up and send a reset to, and the framework will accept an array instead of a simple string; the endpoint looks up the first address, but the variable used to determine who to send the reset mail to is the array. Again: just a guess as to the underlying bug (I've seen that specific bug before is why I guessed).
- nightpool 3y agoThis is correct: The vulnerability lies in the management of emails when resetting passwords. An attacker can provide 2 emails and the reset code will be sent to both. It is therefore possible to provide the e-mail address of the target account as well as that of the attacker, and to reset the administrator password. Here's an example payload: user[email][]=my.target@example.com&user[email][]=hacker@evil.com (per this POC github: https://github.com/Vozec/CVE-2023-7028 https://github.com/Vozec/CVE-2023-7028)
- tptacek 3y agoYep, so it's the classic Rails bug pattern.
- chatmasta 3y agoThis is such a rarely used feature that I wonder if it would be helpful to have a CSP or preflight header that restricts the browser from sending multiple values for the same parameter.
- janpieterz 3y agoIf you'd want to configure this you'd probably want it as some kind of configuration in the backend that disables it.
- 5- 3y agoa browser is typically not used to exploit this class of bugs.
- chatmasta 3y agoThere is precedent for deputizing the browser to stop this kind of bug with Access-Control-Allow-Headers. If the backend wants to default to ignoring multiple GET/POST parameters with the same name, then the browser could helpfully fail to make a request that attempts to send them.
- talkin 3y agoThe attacker doesnt’t use a compliant browser to make the request. User agent protections only help in situations where a regular user (or their software) is being tricked
- tptacek 3y agoIt's pretty commonly used in Rails form handling logic though, isn't it?
- jeremymcanally 3y agoProperly used white list parameter controls (i.e., strong parameters) that are the default Rails behavior at this point would have prevented this bug completely.
- tptacek 3y agoThis is a little like saying the best way to avoid this bug is to not have the bug. But that's true of all bugs. The C apologists used to say, "just bounds check properly!"
- technion 3y agoStrong parameters has been a core security feature of rails for a long time, and all the guides go into detail about the boilerplate you need just to accept a form input past the strong parameter filters. It's weird to me that the pattern doesn't also include a "must he a string" option. I know you can add to_s everywhere, but making it part of the existing strong params would actually incentivise use.
- kevinmchugh 3y agoIt's weird, as I recall with strong params one of the only things it really makes you decide is whether a value is a scalar, array, or Hash. You can certainly allow a value to be scalar or array, but it's not very natural in strong params. I mostly hate the way strong params gets used - it's a bad compromise between letting Ruby people do Ruby things and trying to plug up a category of vulnerability that's been biting rails apps for a decade. Now I do all my api definitions in openapi and it's way easier. I haven't tried it with a rails app but I think it'd work well there.
- simonw 3y agoA tiny little piece of Django design that I'm pleased to have participated in is this: emails = request.POST.getlist("email") Django doesn't mix lists and single string values, because I'd been burned by that problem in PHP.
- EGreg 3y agowait, what do you mean by in PHP?
- stephenr 3y agoIn php it would be trivial (and expected) to have a `string` type on a parameter that's expected to be a string - thus negating this issue. But then using the email address from the request rather than the already verified address in the DB seems like a weird design decision to me anyway.
- tzs 3y agoI think I'd count that as a bug and a design error. The bug is accepting an array when it should only take a scalar. The design error is that the endpoint should not be taking email addresses at all. It should take account IDs. Even if a system uses email addresses as account IDs they are conceptually not the same and the code should not muddle them. Keep them separate and then even if you get an "allows an array where it should have been a scalar" bug the result should be either just the first account in the array gets a reset email or all the accounts in the array that are existing accounts get reset emails for their accounts.
- tptacek 3y agoUsers hate this, because it requires them to do two email round trips (the first to recover the account ID).
- tzs 3y agoI think it is OK to call the account ID "Email Address" on everything the user sees, and make it the same string as the user's email address. As far as the user is concerned they login with email address and password. I'm just saying that in the software and in the database store account ID and email separately. Treat the fact that the account ID column matches the email address column as just a coincidence that you do not take advantage of. I'd enforce not taking advantage of it by having employee accounts actually use an account ID that does not match their email address, such as their name, so that if we accidentally leave out a call to EmailFromAccountID(...) somewhere and try to use an account ID directly as an email address it will break employee accounts. Also, it is not clear to me that even with user visible account ID that is not the same as email address that it would take two email rounds trips. The reset page could take email address, not account ID. The reset endpoint could then look up the account ID from the email address, and initiate the reset, calling the SendEmailToAccount service with the account ID to send the email. That service would look up the email address for the account.
- tptacek 3y agoOh, sure. Storing the email address in a canonical column and using the provided address as a key helps. But I think the underlying bug is still there, because the email code will still _accept_ the user input if you feed that to it.