@@ -19,19 +19,75 @@ package cmd
1919
2020import (
2121 "bytes"
22+ "context"
2223 "fmt"
2324 "io"
2425 "net/http"
26+ "net/http/httptest"
2527 "reflect"
28+ "runtime"
2629 "strconv"
2730 "testing"
2831
2932 "github.com/klauspost/compress/s2"
33+ "github.com/minio/minio/internal/auth"
3034 "github.com/minio/minio/internal/config/compress"
3135 "github.com/minio/minio/internal/crypto"
3236 "github.com/minio/pkg/trie"
3337)
3438
39+ // Wrapper
40+ func TestPathTraversalExploit (t * testing.T ) {
41+ if runtime .GOOS != globalWindowsOSName {
42+ t .Skip ()
43+ }
44+ defer DetectTestLeak (t )()
45+ ExecExtendedObjectLayerAPITest (t , testPathTraversalExploit , []string {"PutObject" })
46+ }
47+
48+ // testPathTraversal exploit test, exploits path traversal on windows
49+ // with following object names "\\../.minio.sys/config/iam/${username}/identity.json"
50+ // #16852
51+ func testPathTraversalExploit (obj ObjectLayer , instanceType , bucketName string , apiRouter http.Handler ,
52+ credentials auth.Credentials , t * testing.T ,
53+ ) {
54+ if err := newTestConfig (globalMinioDefaultRegion , obj ); err != nil {
55+ t .Fatalf ("Initializing config.json failed" )
56+ }
57+
58+ objectName := `\../.minio.sys/config/hello.txt`
59+
60+ // initialize HTTP NewRecorder, this records any mutations to response writer inside the handler.
61+ rec := httptest .NewRecorder ()
62+ // construct HTTP request for Get Object end point.
63+ req , err := newTestSignedRequestV4 (http .MethodPut , getPutObjectURL ("" , bucketName , objectName ),
64+ int64 (5 ), bytes .NewReader ([]byte ("hello" )), credentials .AccessKey , credentials .SecretKey , map [string ]string {})
65+ if err != nil {
66+ t .Fatalf ("failed to create HTTP request for Put Object: <ERROR> %v" , err )
67+ }
68+
69+ // Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic ofthe handler.
70+ // Call the ServeHTTP to execute the handler.
71+ apiRouter .ServeHTTP (rec , req )
72+
73+ ctx , cancel := context .WithCancel (GlobalContext )
74+ defer cancel ()
75+
76+ // Now check if we actually wrote to backend (regardless of the response
77+ // returned by the server).
78+ z := obj .(* erasureServerPools )
79+ xl := z .serverPools [0 ].sets [0 ]
80+ erasureDisks := xl .getDisks ()
81+ parts , errs := readAllFileInfo (ctx , erasureDisks , bucketName , objectName , "" , false )
82+ for i := range parts {
83+ if errs [i ] == nil {
84+ if parts [i ].Name == objectName {
85+ t .Errorf ("path traversal allowed to allow writing to minioMetaBucket: %s" , instanceType )
86+ }
87+ }
88+ }
89+ }
90+
3591// Tests validate bucket name.
3692func TestIsValidBucketName (t * testing.T ) {
3793 testCases := []struct {
0 commit comments