Skip to content
This repository has been archived by the owner on Nov 19, 2024. It is now read-only.

fix: prevent extraction of archived files outside target path #65

Merged
merged 2 commits into from
Apr 17, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions archiver.go
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ import (
"os"
"path/filepath"
"runtime"
"strings"
)

// Archiver represent a archive format
@@ -105,3 +106,14 @@ func mkdir(dirPath string) error {
}
return nil
}

func sanitizeExtractPath(filePath string, destination string) error {
// to avoid zip slip (writing outside of the destination), we resolve
// the target path, and make sure it's nested in the intended
// destination, or bail otherwise.
destpath := filepath.Join(destination, filePath)
if !strings.HasPrefix(destpath, destination) {
return fmt.Errorf("%s: illegal file path", filePath)
}
return nil
}
5 changes: 4 additions & 1 deletion cmd/archiver/main.go
Original file line number Diff line number Diff line change
@@ -27,7 +27,10 @@ func main() {
}
err = ff.Make(filename, os.Args[3:])
case "open":
dest := ""
dest, osErr := os.Getwd()
if osErr != nil {
fatal(err)
}
if len(os.Args) == 4 {
dest = os.Args[3]
} else if len(os.Args) > 4 {
13 changes: 10 additions & 3 deletions rar.go
Original file line number Diff line number Diff line change
@@ -72,8 +72,15 @@ func (rarFormat) Read(input io.Reader, destination string) error {
return err
}

err = sanitizeExtractPath(header.Name, destination)
if err != nil {
return err
}

destpath := filepath.Join(destination, header.Name)

if header.IsDir {
err = mkdir(filepath.Join(destination, header.Name))
err = mkdir(destpath)
if err != nil {
return err
}
@@ -82,12 +89,12 @@ func (rarFormat) Read(input io.Reader, destination string) error {

// if files come before their containing folders, then we must
// create their folders before writing the file
err = mkdir(filepath.Dir(filepath.Join(destination, header.Name)))
err = mkdir(filepath.Dir(destpath))
if err != nil {
return err
}

err = writeNewFile(filepath.Join(destination, header.Name), rr, header.Mode())
err = writeNewFile(destpath, rr, header.Mode())
if err != nil {
return err
}
15 changes: 11 additions & 4 deletions tar.go
Original file line number Diff line number Diff line change
@@ -219,15 +219,22 @@ func untar(tr *tar.Reader, destination string) error {

// untarFile untars a single file from tr with header header into destination.
func untarFile(tr *tar.Reader, header *tar.Header, destination string) error {
err := sanitizeExtractPath(header.Name, destination)
if err != nil {
return err
}

destpath := filepath.Join(destination, header.Name)

switch header.Typeflag {
case tar.TypeDir:
return mkdir(filepath.Join(destination, header.Name))
return mkdir(destpath)
case tar.TypeReg, tar.TypeRegA, tar.TypeChar, tar.TypeBlock, tar.TypeFifo:
return writeNewFile(filepath.Join(destination, header.Name), tr, header.FileInfo().Mode())
return writeNewFile(destpath, tr, header.FileInfo().Mode())
case tar.TypeSymlink:
return writeNewSymbolicLink(filepath.Join(destination, header.Name), header.Linkname)
return writeNewSymbolicLink(destpath, header.Linkname)
case tar.TypeLink:
return writeNewHardLink(filepath.Join(destination, header.Name), filepath.Join(destination, header.Linkname))
return writeNewHardLink(destpath, filepath.Join(destination, header.Linkname))
default:
return fmt.Errorf("%s: unknown type flag: %c", header.Name, header.Typeflag)
}
5 changes: 5 additions & 0 deletions zip.go
Original file line number Diff line number Diff line change
@@ -187,6 +187,11 @@ func unzipAll(r *zip.Reader, destination string) error {
}

func unzipFile(zf *zip.File, destination string) error {
err := sanitizeExtractPath(zf.Name, destination)
if err != nil {
return err
}

if strings.HasSuffix(zf.Name, "/") {
return mkdir(filepath.Join(destination, zf.Name))
}