Kind of Directory Traversal
If you see this code: what’s wrong?
from os import path
page_id = req.args.get('page_id', 'index')
filename = path.join(path.dirname(__file__), 'includes', page_id)
try:
f = file(filename)
except IOError:
handle_not_found()
First of all, the page_id comes from an user submitted variable in a web application. It’s in fact a variable from the query string. Now someone could say ?page_id=../../../etc/htpasswd etc. There are numerous ways to fix that. For example you can do this:
from os import path
fn = path.join(*[x for x in fn.split('/') if x != '..'])
This also makes sure that the path separator is valid. I guess everybody that knows about security also knows how to defend those problems.
What you might not know is that python itself doesn’t accept null bytes in the “file/open” call. This is some sort of built in security feature. Other languages such as PHP forward the nullbyte to the C layer. Thus an attacker could cut off a string at a given position to gain further control over the input layer (cutting of a .php extension etc). This is more severe in Perl where you can also pipe stuff in the file call.
This security feature however doesn’t raise an IOError but a TypeError! So the corrected example from above looks like this:
from os import path
page_id = req.args.get('page_id', 'index')
filename = path.join(path.dirname(__file__), 'includes',
*[x for x in page_id.split('/') if x != '..'])
try:
f = file(filename)
except (IOError, TypeError):
handle_not_found()