mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2025-09-19 04:06:18 +08:00
fix(security): zip slip (#1228)
* fix(security): Zip Slip * chore:remove repeat clean * fix: archives,iso9660 and rardecode module --------- Co-authored-by: ILoveScratch <ilovescratch@foxmail.com>
This commit is contained in:
@ -1,10 +1,11 @@
|
||||
package archives
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
stdpath "path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/archive/tool"
|
||||
@ -107,7 +108,7 @@ func (Archives) Decompress(ss []*stream.SeekableStream, outputPath string, args
|
||||
}
|
||||
if stat.IsDir() {
|
||||
isDir = true
|
||||
outputPath = stdpath.Join(outputPath, stat.Name())
|
||||
outputPath = filepath.Join(outputPath, stat.Name())
|
||||
err = os.Mkdir(outputPath, 0700)
|
||||
if err != nil {
|
||||
return filterPassword(err)
|
||||
@ -120,11 +121,14 @@ func (Archives) Decompress(ss []*stream.SeekableStream, outputPath string, args
|
||||
return err
|
||||
}
|
||||
relPath := strings.TrimPrefix(p, path+"/")
|
||||
dstPath := stdpath.Join(outputPath, relPath)
|
||||
dstPath := filepath.Join(outputPath, relPath)
|
||||
if !strings.HasPrefix(dstPath, outputPath+string(os.PathSeparator)) {
|
||||
return fmt.Errorf("illegal file path: %s", relPath)
|
||||
}
|
||||
if d.IsDir() {
|
||||
err = os.MkdirAll(dstPath, 0700)
|
||||
} else {
|
||||
dir := stdpath.Dir(dstPath)
|
||||
dir := filepath.Dir(dstPath)
|
||||
err = decompress(fsys, p, dir, func(_ float64) {})
|
||||
}
|
||||
return err
|
||||
|
@ -1,10 +1,11 @@
|
||||
package archives
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
fs2 "io/fs"
|
||||
"os"
|
||||
stdpath "path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/errs"
|
||||
@ -69,7 +70,11 @@ func decompress(fsys fs2.FS, filePath, targetPath string, up model.UpdateProgres
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.OpenFile(stdpath.Join(targetPath, stat.Name()), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
||||
destPath := filepath.Join(targetPath, stat.Name())
|
||||
if !strings.HasPrefix(destPath, targetPath+string(os.PathSeparator)) {
|
||||
return fmt.Errorf("illegal file path: %s", stat.Name())
|
||||
}
|
||||
f, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package iso9660
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
stdpath "path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/archive/tool"
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/errs"
|
||||
@ -79,7 +81,11 @@ func (ISO9660) Decompress(ss []*stream.SeekableStream, outputPath string, args m
|
||||
}
|
||||
if obj.IsDir() {
|
||||
if args.InnerPath != "/" {
|
||||
outputPath = stdpath.Join(outputPath, obj.Name())
|
||||
rootpath := outputPath
|
||||
outputPath = filepath.Join(outputPath, obj.Name())
|
||||
if !strings.HasPrefix(outputPath, rootpath+string(os.PathSeparator)) {
|
||||
return fmt.Errorf("illegal file path: %s", obj.Name())
|
||||
}
|
||||
if err = os.MkdirAll(outputPath, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
package iso9660
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
stdpath "path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/errs"
|
||||
@ -62,7 +63,11 @@ func toModelObj(file *iso9660.File) model.Obj {
|
||||
}
|
||||
|
||||
func decompress(f *iso9660.File, path string, up model.UpdateProgress) error {
|
||||
file, err := os.OpenFile(stdpath.Join(path, f.Name()), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
||||
destPath := filepath.Join(path, f.Name())
|
||||
if !strings.HasPrefix(destPath, path+string(os.PathSeparator)) {
|
||||
return fmt.Errorf("illegal file path: %s", f.Name())
|
||||
}
|
||||
file, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -84,7 +89,10 @@ func decompressAll(children []*iso9660.File, path string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nextPath := stdpath.Join(path, child.Name())
|
||||
nextPath := filepath.Join(path, child.Name())
|
||||
if !strings.HasPrefix(nextPath, path+string(os.PathSeparator)) {
|
||||
return fmt.Errorf("illegal file path: %s", child.Name())
|
||||
}
|
||||
if err = os.MkdirAll(nextPath, 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package rardecode
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
stdpath "path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/archive/tool"
|
||||
@ -93,7 +93,7 @@ func (RarDecoder) Decompress(ss []*stream.SeekableStream, outputPath string, arg
|
||||
}
|
||||
} else {
|
||||
innerPath := strings.TrimPrefix(args.InnerPath, "/")
|
||||
innerBase := stdpath.Base(innerPath)
|
||||
innerBase := filepath.Base(innerPath)
|
||||
createdBaseDir := false
|
||||
for {
|
||||
var header *rardecode.FileHeader
|
||||
@ -115,7 +115,7 @@ func (RarDecoder) Decompress(ss []*stream.SeekableStream, outputPath string, arg
|
||||
}
|
||||
break
|
||||
} else if strings.HasPrefix(name, innerPath+"/") {
|
||||
targetPath := stdpath.Join(outputPath, innerBase)
|
||||
targetPath := filepath.Join(outputPath, innerBase)
|
||||
if !createdBaseDir {
|
||||
err = os.Mkdir(targetPath, 0700)
|
||||
if err != nil {
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
stdpath "path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@ -124,7 +124,7 @@ type WrapFileInfo struct {
|
||||
}
|
||||
|
||||
func (f *WrapFileInfo) Name() string {
|
||||
return stdpath.Base(f.File.Name)
|
||||
return filepath.Base(f.File.Name)
|
||||
}
|
||||
|
||||
func (f *WrapFileInfo) Size() int64 {
|
||||
@ -183,12 +183,16 @@ func getReader(ss []*stream.SeekableStream, password string) (*rardecode.Reader,
|
||||
|
||||
func decompress(reader *rardecode.Reader, header *rardecode.FileHeader, filePath, outputPath string) error {
|
||||
targetPath := outputPath
|
||||
dir, base := stdpath.Split(filePath)
|
||||
dir, base := filepath.Split(filePath)
|
||||
if dir != "" {
|
||||
targetPath = stdpath.Join(targetPath, dir)
|
||||
err := os.MkdirAll(targetPath, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
targetPath = filepath.Join(targetPath, dir)
|
||||
if strings.HasPrefix(targetPath, outputPath+string(os.PathSeparator)) {
|
||||
err := os.MkdirAll(targetPath, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
targetPath = outputPath
|
||||
}
|
||||
}
|
||||
if base != "" {
|
||||
@ -201,7 +205,11 @@ func decompress(reader *rardecode.Reader, header *rardecode.FileHeader, filePath
|
||||
}
|
||||
|
||||
func _decompress(reader *rardecode.Reader, header *rardecode.FileHeader, targetPath string, up model.UpdateProgress) error {
|
||||
f, err := os.OpenFile(stdpath.Join(targetPath, stdpath.Base(header.Name)), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
||||
destPath := filepath.Join(targetPath, filepath.Base(header.Name))
|
||||
if !strings.HasPrefix(destPath, targetPath+string(os.PathSeparator)) {
|
||||
return fmt.Errorf("illegal file path: %s", filepath.Base(header.Name))
|
||||
}
|
||||
f, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
package tool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
stdpath "path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenListTeam/OpenList/v4/internal/model"
|
||||
@ -40,13 +41,13 @@ func GenerateMetaTreeFromFolderTraversal(r ArchiveReader) (bool, []model.ObjTree
|
||||
isNewFolder := false
|
||||
if !file.FileInfo().IsDir() {
|
||||
// 先将 文件 添加到 所在的文件夹
|
||||
dir = stdpath.Dir(name)
|
||||
dir = filepath.Dir(name)
|
||||
dirObj = dirMap[dir]
|
||||
if dirObj == nil {
|
||||
isNewFolder = dir != "."
|
||||
dirObj = &model.ObjectTree{}
|
||||
dirObj.IsFolder = true
|
||||
dirObj.Name = stdpath.Base(dir)
|
||||
dirObj.Name = filepath.Base(dir)
|
||||
dirObj.Modified = file.FileInfo().ModTime()
|
||||
dirMap[dir] = dirObj
|
||||
}
|
||||
@ -64,28 +65,28 @@ func GenerateMetaTreeFromFolderTraversal(r ArchiveReader) (bool, []model.ObjTree
|
||||
dirMap[dir] = dirObj
|
||||
}
|
||||
dirObj.IsFolder = true
|
||||
dirObj.Name = stdpath.Base(dir)
|
||||
dirObj.Name = filepath.Base(dir)
|
||||
dirObj.Modified = file.FileInfo().ModTime()
|
||||
}
|
||||
if isNewFolder {
|
||||
// 将 文件夹 添加到 父文件夹
|
||||
// 考虑压缩包仅记录文件的路径,不记录文件夹
|
||||
// 循环创建所有父文件夹
|
||||
parentDir := stdpath.Dir(dir)
|
||||
parentDir := filepath.Dir(dir)
|
||||
for {
|
||||
parentDirObj := dirMap[parentDir]
|
||||
if parentDirObj == nil {
|
||||
parentDirObj = &model.ObjectTree{}
|
||||
if parentDir != "." {
|
||||
parentDirObj.IsFolder = true
|
||||
parentDirObj.Name = stdpath.Base(parentDir)
|
||||
parentDirObj.Name = filepath.Base(parentDir)
|
||||
parentDirObj.Modified = file.FileInfo().ModTime()
|
||||
}
|
||||
dirMap[parentDir] = parentDirObj
|
||||
}
|
||||
parentDirObj.Children = append(parentDirObj.Children, dirObj)
|
||||
|
||||
parentDir = stdpath.Dir(parentDir)
|
||||
parentDir = filepath.Dir(parentDir)
|
||||
if dirMap[parentDir] != nil {
|
||||
break
|
||||
}
|
||||
@ -127,7 +128,7 @@ func DecompressFromFolderTraversal(r ArchiveReader, outputPath string, args mode
|
||||
}
|
||||
} else {
|
||||
innerPath := strings.TrimPrefix(args.InnerPath, "/")
|
||||
innerBase := stdpath.Base(innerPath)
|
||||
innerBase := filepath.Base(innerPath)
|
||||
createdBaseDir := false
|
||||
for _, file := range files {
|
||||
name := file.Name()
|
||||
@ -138,7 +139,7 @@ func DecompressFromFolderTraversal(r ArchiveReader, outputPath string, args mode
|
||||
}
|
||||
break
|
||||
} else if strings.HasPrefix(name, innerPath+"/") {
|
||||
targetPath := stdpath.Join(outputPath, innerBase)
|
||||
targetPath := filepath.Join(outputPath, innerBase)
|
||||
if !createdBaseDir {
|
||||
err = os.Mkdir(targetPath, 0700)
|
||||
if err != nil {
|
||||
@ -159,12 +160,16 @@ func DecompressFromFolderTraversal(r ArchiveReader, outputPath string, args mode
|
||||
|
||||
func decompress(file SubFile, filePath, outputPath, password string) error {
|
||||
targetPath := outputPath
|
||||
dir, base := stdpath.Split(filePath)
|
||||
dir, base := filepath.Split(filePath)
|
||||
if dir != "" {
|
||||
targetPath = stdpath.Join(targetPath, dir)
|
||||
err := os.MkdirAll(targetPath, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
targetPath = filepath.Join(targetPath, dir)
|
||||
if strings.HasPrefix(targetPath, outputPath+string(os.PathSeparator)) {
|
||||
err := os.MkdirAll(targetPath, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
targetPath = outputPath
|
||||
}
|
||||
}
|
||||
if base != "" {
|
||||
@ -185,7 +190,11 @@ func _decompress(file SubFile, targetPath, password string, up model.UpdateProgr
|
||||
return err
|
||||
}
|
||||
defer func() { _ = rc.Close() }()
|
||||
f, err := os.OpenFile(stdpath.Join(targetPath, file.FileInfo().Name()), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
||||
destPath := filepath.Join(targetPath, file.FileInfo().Name())
|
||||
if !strings.HasPrefix(destPath, targetPath+string(os.PathSeparator)) {
|
||||
return fmt.Errorf("illegal file path: %s", file.FileInfo().Name())
|
||||
}
|
||||
f, err := os.OpenFile(destPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
Reference in New Issue
Block a user