Skip to content

Latest commit

 

History

History
282 lines (255 loc) · 19 KB

vulnerabilities-workflow-1.md

File metadata and controls

282 lines (255 loc) · 19 KB

Here is the combined list of vulnerabilities, formatted as markdown with descriptions, impacts, ranks, mitigations, preconditions, source code analysis, and security test cases.

Combined Vulnerability List

Vulnerability 1: Path Traversal in BasePathFs

  • Vulnerability Name: Path Traversal in BasePathFs

  • Description:

    • An attacker can bypass the base path restriction imposed by BasePathFs and access files outside the intended directory.
    • This can be achieved by crafting paths with ".." sequences that, after initial cleaning by filepath.Clean, still allow traversal out of the base path when combined with the internal base path handling within BasePathFs.
    • The vulnerability arises because the RealPath function in BasePathFs only checks if the final joined path starts with the cleaned base path, but doesn't prevent path traversal within the name itself before joining.
  • Impact:

    • High
    • Unauthorized file system access: An attacker can read, and potentially modify or delete files outside the intended base path if the underlying filesystem and permissions allow it.
    • Information disclosure: Attackers can read sensitive files located outside the restricted directory.
    • Data integrity compromise: Attackers might be able to modify or delete files outside the base path.
  • Vulnerability Rank: High

  • Currently Implemented Mitigations:

    • None. The code attempts to restrict access using BasePathFs, but the current implementation is flawed and bypassable.
  • Missing Mitigations:

    • Stronger path validation in RealPath to prevent traversal beyond the intended base directory.
    • Implement checks to disallow ".." sequences within the input name before path joining.
    • Consider using secure path manipulation functions that prevent path traversal vulnerabilities.
  • Preconditions:

    • An application uses BasePathFs to restrict file system access to a specific directory.
    • The application allows user-controlled input to be used as file paths within the BasePathFs.
  • Source Code Analysis:

    • File: /code/basepath.go
    • Function: RealPath(name string) (path string, err error)
    func (b *BasePathFs) RealPath(name string) (path string, err error) {
        if err := validateBasePathName(name); err != nil { // [1] Validate base path name
            return name, err
        }
    
        bpath := filepath.Clean(b.path) // [2] Clean base path
        path = filepath.Clean(filepath.Join(bpath, name)) // [3] Join base path and name, and clean again
        if !strings.HasPrefix(path, bpath) { // [4] Check if the final path starts with the base path
            return name, os.ErrNotExist
        }
    
        return path, nil
    }
    • Step-by-step vulnerability analysis:

      1. validateBasePathName(name) [1]: This function performs basic validation, but it does not prevent path traversal sequences like "..". For non-windows OS it returns nil always.
      2. filepath.Clean(b.path) [2]: The base path is cleaned, which is good practice.
      3. filepath.Clean(filepath.Join(bpath, name)) [3]: The input name is joined with the base path and cleaned. However, if the name itself contains enough ".." sequences to traverse out of the bpath before the join and clean operation, this step can be bypassed.
      4. strings.HasPrefix(path, bpath) [4]: This check verifies if the final path starts with the base path. But if the traversal happens within name before joining, this check might still pass even if the effective path is outside the intended base directory.
    • Visualization: Imagine b.path is /restricted/base and attacker provides name as base/../sensitive/file.txt.

      1. bpath becomes /restricted/base (cleaned).
      2. path becomes filepath.Clean(filepath.Join("/restricted/base", "base/../sensitive/file.txt")) which simplifies to /restricted/sensitive/file.txt.
      3. strings.HasPrefix("/restricted/sensitive/file.txt", "/restricted/base") is TRUE. In this case, the vulnerability IS triggered and attacker can access file outside the base directory /restricted/base.

      The vulnerability occurs when the attacker can craft a path that, after joining with the base path and cleaning, still starts with the base path prefix but effectively points outside the intended base directory.

  • Security Test Case:

    • Step 1: Set up a MemMapFs as the base filesystem.
    • Step 2: Create a base directory /restricted/base within the MemMapFs.
    • Step 3: Create a sensitive file /sensitive/outside.txt outside the base directory in the MemMapFs with content "Sensitive Data".
    • Step 4: Create a BasePathFs instance with /restricted/base as the base path, using the MemMapFs as the source.
    • Step 5: Attempt to open and read the sensitive file using the BasePathFs with the path base/../sensitive/outside.txt.
    • Step 6: Verify that the content read from the opened file is "Sensitive Data", confirming path traversal vulnerability.
    package afero_test
    
    import (
        "bytes"
        "os"
        "testing"
    
        "github.com/spf13/afero"
    )
    
    func TestBasePathFsPathTraversal(t *testing.T) {
        baseFs := afero.NewMemMapFs()
        basePath := "/restricted/base"
        sensitiveFilePath := "/sensitive/outside.txt"
        sensitiveData := "Sensitive Data"
    
        // Setup base filesystem
        baseFs.MkdirAll(basePath, 0o777)
        baseFs.MkdirAll("/sensitive", 0o777)
        afero.WriteFile(baseFs, sensitiveFilePath, []byte(sensitiveData), 0o644)
    
        // Create BasePathFs
        bpFs := afero.NewBasePathFs(baseFs, basePath)
    
        // Attempt to open sensitive file using path traversal
        traversalPath := "base/../sensitive/outside.txt"
        f, err := bpFs.Open(traversalPath)
        if err != nil {
            t.Fatalf("Failed to open file with traversal path: %v", err)
        }
        defer f.Close()
    
        // Read the content of the opened file
        buf := new(bytes.Buffer)
        _, err = buf.ReadFrom(f)
        if err != nil {
            t.Fatalf("Failed to read file content: %v", err)
        }
    
        // Verify if sensitive data is accessed, indicating path traversal
        if buf.String() != sensitiveData {
            t.Errorf("Path traversal vulnerability not detected. Expected content: '%s', Got: '%s'", sensitiveData, buf.String())
        } else {
            t.Logf("Path traversal vulnerability successfully detected!")
        }
    }

