Page MenuHomePhabricator

CVE-2021-44856: Title blocked in AbuseFilter can be created via Special:ChangeContentModel due to the mishandling of EditFilterMergedContent hook return value
Closed, ResolvedPublicSecurity

Description

The EditFilterMergedContent hook in ContentModelChange class required returning false to interrupt edit action, but handling function of AbuseFilter don't have a return value.

So when use Special:ChangeContentModel in a non-existent title, it will create the page, while the AbuseFilter's log assumed the creation was blocked.

Event Timeline

Note that the handling of EditFilterMergedContent hook's return value in ContentModelChange class is different compare to which in EditFilterMergedContentHookConstraint class, should it to be modified or put up a warning to avoid such a mistake?

Returning false from the hook seems a good temporary solution, and I think it can be pushed publicly on gerrit, pretending it's some standardization / cleanup. But yes, core being inconsistent is the real problem.

Returning false from the hook seems a good temporary solution, and I think it can be pushed publicly on gerrit, pretending it's some standardization / cleanup. But yes, core being inconsistent is the real problem.

Yeah, core is really inconsistent. You can see the logic used for saving edits at EditFilterMergedContentHookConstraint. Note that switching to returning false might result in different behavior for saving edits, not sure since I'm not familiar enough with what AbuseFilter currently does in that hook

Returning false from the hook seems a good temporary solution, and I think it can be pushed publicly on gerrit, pretending it's some standardization / cleanup. But yes, core being inconsistent is the real problem.

Yeah, core is really inconsistent. You can see the logic used for saving edits at EditFilterMergedContentHookConstraint. Note that switching to returning false might result in different behavior for saving edits, not sure since I'm not familiar enough with what AbuseFilter currently does in that hook

OK, fair. I didn't check the core code, but then perhaps we can copy part of EditFilterMergedContentHookConstraint into ContentModelChange? Specifically the part which checks the Status.

Returning false from the hook seems a good temporary solution, and I think it can be pushed publicly on gerrit, pretending it's some standardization / cleanup. But yes, core being inconsistent is the real problem.

If return false, you should set $status->value after $status->merge( $filterResultApi ); manually, such as $status->value = MediaWiki\EditPage\IEditObject::AS_HOOK_ERROR_EXPECTED;.
I tested in my install of mw1.35, it's fine with edit and changecontentmodel both. But I wonder if that is a correct way to handle this hook?

I hope the code in ContentModelChange can be improved, because almost all hooks (originally) provide by EditPage.php support set Status object without return false.

I wonder if the intention with ignoring the status in ContentModelChange is to allow users to go (content1, model1) -> (content1, model2) -> (content2, model2) when there's no content that would be valid under both model1 and model2 so you couldn't otherwise get from one to the other.

On the net it still seems like a bad idea though. The API allows changing the content and the model at the same time, and it's a sufficiently infrequent problem that that should be a valid solution.

On the net it still seems like a bad idea though. The API allows changing the content and the model at the same time, and it's a sufficiently infrequent problem that that should be a valid solution.

Sorry for my poor english, what change should be done to solve this bug in your opinion?

This comment was removed by Func.

@matmarex , Changes related to T280312 can actually solve this security issue, so I considered doing backports.
I stopped creating backport changes now, If backports really shouldn't be done, please fell free to abandon them.

Extensions outside of our version control could also trigger this issue, right?

If so, it seems to me that it should be fixed in the ContentModelChange class, by changing the logic to match the EditFilterMergedContentHookConstraint class. And then that's the patch that should be backported.

And the required patch appears to be this:

Reedy renamed this task from Title which blocked in AbuseFilter can be create via Special:ChangeContentModel due to the mishandling of EditFilterMergedContent hook to Title which blocked in AbuseFilter can be created via Special:ChangeContentModel due to the mishandling of EditFilterMergedContent hook return value.Jul 12 2021, 3:37 PM

The security team would be happy to deploy this patch as soon as it can be reviewed by another person.

@Daimona @Func Are you able to have a look at the patch? It's very short and hopefully trivial.

Patch from T271037#7178772 was deployed during today's security window:

22:19 mstyles@deploy1002: Synchronized php-1.38.0-wmf.9/includes/content/ContentModelChange.php: Deploy security patch for T271037 (duration: 00m 56s)

Tracking as part of the next security release: T292226. We're not seeing any errors in logstash, but if other folks subscribed on this task could perform some additional verification that the patch is behaving properly within production, that'd be great.

sbassett changed Author Affiliation from N/A to Wikimedia Communities.
sbassett changed Risk Rating from N/A to Low.
Reedy renamed this task from Title which blocked in AbuseFilter can be created via Special:ChangeContentModel due to the mishandling of EditFilterMergedContent hook return value to Title blocked in AbuseFilter can be created via Special:ChangeContentModel due to the mishandling of EditFilterMergedContent hook return value.Dec 10 2021, 5:48 PM
Reedy assigned this task to matmarex.

Patch applies to all supported branches cleanly.

Reedy renamed this task from Title blocked in AbuseFilter can be created via Special:ChangeContentModel due to the mishandling of EditFilterMergedContent hook return value to CVE-2021-44856: Title blocked in AbuseFilter can be created via Special:ChangeContentModel due to the mishandling of EditFilterMergedContent hook return value.Dec 13 2021, 3:04 AM

Change 747574 had a related patch set uploaded (by Reedy; author: Bartosz Dziewoński):

[mediawiki/core@REL1_35] SECURITY: Fix use of EditFilterMergedContent hook when changing content model

https://gerrit.wikimedia.org/r/747574

Change 747581 had a related patch set uploaded (by Reedy; author: Bartosz Dziewoński):

[mediawiki/core@REL1_36] SECURITY: Fix use of EditFilterMergedContent hook when changing content model

https://gerrit.wikimedia.org/r/747581

Change 747588 had a related patch set uploaded (by Reedy; author: Bartosz Dziewoński):

[mediawiki/core@REL1_37] SECURITY: Fix use of EditFilterMergedContent hook when changing content model

https://gerrit.wikimedia.org/r/747588

Change 747599 had a related patch set uploaded (by Reedy; author: Bartosz Dziewoński):

[mediawiki/core@master] SECURITY: Fix use of EditFilterMergedContent hook when changing content model

https://gerrit.wikimedia.org/r/747599

Change 747574 merged by jenkins-bot:

[mediawiki/core@REL1_35] SECURITY: Fix use of EditFilterMergedContent hook when changing content model

https://gerrit.wikimedia.org/r/747574

Reedy changed the visibility from "Custom Policy" to "Public (No Login Required)".Dec 15 2021, 7:53 PM
Reedy changed the edit policy from "Custom Policy" to "All Users".

Change 747588 merged by jenkins-bot:

[mediawiki/core@REL1_37] SECURITY: Fix use of EditFilterMergedContent hook when changing content model

https://gerrit.wikimedia.org/r/747588

Change 747581 merged by jenkins-bot:

[mediawiki/core@REL1_36] SECURITY: Fix use of EditFilterMergedContent hook when changing content model

https://gerrit.wikimedia.org/r/747581

Change 747599 merged by jenkins-bot:

[mediawiki/core@master] SECURITY: Fix use of EditFilterMergedContent hook when changing content model

https://gerrit.wikimedia.org/r/747599