mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-07-25 13:37:51 +00:00
Merge pull request #1370 from aptly-dev/fix/path-traversal
fix path traversal
This commit is contained in:
+8
-5
@@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/aptly-dev/aptly/utils"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/saracen/walker"
|
"github.com/saracen/walker"
|
||||||
)
|
)
|
||||||
@@ -72,7 +73,7 @@ func apiFilesUpload(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
path := filepath.Join(context.UploadPath(), c.Params.ByName("dir"))
|
path := filepath.Join(context.UploadPath(), utils.SanitizePath(c.Params.ByName("dir")))
|
||||||
err := os.MkdirAll(path, 0777)
|
err := os.MkdirAll(path, 0777)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -128,7 +129,7 @@ func apiFilesListFiles(c *gin.Context) {
|
|||||||
|
|
||||||
list := []string{}
|
list := []string{}
|
||||||
listLock := &sync.Mutex{}
|
listLock := &sync.Mutex{}
|
||||||
root := filepath.Join(context.UploadPath(), c.Params.ByName("dir"))
|
root := filepath.Join(context.UploadPath(), utils.SanitizePath(c.Params.ByName("dir")))
|
||||||
|
|
||||||
err := filepath.Walk(root, func(path string, _ os.FileInfo, err error) error {
|
err := filepath.Walk(root, func(path string, _ os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -164,7 +165,7 @@ func apiFilesDeleteDir(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := os.RemoveAll(filepath.Join(context.UploadPath(), c.Params.ByName("dir")))
|
err := os.RemoveAll(filepath.Join(context.UploadPath(), utils.SanitizePath(c.Params.ByName("dir"))))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
AbortWithJSONError(c, 500, err)
|
AbortWithJSONError(c, 500, err)
|
||||||
return
|
return
|
||||||
@@ -179,12 +180,14 @@ func apiFilesDeleteFile(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !verifyPath(c.Params.ByName("name")) {
|
dir := utils.SanitizePath(c.Params.ByName("dir"))
|
||||||
|
name := utils.SanitizePath(c.Params.ByName("name"))
|
||||||
|
if !verifyPath(name) {
|
||||||
AbortWithJSONError(c, 400, fmt.Errorf("wrong file"))
|
AbortWithJSONError(c, 400, fmt.Errorf("wrong file"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := os.Remove(filepath.Join(context.UploadPath(), c.Params.ByName("dir"), c.Params.ByName("name")))
|
err := os.Remove(filepath.Join(context.UploadPath(), dir, name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err1, ok := err.(*os.PathError); !ok || !os.IsNotExist(err1.Err) {
|
if err1, ok := err.(*os.PathError); !ok || !os.IsNotExist(err1.Err) {
|
||||||
AbortWithJSONError(c, 500, err)
|
AbortWithJSONError(c, 500, err)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/aptly-dev/aptly/pgp"
|
"github.com/aptly-dev/aptly/pgp"
|
||||||
|
"github.com/aptly-dev/aptly/utils"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,6 +24,10 @@ func apiGPGAddKey(c *gin.Context) {
|
|||||||
if c.Bind(&b) != nil {
|
if c.Bind(&b) != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
b.Keyserver = utils.SanitizePath(b.Keyserver)
|
||||||
|
b.GpgKeyID = utils.SanitizePath(b.GpgKeyID)
|
||||||
|
b.GpgKeyArmor = utils.SanitizePath(b.GpgKeyArmor)
|
||||||
|
// b.Keyring can be an absolute path
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
args := []string{"--no-default-keyring", "--allow-non-selfsigned-uid"}
|
args := []string{"--no-default-keyring", "--allow-non-selfsigned-uid"}
|
||||||
|
|||||||
+10
-6
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/aptly-dev/aptly/deb"
|
"github.com/aptly-dev/aptly/deb"
|
||||||
"github.com/aptly-dev/aptly/pgp"
|
"github.com/aptly-dev/aptly/pgp"
|
||||||
"github.com/aptly-dev/aptly/task"
|
"github.com/aptly-dev/aptly/task"
|
||||||
|
"github.com/aptly-dev/aptly/utils"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -43,9 +44,10 @@ func getSigner(options *SigningOptions) (pgp.Signer, error) {
|
|||||||
return signer, nil
|
return signer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace '_' with '/' and double '__' with single '_'
|
// Replace '_' with '/' and double '__' with single '_', SanitizePath
|
||||||
func parseEscapedPath(path string) string {
|
func slashEscape(path string) string {
|
||||||
result := strings.Replace(strings.Replace(path, "_", "/", -1), "//", "_", -1)
|
result := strings.Replace(strings.Replace(path, "_", "/", -1), "//", "_", -1)
|
||||||
|
result = utils.SanitizePath(result)
|
||||||
if result == "" {
|
if result == "" {
|
||||||
result = "."
|
result = "."
|
||||||
}
|
}
|
||||||
@@ -86,7 +88,7 @@ func apiPublishList(c *gin.Context) {
|
|||||||
|
|
||||||
// POST /publish/:prefix
|
// POST /publish/:prefix
|
||||||
func apiPublishRepoOrSnapshot(c *gin.Context) {
|
func apiPublishRepoOrSnapshot(c *gin.Context) {
|
||||||
param := parseEscapedPath(c.Params.ByName("prefix"))
|
param := slashEscape(c.Params.ByName("prefix"))
|
||||||
storage, prefix := deb.ParsePrefix(param)
|
storage, prefix := deb.ParsePrefix(param)
|
||||||
|
|
||||||
var b struct {
|
var b struct {
|
||||||
@@ -113,6 +115,8 @@ func apiPublishRepoOrSnapshot(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.Distribution = utils.SanitizePath(b.Distribution)
|
||||||
|
|
||||||
signer, err := getSigner(&b.Signing)
|
signer, err := getSigner(&b.Signing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
AbortWithJSONError(c, 500, fmt.Errorf("unable to initialize GPG signer: %s", err))
|
AbortWithJSONError(c, 500, fmt.Errorf("unable to initialize GPG signer: %s", err))
|
||||||
@@ -248,9 +252,9 @@ func apiPublishRepoOrSnapshot(c *gin.Context) {
|
|||||||
|
|
||||||
// PUT /publish/:prefix/:distribution
|
// PUT /publish/:prefix/:distribution
|
||||||
func apiPublishUpdateSwitch(c *gin.Context) {
|
func apiPublishUpdateSwitch(c *gin.Context) {
|
||||||
param := parseEscapedPath(c.Params.ByName("prefix"))
|
param := slashEscape(c.Params.ByName("prefix"))
|
||||||
storage, prefix := deb.ParsePrefix(param)
|
storage, prefix := deb.ParsePrefix(param)
|
||||||
distribution := c.Params.ByName("distribution")
|
distribution := utils.SanitizePath(c.Params.ByName("distribution"))
|
||||||
|
|
||||||
var b struct {
|
var b struct {
|
||||||
ForceOverwrite bool
|
ForceOverwrite bool
|
||||||
@@ -373,7 +377,7 @@ func apiPublishDrop(c *gin.Context) {
|
|||||||
force := c.Request.URL.Query().Get("force") == "1"
|
force := c.Request.URL.Query().Get("force") == "1"
|
||||||
skipCleanup := c.Request.URL.Query().Get("SkipCleanup") == "1"
|
skipCleanup := c.Request.URL.Query().Get("SkipCleanup") == "1"
|
||||||
|
|
||||||
param := parseEscapedPath(c.Params.ByName("prefix"))
|
param := slashEscape(c.Params.ByName("prefix"))
|
||||||
storage, prefix := deb.ParsePrefix(param)
|
storage, prefix := deb.ParsePrefix(param)
|
||||||
distribution := c.Params.ByName("distribution")
|
distribution := c.Params.ByName("distribution")
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -343,8 +343,8 @@ func apiReposPackageFromDir(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dirParam := c.Params.ByName("dir")
|
dirParam := utils.SanitizePath(c.Params.ByName("dir"))
|
||||||
fileParam := c.Params.ByName("file")
|
fileParam := utils.SanitizePath(c.Params.ByName("file"))
|
||||||
if fileParam != "" && !verifyPath(fileParam) {
|
if fileParam != "" && !verifyPath(fileParam) {
|
||||||
AbortWithJSONError(c, 400, fmt.Errorf("wrong file"))
|
AbortWithJSONError(c, 400, fmt.Errorf("wrong file"))
|
||||||
return
|
return
|
||||||
@@ -620,8 +620,8 @@ func apiReposIncludePackageFromDir(c *gin.Context) {
|
|||||||
|
|
||||||
var sources []string
|
var sources []string
|
||||||
var taskName string
|
var taskName string
|
||||||
dirParam := c.Params.ByName("dir")
|
dirParam := utils.SanitizePath(c.Params.ByName("dir"))
|
||||||
fileParam := c.Params.ByName("file")
|
fileParam := utils.SanitizePath(c.Params.ByName("file"))
|
||||||
if fileParam != "" && !verifyPath(fileParam) {
|
if fileParam != "" && !verifyPath(fileParam) {
|
||||||
AbortWithJSONError(c, 400, fmt.Errorf("wrong file"))
|
AbortWithJSONError(c, 400, fmt.Errorf("wrong file"))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module github.com/aptly-dev/aptly
|
module github.com/aptly-dev/aptly
|
||||||
|
|
||||||
go 1.22
|
go 1.22.7
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AlekSi/pointer v1.1.0
|
github.com/AlekSi/pointer v1.1.0
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package utils
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
@@ -22,3 +23,12 @@ func DirIsAccessible(filename string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove leading '/', remove '..', '$' and '`'
|
||||||
|
func SanitizePath(path string) (result string) {
|
||||||
|
result = strings.Replace(path, "..", "", -1)
|
||||||
|
result = strings.Replace(result, "$", "", -1)
|
||||||
|
result = strings.Replace(result, "`", "", -1)
|
||||||
|
result = strings.TrimLeft(result, "/")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user