Python中需考虑Null byte injection漏洞吗?如何编写易受攻击代码?
Great question! Let's break this down clearly—Python isn't entirely immune to null byte injection, but its behavior differs a lot from languages like PHP, especially across Python 2 vs. Python 3.
Vulnerable Code in Python 2
In Python 2, strings are byte-based, and when you pass them to low-level file system calls (like open()), they're handed directly to C functions that treat \x00 (null byte) as a string terminator. This creates a classic null byte injection scenario.
Here's a simple vulnerable example:
# Python 2: Risky file handling with user input user_supplied_filename = "sensitive_data.txt\x00.jpg" # Attacker's input full_path = "/app/uploads/" + user_supplied_filename # The C-level fopen() will stop at the null byte, opening /app/uploads/sensitive_data.txt with open(full_path, "r") as file: contents = file.read() print(contents) # Exposes sensitive file content
If your code checks for allowed file extensions (e.g., only .jpg), an attacker can append a null byte followed by the allowed extension to bypass the check—while the actual file opened is the one before the null byte.
Python 3's Built-in Protections
Python 3 changed how strings and file system interactions work. By default, strings are Unicode, and Python explicitly blocks paths containing null bytes by throwing a ValueError when you try to use them in file operations.
Try this in Python 3:
# Python 3: Null byte in path throws an error user_input = "secret.txt\x00.png" full_path = "/app/uploads/" + user_input try: with open(full_path, "r") as file: print(file.read()) except ValueError as e: print(e) # Output: "embedded null byte"
This built-in check eliminates most basic null byte injection risks for file operations. However, there are edge cases to watch for:
Edge Case: Calling External Commands
If you use subprocess with byte strings (instead of Unicode strings) or interact with legacy systems, you might still face risks. For example:
# Python 3: Potential risk with byte string arguments import subprocess # Attacker's input with null byte malicious_arg = b"config.ini\x00; rm -rf /" subprocess.call([b"cat", malicious_arg])
On Linux, the execve system call allows null bytes in arguments, so cat will receive config.ini as its argument (ignoring everything after the null byte). While this doesn't execute the rm command here, it could let an attacker bypass argument validation in the external tool.
How to Mitigate Risks
For Python 2 (if you're stuck supporting it):
- Explicitly check for null bytes in all user-supplied input:
if "\x00" in user_input: raise ValueError("Invalid input") - Validate file extensions by parsing the full filename (don't just check the suffix—an attacker could hide a null byte before it)
- Use
os.pathutilities to normalize and sanitize paths (e.g.,os.path.basename()to extract the actual filename)
- Explicitly check for null bytes in all user-supplied input:
For Python 3:
- Rely on Python's built-in
ValueErrorfor null bytes in paths, but still validate user input to catch issues early - Avoid
shell=Trueinsubprocesscalls—use argument lists instead of concatenating command strings to prevent shell injection (which can overlap with null byte risks) - If working with byte strings (e.g., for legacy APIs), explicitly scan for
\x00bytes and reject invalid input
- Rely on Python's built-in
内容的提问来源于stack exchange,提问作者Kohei TAMURA