Vulnerability 2: Predictable Temporary File Name Generation

  • Vulnerability Name: Predictable Temporary File Name Generation
  • Description:
    • The functions TempFile and TempDir (located in /code/util.go) derive a “random” suffix using an LCG (linear congruential generator) seeded with the current time and process ID.
    • Because this method is not cryptographically secure, an external attacker who can write to the system’s temporary directory may predict the temporary file or directory name before it is created.
    • By pre-creating (or pre-linking) the file under that name, the attacker can force file–hijacking or race–conditions.
  • Impact:
    • High
    • An attacker who successfully predicts the temporary file name may hijack sensitive file contents, force failures in file creation, or even influence application logic when temporary files are used in security‐sensitive contexts.
  • Vulnerability Rank: High
  • Currently Implemented Mitigations:
    • The code uses an exclusive creation flag (os.O_CREATE|os.O_EXCL) when opening temporary files.
  • Missing Mitigations:
    • A cryptographically secure random number generator is not used to produce the temporary suffix.
    • No atomic “check‐and‐create” mechanism is employed to hide the predictable randomness.
  • Preconditions:
    • The attacker must be able to write to (or influence) the temporary directory (typically the one returned by os.TempDir()).
    • The application uses these functions in a multiuser or publicly accessible environment.
  • Source Code Analysis:
    • In /code/util.go, the file–creation loop extracts a prefix and suffix from a pattern and then composes the file name by appending the result of nextRandom().
    • The helper function nextRandom() relies on a linear congruential update that makes future values predictable from the current seed.
    • Because the flag os.O_CREATE|os.O_EXCL only prevents overwrite of an already–existing file (and cannot stop an attacker from pre–creating the file), the predictable name leads to a security risk.
  • Security Test Case:
    1. In an environment where the temporary directory is writable by an attacker, call TempFile (or TempDir) with a known naming pattern.
    2. Record the current system time and process ID (or otherwise replicate the known seed conditions).
    3. Compute the expected “random” suffix using the same LCG algorithm as in nextRandom().
    4. Pre-create a file (or symbolic link) at the computed temporary name.
    5. Invoke the application function that creates a temporary file/directory and verify that file creation fails or that the new file’s content/path can be controlled by the attacker.
    6. Confirm that the vulnerability is exploitable by repeating the test under race conditions.

