VNX-626 – Null Byte Interaction Error (Null Byte Injection)
Overview
In languages that interface with C-based libraries (PHP, early Python versions), a null byte (%00 or \0) in a string terminates it at the C level while the higher-level language sees the full string. Attackers append %00 to filenames to strip validation suffixes: ../../../../etc/passwd%00.jpg passes an .jpg extension check but opens /etc/passwd.
Severity: High | CWE: CWE-626 – Null Byte Interaction Error (Null Byte Injection)
Why This Matters
PHP versions before 5.3.4 were notoriously vulnerable: include($_GET['page'] . '.php') could be bypassed with page=../../../../etc/passwd%00 to read arbitrary files. Even modern applications using C-extension file paths may be vulnerable if null bytes are not stripped from user input.
What Gets Flagged
<?php
// FLAGGED: User input used directly in include without null byte sanitization
include($_GET['page'] . '.php');
// FLAGGED: File open with user-supplied name
$file = $_GET['file'];
readfile($BASE_DIR . $file);
# FLAGGED: open() with user-provided path, no null byte check
path = request.GET['file']
with open(os.path.join(base_dir, path)) as f:
return f.read()
Remediation
Strip null bytes from user input and validate after sanitization:
<?php
// SAFE: Strip null bytes and validate extension
$page = str_replace(chr(0), '', $_GET['page']);
if (!preg_match('/^[a-zA-Z0-9_\-]+$/', $page)) {
die('Invalid page name');
}
include($BASE_DIR . $page . '.php');
# SAFE: Strip null bytes, use basename, validate
path = request.GET.get('file', '')
path = path.replace('\x00', '')
path = os.path.basename(path) # strip directory traversal
full_path = os.path.realpath(os.path.join(base_dir, path))
if not full_path.startswith(os.path.realpath(base_dir)):
return HttpResponseForbidden()