Improper Access Control in splitbrain/dokuwiki
Reported on
Dec 16th 2021
Description
Users can access drafts of restricted files if they have create permissions on the same namespace and have the ability to create their own usernames due to the conflicting cache names. This can reveal draft contents, delete draft and overwrite the draft content of the restricted file.
Proof of Concept
1: User named admin creates a restricted file named secret on the root namespace (secret)
2: User named admin saves a draft of the secret file, this causes the draft file of the secret page to be generated as follows:
getCacheName($client.$ID, '.draft');
The parameter passed to getCacheName will be "admin"."secret" = "adminsecret".
3: The attacker can register user named "admins" and assuming they have create permissions on the same namespace they can create "ecret" (Important that ecret page is created in order to bypass some checks):
"admins"."ecret" = "adminsecret"
When this happens, the same parameter "adminsecret" is passed to getCacheName. And thus, the attacker named "admins" can access the draft information via http://[DOKU-URL]/doku.php?id=ecret&do=draft.
4: They can proceed to access draft content, delete draft and overwrite the draft content.
Impact
If registration is enabled and users are given create permissions on the same namespace as the restricted file, they can access draft information, overwrite draft information and even delete other users drafts of restricted pages.
Recommended Fix:
Instead of passing in directly the client name, instead hash the client name first (any hash algorithm will do!) Example:
md5(admin) => 21232f297a57a5a743894a0e4a801fc3
"21232f297a57a5a743894a0e4a801fc3"."secret" => "21232f297a57a5a743894a0e4a801fc3secret"
This works because hashes are of fixed length, hence there is no way to abuse this.
Ajax draftdel endpoint can be abused without create permissions.
Recommended Fix Update: MD5 doesn't seem to be collision resistant. It is possible that two different usernames will generate the same hash, but it is very unlikely that this occurs.
I suggest using SHA-2 hashes instead to avoid this possibility.
A lot of things have to come together to actually exploit this. First of all an attack like this only works while the privileged user is editing or for some reason abandoned a editing session in a non-normal way (like a browser crash). Drafts are usually very short lived.
Anyway, the problem is valid. I wonder if instead of hashing the user name, wouldn't it be enough to separate user and pageID by some separator? Preferably one that isn't allowed in page names (like a new line).