Vulnerability 3: Time‐of‐Check-to-Time‐of-Use (TOCTOU) Race in SafeWriteReader

  • Vulnerability Name: Time‐of‐Check-to-Time‐of-Use (TOCTOU) Race in SafeWriteReader
  • Description:
    • The function SafeWriteReader (in /code/util.go) first checks for file existence by calling Exists() and then creates the file via fs.Create() if no file is found.
    • This two–step “check then act” process is not atomic.
    • An attacker who can write to the target directory may create the file (or substitute a symbolic link) between the check and the creation call.
    • The safe write operation can thus be hijacked or misdirected.
  • Impact:
    • High
    • An attacker may force the safe write operation to write data into a file under attacker control or simply cause the operation to fail.
    • In scenarios where the data is sensitive or the file is accessed by another privileged process, this may lead to data corruption or unauthorized data injection.
  • Vulnerability Rank: High
  • Currently Implemented Mitigations:
    • The code uses an explicit existence check (Exists(fs, path)) before file creation; however, the check and creation remain separate.
  • Missing Mitigations:
    • An atomic “create‐if–not–exists” operation (or exclusive file–creation flag) is not used to remove the race window.
    • There is no additional synchronization between the check and the create steps.
  • Preconditions:
    • The destination directory must be writable by an attacker.
    • The attacker must be able to perform a file creation (or symlink insertion) between the existence check and the subsequent write operation.
  • Source Code Analysis:
    • In /code/util.go, SafeWriteReader calls Exists() to verify that a file does not exist.
    • If the file is absent, it then continues to call fs.Create(path) and writes data.
    • The lack of atomicity between checking and creation permits an attacker to intervene and create the file (or a symlink) in the interim, thus hijacking or disrupting the write operation.
  • Security Test Case:
    1. Set up a controlled file system instance where the attacker can simulate concurrent file creation.
    2. Begin the invocation of SafeWriteReader with a given file path and a known input stream.
    3. Immediately after the existence check, initiate a parallel process (or goroutine) that creates the file at the same path.
    4. Observe that SafeWriteReader either fails with an “already exists” error or writes data to a file controlled by the attacker.
    5. Repeat the test several times to demonstrate the race condition.

Vulnerability 4: TOCTOU Race in GCS File Creation via OpenFile

  • Vulnerability Name: TOCTOU Race in GCS File Creation via OpenFile
  • Description:
    • In the GCS–backed filesystem implementation (in /code/gcsfs/fs.go), the OpenFile method handles the os.O_CREATE flag by first calling file.Stat() to check whether an object exists and then, if no file is found, proceeds to create the file by calling file.WriteString("").
    • Because these are executed as two separate operations (a “check‐then‐act” sequence), an attacker who is able to race the file creation may pre–create an object (or a malicious symbolic link) with the same name in the time gap between the existence check and the write.
  • Impact:
    • High
    • An attacker exploiting this race condition could influence the outcome of the file creation.
    • This may lead to the file being created under the attacker’s control or result in unexpected file content – ultimately affecting the integrity and security of the data stored in the GCS bucket.
  • Vulnerability Rank: High
  • Currently Implemented Mitigations:
    • The code in OpenFile calls file.Stat() before attempting creation and checks for existence; however, it does not enforce an atomic check‐and‐create operation.
  • Missing Mitigations:
    • An atomic “create–if–not–exists” operation using GCS’s pre–conditions or similar measures is missing.
    • There is no synchronization to bridge the gap between the separate stat and write operations.
  • Preconditions:
    • The attacker must have—or be able to simulate having—write access to the target GCS bucket (or be in a position to trigger a race condition by concurrently creating objects).
    • The file creation request must be susceptible to interference by a concurrent process.
  • Source Code Analysis:
    • Within /code/gcsfs/fs.go, the relevant code begins by normalizing the file name and then (if flag & os.O_CREATE is set) performing a call to file.Stat().
    • If Stat() returns no error (meaning the object exists), the function returns an error (syscall.EPERM).
    • Otherwise, the code proceeds with file.WriteString("") to create an empty object.
    • The non–atomic nature of the two–step process (first checking with Stat() and then writing) introduces a window in which an attacker can act.
  • Security Test Case:
    1. In a test setup (for example, using a mocked or staging GCS bucket), invoke OpenFile with the os.O_CREATE flag for a chosen object name.
    2. Immediately after the Stat() check but before the WriteString("") call has been completed, simulate an attacker’s concurrent process that creates an object (or a symlink) with the same name in the bucket.
    3. Observe that the subsequent file creation logic does not reliably prevent the creation (or overwriting) of the object by the attacker.
    4. Verify that the function either returns an unexpected successful creation (allowing attacker–controlled file content) or returns an error that indicates the race condition was exposed.
    5. Repeat this test multiple times to confirm the intermittent nature of the race condition.

