KGCS Documentation

02 — Root Cause Analysis: CWE-22

Filesystem Path Fundamentals

Linux/Unix paths:

/home/alice/documents/file.txt
├─ / = root directory
├─ home = subdirectory
├─ alice = subdirectory
└─ documents/file.txt = file

Path shortcuts:

The Vulnerability

When a web application uses user input to construct file paths:

VULNERABLE CODE:
file_name = request.args.get('file')
file_path = f'/var/www/uploads/{file_name}'
with open(file_path, 'r') as f:
    return f.read()

ATTACK PAYLOAD:
file_name = '../../etc/passwd'
file_path = '/var/www/uploads/../../etc/passwd'
# Which resolves to: /etc/passwd

Attack Vectors

1. Dot-Dot-Slash (../)

Current: /var/www/uploads/
../ moves up one level
../../ moves up two levels
../../../ moves up three levels
etc/passwd ends up at root's passwd file

2. Backslash (.)

On Windows:

C:\www\uploads\
..\..\ moves up
..\..\windows\system32\config\sam (Windows password hashes)

3. Unicode/UTF-8 Normalization

%C0%AE = encoded version of ../
%252E%252E%252F = double-encoded ../
Filters see %C0%AE and whitelist it
System decodes it to ../
Attack succeeds

4. Case Sensitivity Bypass

Some systems: .. filtered, but ..%5c bypasses(literal backslash)

# Admin creates symlink in uploads dir
ln -s /etc/passwd /var/www/uploads/legitimate.txt

# User downloads "legitimate.txt"
# Actually gets /etc/passwd (invisible attack)

Secure Implementation

SAFE - Canonicalization:

import os
from pathlib import Path

def secure_file_access(file_name):
    allowed_dir = Path('/var/www/uploads').resolve()
    file_path = (allowed_dir / file_name).resolve()

    # Ensure file is still within allowed directory
    if not str(file_path).startswith(str(allowed_dir)):
        raise ValueError("Path traversal attempt detected")

    with open(file_path, 'r') as f:
        return f.read()

# Attack payload:
file_name = '../../etc/passwd'
# file_path resolves to /etc/passwd
# Check fails: /etc/passwd is not under /var/www/uploads
# Request rejected

Why Blacklist Fails

Common mistake:

UNSAFE - Blacklist approach
if '..' in file_name:
    reject()
if file_name.startswith('/'):
    reject()

Bypasses: - Unicode: %C0%AE = .. - Double encoding: %252E%252E - Case: ..%5c - Null byte: ..%00.jpg (null terminator tricks)

KGCS Causal Chain

CWE-22 (Path Traversal)
  ├─ Root cause: Improper pathname limiting
  ├─ Demonstrated by → CAPEC-126
  └─ Implements → T1005 (Data from Local System)
       └─ Result: Unauthorized file read

Next: 03 Attack Scenarios