diff --git a/archetype/eureka.go b/archetype/eureka.go index 5486b7e..952e4f6 100644 --- a/archetype/eureka.go +++ b/archetype/eureka.go @@ -89,12 +89,12 @@ func (self *EurekaAdapter) ListPages() map[string]string { } func (self *EurekaAdapter) GetPage(filename string) Page { - if strings.Contains(filename, "../") || strings.Contains(filename, "..\\") { + fullPath := filepath.Join(self.Root, "inc", filename) + if !strings.HasPrefix(filepath.Clean(fullPath), self.Root) { return Page{ Error: "You cannot escape!", } } - fullPath := filepath.Join(self.Root, "inc", filename) f, err := os.ReadFile(fullPath) if err != nil { @@ -199,8 +199,8 @@ func (self *EurekaAdapter) CreatePage(slug, title, content string) error { slug = strings.ToLower(strings.ReplaceAll(title, " ", "_")) + ".htm" path := filepath.Join(self.Root, "inc", slug) - if strings.Contains(slug, "../") || strings.Contains(slug, "..\\") { - return errors.New("You cannot escape!") + if !strings.HasPrefix(filepath.Clean(path), self.Root) { + errors.New("You cannot escape!") } _, err := os.Stat(path) @@ -220,8 +220,11 @@ func (self *EurekaAdapter) SavePage(oldSlug, newSlug, title, content string) err // eureka creates titles from slugs, so we transform the title into the slug newSlug = strings.ToLower(strings.ReplaceAll(title, " ", "_")) + ".htm" - if strings.Contains(newSlug, "../") || strings.Contains(newSlug, "..\\") || - strings.Contains(oldSlug, "../") || strings.Contains(oldSlug, "..\\") { + oldPath := filepath.Join(self.Root, "inc", oldSlug) + newPath := filepath.Join(self.Root, "inc", newSlug) + + if !strings.HasPrefix(filepath.Clean(oldPath), filepath.Join(self.Root, "inc")) || + !strings.HasPrefix(filepath.Clean(newPath), filepath.Join(self.Root, "inc")) { return errors.New("You cannot escape!") } @@ -249,15 +252,16 @@ func (self *EurekaAdapter) SavePage(oldSlug, newSlug, title, content string) err } func (self *EurekaAdapter) DeletePage(slug string) error { - if strings.Contains(slug, "../") || strings.Contains(slug, "..\\") { - return errors.New("You cannot escape!") - } - siteRoot := self.Config[ConfigOption{ Name: "SITEROOT", Type: "string", }] htmlFile := filepath.Join(self.Root, siteRoot, slug+"l") + + if !strings.HasPrefix(filepath.Clean(htmlFile), filepath.Join(self.Root, siteRoot)) { + return errors.New("You cannot escape!") + } + _, err := os.Stat(htmlFile) if !os.IsNotExist(err) { os.Remove(htmlFile) diff --git a/archetype/fileManager.go b/archetype/fileManager.go index 5fd5538..6b99bcd 100644 --- a/archetype/fileManager.go +++ b/archetype/fileManager.go @@ -54,13 +54,13 @@ func (self *SimpleFileManager) Init(cfg *Config) error { func (self *SimpleFileManager) ListSubTree(root string) FileListing { list := FileListing{} - if strings.Contains(root, "../") || strings.Contains(root, "..\\") { + fullPath := filepath.Join(self.Root, root) + + if !strings.HasPrefix(filepath.Clean(fullPath), self.Root) { list.Error = "You cannot escape!" return list } - fullPath := filepath.Join(self.Root, root) - files, err := ioutil.ReadDir(fullPath) if err != nil { @@ -114,7 +114,7 @@ func (self *SimpleFileManager) GetFileData(slug string) FileData { Error: err.Error(), } } - if !strings.HasPrefix(fullPath, self.Root) { + if !strings.HasPrefix(filepath.Clean(fullPath), self.Root) { return FileData{ Error: "You cannot escape!", } @@ -133,29 +133,31 @@ func (self *SimpleFileManager) GetFileData(slug string) FileData { func (self *SimpleFileManager) Remove(slug string) error { fullPath := filepath.Join(self.Root, slug) - _, err := os.Stat(fullPath) + if !strings.HasPrefix(filepath.Clean(fullPath), self.Root) { + return errors.New("You cannot escape!") + } + + _, err := os.Stat(fullPath) if err != nil { return err } - if !strings.HasPrefix(fullPath, self.Root) { - return errors.New("You cannot escape!") - } return os.RemoveAll(fullPath) } func (self *SimpleFileManager) AddFile(path string, req *http.Request) error { fullPath := filepath.Join(self.Root, path) + + if !strings.HasPrefix(filepath.Clean(fullPath), filepath.Clean(self.Root)) { + return errors.New("You cannot escape!") + } + _, err := os.Stat(fullPath) if err != nil { return err } - if !strings.HasPrefix(fullPath, filepath.Clean(self.Root)) { - return errors.New("You cannot escape!") - } - req.ParseMultipartForm(self.maxUploadMB << 20) file, header, err := req.FormFile("file") if err != nil { @@ -180,7 +182,7 @@ func (self *SimpleFileManager) AddFile(path string, req *http.Request) error { func (self *SimpleFileManager) MkDir(path, newDir string) error { fullPath := filepath.Join(self.Root, path) - if !strings.HasPrefix(fullPath, self.Root) { + if !strings.HasPrefix(filepath.Clean(fullPath), self.Root) { return errors.New("You cannot escape!") } @@ -204,12 +206,21 @@ func (self *SimpleFileManager) MkDir(path, newDir string) error { func (self *SimpleFileManager) Rename(oldFullPath, newPath, newName string) error { fullPath := filepath.Join(self.Root, oldFullPath) + + if !strings.HasPrefix(filepath.Clean(fullPath), self.Root) { + return errors.New("You cannot escape!") + } + _, err := os.Stat(fullPath) if err != nil { return err } - newParent := filepath.Join(self.Root, newPath) + newParent := filepath.Clean(filepath.Join(self.Root, newPath)) + if !strings.HasPrefix(newParent, self.Root) { + return errors.New("You cannot escape!") + } + _, err = os.Stat(newParent) if err != nil { return err @@ -220,6 +231,11 @@ func (self *SimpleFileManager) Rename(oldFullPath, newPath, newName string) erro newName = oldName } + newFullPath := filepath.Join(newParent, newName) + if !strings.HasPrefix(filepath.Clean(newFullPath), newParent) { + return errors.New("You cannot escape!") + } + return os.Rename(fullPath, filepath.Join(newParent, newName)) }