Vulnerability 5: Path Traversal in HttpFs

  • Vulnerability Name: Path Traversal in HttpFs
  • Description:
    • An attacker sends a crafted HTTP request to an application using HttpFs.
    • The request path contains path traversal sequences like ../../../.
    • The httpDir.Open function processes the path.
    • path.Clean("/"+name) is called, which can resolve to an absolute path outside the intended base directory. For example, ../../../sensitive_file becomes /sensitive_file.
    • filepath.Join then concatenates the base path with the cleaned path. However, if the cleaned path is absolute, filepath.Join effectively ignores the base path and uses the absolute path.
    • HttpFs.Open opens the file at the escaped path, allowing access outside the intended directory.
  • Impact:
    • High
    • An attacker can read arbitrary files from the server's filesystem that are accessible to the application process.
    • This can lead to information disclosure of sensitive data, source code, configuration files, etc.
  • Vulnerability Rank: High
  • Currently Implemented Mitigations:
    • None. The current implementation in httpDir.Open does not prevent path traversal.
  • Missing Mitigations:
    • Implement path validation in httpDir.Open after cleaning the path and before opening the file.
    • Verify that the resolved path remains within the intended base directory. A simple check would be to ensure the resolved path still has the base path as a prefix.
  • Preconditions:
    • An application uses afero.HttpFs to serve static files.
    • The application does not implement additional path validation before using HttpFs.
    • An attacker has network access to the application.
  • Source Code Analysis:
    • File: /code/httpFs.go
    func (d httpDir) Open(name string) (http.File, error) {
    	if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) ||
    		strings.Contains(name, "\x00") {
    		return nil, errors.New("http: invalid character in file path")
    	}
    	dir := string(d.basePath) // Base path is stored in d.basePath
    	if dir == "" {
    		dir = "."
    	}
    
    	// Vulnerable line: path.Clean might resolve to absolute path, escaping basePath
    	f, err := d.fs.Open(filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name))))
    	if err != nil {
    		return nil, err
    	}
    	return f, nil
    }
    • Step-by-step vulnerability analysis: The vulnerability is in the line f, err := d.fs.Open(filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))). path.Clean("/"+name) can return an absolute path, and when joined with dir using filepath.Join, it can bypass the intended base path restriction.
  • Security Test Case:
    1. Create a directory /tmp/afero_httpfs_test_base as the base directory for HttpFs.
    2. Inside /tmp/afero_httpfs_test_base, create a file index.html with content "Hello from base directory".
    3. Outside /tmp/afero_httpfs_test_base, create a sensitive file /tmp/sensitive.txt with content "This is sensitive data.".
    4. Write a Go program that uses afero.HttpFs to serve files from /tmp/afero_httpfs_test_base using http.FileServer.
    package main
    
    import (
    	"log"
    	"net/http"
    	"github.com/spf13/afero"
    )
    
    func main() {
    	baseFs := afero.NewOsFs()
    	httpFs := afero.NewHttpFs(baseFs)
    	fs := http.FileServer(httpFs.Dir("/tmp/afero_httpfs_test_base"))
    	http.Handle("/", fs)
    	log.Println("Server listening on :8080")
    	log.Fatal(http.ListenAndServe(":8080", nil))
    }
    1. Run the Go program.
    2. Send an HTTP GET request to http://localhost:8080/index.html. Verify that you receive "Hello from base directory".
    3. Send a crafted HTTP GET request to http://localhost:8080/../../../tmp/sensitive.txt.
    4. Check the HTTP response body. If the response body contains "This is sensitive data.", then path traversal vulnerability exists.