more robust path traversal prevention

This commit is contained in:
Iris Lightshard 2024-05-02 20:46:59 -06:00
parent 5b506f06d0
commit 2ed7370c2c
Signed by: nilix
GPG key ID: 688407174966CAF3
2 changed files with 44 additions and 24 deletions

View file

@ -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)

View file

@ -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))
}