Null-Byte-Interaktionsfehler (Poison Null Byte)
Beschreibung
Null-Byte-Interaktionsfehler tritt auf, wenn Anwendungen Benutzereingaben verarbeiten, die Null-Bytes (\x00) enthalten, die Diskrepanzen in der String-Behandlung zwischen verschiedenen Komponenten verursachen. Einige Sprachen (C, PHP) behandeln Null-Bytes als String-Terminatoren, während andere (Java, Python) sie als reguläre Zeichen einbeziehen. Diese Diskrepanz ermöglicht Angreifern, Sicherheitsfilter zu umgehen und auf unbefugte Ressourcen zuzugreifen.
Risiko
Angreifer können Dateierweiterungs-Validierung umgehen, um bösartige Dateien hochzuladen. Path-Traversal-Angriffe können Sicherheitsfilter umgehen. Zugriffskontrollmechanismen, die auf String-Matching basieren, können umgangen werden. Log-Injection und -Vergiftung wird möglich. SQL-Injection- und XSS-Filter können umgangen werden. Die Schwachstelle ist besonders gefährlich in Webanwendungen, die mit C-basierten Bibliotheken interagieren.
Lösung
Entfernen oder lehnen Sie Null-Bytes aus allen Benutzereingaben ab. Verwenden Sie Funktionen, die Null-Bytes korrekt behandeln. Validieren Sie Eingaben vor und nach der Null-Byte-Verarbeitung. Verwenden Sie sprachgerechte String-Behandlung. Implementieren Sie Defense in Depth mit mehreren Validierungsschichten. Berücksichtigen Sie den gesamten Datenfluss und alle beteiligten Komponenten.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Zugriffskontrolle | Bereich: Bypass Sicherheitsfilter erkennen bösartigen Inhalt nicht. |
| Integrität | Bereich: Dateisystem Unbefugter Dateizugriff oder Uploads. |
| Vertraulichkeit | Bereich: Informationsoffenlegung Lesen von Dateien außerhalb des beabsichtigten Bereichs. |
Beispielcode + Lösungscode
Verwundbarer Code
<?php
// VERWUNDBAR: Null-Byte-Injection in Dateieinbindung
function includePageVulnerable($page) {
// Nur .php-Dateien erlauben
if (substr($page, -4) !== '.php') {
$page .= '.php';
}
// Auf Path-Traversal prüfen
if (strpos($page, '..') !== false) {
die('Ungültiger Pfad');
}
include '/var/www/pages/' . $page;
}
// Angriff: page=../../etc/passwd%00
// In älterem PHP schneidet das Null-Byte den String ab
// include('/var/www/pages/../../etc/passwd') wird ausgeführt!
// VERWUNDBAR: Datei-Upload-Erweiterungs-Prüfung
function uploadFileVulnerable($filename, $content) {
$allowed = ['jpg', 'png', 'gif'];
// Erweiterung holen
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if (!in_array(strtolower($ext), $allowed)) {
die('Ungültiger Dateityp');
}
// Angriff: filename=malware.php%00.jpg
// Passiert Prüfung aber erstellt .php-Datei
file_put_contents('/uploads/' . $filename, $content);
}
// VERWUNDBAR: Zugriffskontroll-Bypass
function checkAccessVulnerable($path) {
$restricted = ['/admin/', '/config/', '/private/'];
foreach ($restricted as $dir) {
if (strpos($path, $dir) !== false) {
return false;
}
}
return true;
}
// Angriff: path=/adm%00in/secret.txt
// strpos findet '/admin/' nicht aber Dateisystem interpretiert als /admin/
?>
# VERWUNDBAR: Pfadvalidierungs-Bypass
import os
def read_file_vulnerable(user_path):
base_dir = '/var/www/public/'
# Einfache Path-Traversal-Prüfung
if '..' in user_path:
raise ValueError('Ungültiger Pfad')
# Erlaubte Erweiterung prüfen
if not user_path.endswith('.txt'):
raise ValueError('Nur .txt-Dateien erlaubt')
# Null-Byte nicht entfernt!
full_path = base_dir + user_path
# Wenn an C-Bibliothek oder bestimmte OS-Aufrufe übergeben:
# user_path = "secret.php\x00.txt"
# Passiert Python-Prüfungen aber C sieht "secret.php"
with open(full_path, 'r') as f:
return f.read()
# VERWUNDBAR: URL-/Befehlskonstruktion
def fetch_url_vulnerable(user_url):
# Validierung
if not user_url.startswith('https://allowed.com/'):
raise ValueError('URL nicht erlaubt')
# Null-Byte kann in nachgelagerter Verarbeitung abschneiden
# user_url = "https://allowed.com/\x00https://evil.com/"
import subprocess
subprocess.run(['curl', user_url]) # Kann zu evil.com gehen
// VERWUNDBAR: Java übergibt an nativen Code
public class VulnerableFileHandler {
// Java-Strings enthalten Null-Bytes
public byte[] readFile(String userPath) throws IOException {
// Validierung in Java
if (userPath.contains("..")) {
throw new SecurityException("Path-Traversal erkannt");
}
if (!userPath.endsWith(".txt")) {
throw new SecurityException("Ungültige Erweiterung");
}
// Wenn Pfad an nativen (JNI) Code oder C-Bibliothek übergeben wird:
// userPath = "secret.php\0.txt"
// Java sieht "secret.php\0.txt" (11 Zeichen)
// C sieht "secret.php" (10 Zeichen, stoppt bei Null)
return Files.readAllBytes(Paths.get(userPath));
}
// VERWUNDBAR: Befehlsausführung
public void runCommand(String filename) throws IOException {
// Dateinamen validieren
if (!filename.matches("[a-zA-Z0-9]+\\.sh")) {
throw new SecurityException("Ungültiger Dateiname");
}
// Null-Byte in Mitte des Strings
// filename = "safe\0; rm -rf /.sh"
Runtime.getRuntime().exec("/scripts/" + filename);
}
}
Lösungscode
<?php
// SICHER: Null-Bytes aus allen Eingaben entfernen
function sanitizeInput($input) {
// Null-Bytes entfernen
return str_replace("\0", '', $input);
}
// SICHER: Dateieinbindung mit Null-Byte-Schutz
function includePageSafe($page) {
// Null-Bytes zuerst entfernen
$page = str_replace(["\0", "\x00", "%00"], '', $page);
// Erlaubte Seiten mit Whitelist
$allowed = ['home', 'about', 'contact', 'products'];
if (!in_array($page, $allowed)) {
die('Ungültige Seite');
}
include '/var/www/pages/' . $page . '.php';
}
// SICHER: Datei-Upload mit umfassender Validierung
function uploadFileSafe($filename, $content) {
// Null-Bytes entfernen
$filename = str_replace(["\0", "\x00"], '', $filename);
// Dateinamen-Format validieren
if (!preg_match('/^[a-zA-Z0-9_-]+\.[a-zA-Z0-9]+$/', $filename)) {
die('Ungültiges Dateinamens-Format');
}
// Erweiterung prüfen
$allowed = ['jpg', 'png', 'gif'];
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (!in_array($ext, $allowed)) {
die('Ungültiger Dateityp');
}
// Verifizieren, dass Inhalt dem behaupteten Typ entspricht
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_buffer($finfo, $content);
finfo_close($finfo);
$allowedMimes = ['image/jpeg', 'image/png', 'image/gif'];
if (!in_array($mime, $allowedMimes)) {
die('Inhalt stimmt nicht mit Erweiterung überein');
}
// Sicheren Dateinamen generieren
$safeFilename = bin2hex(random_bytes(16)) . '.' . $ext;
file_put_contents('/uploads/' . $safeFilename, $content);
return $safeFilename;
}
// SICHER: Zugriffskontrolle mit Null-Byte-Behandlung
function checkAccessSafe($path) {
// Null-Bytes entfernen
$path = str_replace(["\0", "\x00"], '', $path);
// Pfad normalisieren
$path = realpath('/var/www' . $path);
// Muss innerhalb erlaubtem Verzeichnis sein
if ($path === false || strpos($path, '/var/www/public/') !== 0) {
return false;
}
return true;
}
?>
import os
import re
# SICHER: Null-Bytes aus Eingabe entfernen
def sanitize_input(user_input):
if isinstance(user_input, str):
return user_input.replace('\x00', '')
elif isinstance(user_input, bytes):
return user_input.replace(b'\x00', b'')
return user_input
# SICHER: Pfadvalidierung mit Null-Byte-Schutz
def read_file_safe(user_path):
base_dir = '/var/www/public/'
# Null-Bytes entfernen
user_path = sanitize_input(user_path)
# Zeichen mit Whitelist
if not re.match(r'^[a-zA-Z0-9_/-]+\.txt
```java
// SICHER: Null-Byte-Schutz in Java
public class SafeFileHandler {
// Null-Bytes aus String entfernen
private String sanitize(String input) {
if (input == null) return null;
return input.replace("\0", "");
}
public byte[] readFile(String userPath) throws IOException {
// Null-Bytes entfernen
userPath = sanitize(userPath);
// Pfadformat validieren
if (!userPath.matches("^[a-zA-Z0-9_/-]+\\.txt$")) {
throw new SecurityException("Ungültiges Pfadformat");
}
// Pfad auflösen und validieren
Path basePath = Paths.get("/var/www/public").toRealPath();
Path fullPath = basePath.resolve(userPath).normalize();
// Sicherstellen innerhalb Basisverzeichnis
if (!fullPath.startsWith(basePath)) {
throw new SecurityException("Pfad außerhalb erlaubtem Verzeichnis");
}
return Files.readAllBytes(fullPath);
}
// SICHER: Befehlsausführung mit Validierung
public void runCommand(String filename) throws IOException {
// Null-Bytes entfernen
filename = sanitize(filename);
// Strikte Whitelist-Validierung
if (!filename.matches("^[a-z]+\\.sh$")) {
throw new SecurityException("Ungültiger Dateiname");
}
// Verifizieren, dass Datei am erwarteten Ort existiert
Path scriptPath = Paths.get("/scripts", filename).toRealPath();
if (!scriptPath.startsWith(Paths.get("/scripts").toRealPath())) {
throw new SecurityException("Script nicht in erlaubtem Verzeichnis");
}
// ProcessBuilder für Sicherheit verwenden
ProcessBuilder pb = new ProcessBuilder(scriptPath.toString());
pb.directory(new File("/scripts"));
pb.start();
}
}
Ausgenutzt in der Praxis
PHP-Dateieinbindung
Null-Byte-Angriffe wurden weitgehend gegen PHP include() und require() verwendet.
Datei-Upload-Bypass
Erweiterungsvalidierung umgangen um Web-Shells hochzuladen.
WAF-Bypass
Web Application Firewalls mit Null-Bytes umgangen.
Tools zum Testen/Ausnutzen
- Burp Suite — Null-Bytes in Anfragen injizieren.
- Manuelles Testen mit %00 in URLs und Parametern.
- Fuzzing-Tools mit Null-Byte-Payloads.
CVE-Beispiele
- CVE-2006-7243: PHP-Null-Byte in Dateioperationen.
- Mehrere CVEs in Webanwendungen mit Null-Byte-Schwachstellen.
Referenzen
- MITRE. "CWE-626: Null Byte Interaction Error (Poison Null Byte)." https://cwe.mitre.org/data/definitions/626.html
- OWASP. "Embedding Null Code."