views:

313

answers:

5

Assume that an attacker controls the variable $untrusted_user_supplied_path . Is the following Perl code exploitable?

my $untrusted_user_supplied_path = ...
if ($untrusted_user_supplied_path =~ /\.\./) {
  die("Tries to escape homedir.");
}
my $base_path = "/home/username/";
my $full_path = "${base_path}${untrusted_user_supplied_path}";
if (-e $full_path) {
  open(FILE, "<", $full_path) || die("File not accessible.");
  while (<FILE>) {
    # present the content to the user
  }
  close(FILE);
}

The code is defined as exploitable if an attacker can choose a value of $untrusted_user_supplied_path such that he/she can read a file that resides in a directory that is not a sub-directory of $base_path (say /etc/passwd)?

You can assume that the code is running under Linux. Furthermore, you can assume that no additional flaws are introduced in the code which presents the file to the user.

Please note that the question is about whether or not the code is exploitable, not how to make the code more secure. There are numerous ways to make the code more secure (think chroot, etc.) but that is beyond the scope of this question. Just state in your answer if you believe that the code is exploitable or not. And of course, please provide supporting argumentation.

+1  A: 

It looks reasonable to me, although your test is a little draconian. You might want to consider replacing:

/\.\./

with:

m{/\.\./}

to allow access to files and directories containing two dots. It still wouldn't allow convoluted but potentially valid accesses like dir1/../dir2/filename, although you might not be too worried about that.

Tim
Tim, thanks for your answer. I parse it as a "No, the code is not exploitable" - is that correct? :-)
knorv
I wouldn't be prepared to be *that* assertive, but I would be happy with that code until someone could point out a problem I've missed. :-)
Tim
Actually, a lot will depend on how you "read the file $full_path" and whether you do that carefully. In addition to other checks, consider using taint checking http://perldoc.perl.org/5.8.8/perlsec.html and the tree-argument form of `open` http://perldoc.perl.org/5.8.8/functions/open.html
Tim
Note under Windows a triple-dot is also a directory traversal.
bobince
You see, that's the sort of comment I was worried about. :-)
Tim
"I would be happy with that code until someone could point out a problem I've missed." That's perhaps the biggest security problem right there. If you really care about security, you always think there is something you've missed and you're never happy or satisfied. Complacency is the opposite of security.
brian d foy
@Brian Sorry if this came across as complacent - my aim was to write something a long way from the offered "No, the code is not exploitable" which I would never sign up to without consulting an expert. :-) Where security really matters, it's always wise to understand your threat model, have a clear idea what you're doing and why, and consult an expert. Also, as you say, I believe that it's essential to try to keep an open mind about shortcomings which *you* might have missed, but which *others* might spot.
Tim
A: 

Whether it is exploitable or not depends on the code which presents the file to the user. There don't have to be "flaws" in that code so much as opportunities for doing things you haven't thought of.

Kinopiko
You can assume that no additional flaws are introduced in the code which presents the file to the user. Given that assumption, what is your answer?
knorv
It's not really a question of "flaws".
Kinopiko
The question was very clear, and this is not an answer to it.
Tom Anderson
It just isn't as simple as you think it is.
Kinopiko
Kinopiko: Does the part of the code specified in the question contain any security flaws, yes or no?
knorv
"You can assume that no additional flaws" I've heard that quite a bit, and it always means "Everything else is wildly insecure and we're pinning our hopes on this one line of code."
brian d foy
brian d foy: OK, thanks. Now what's your answer to the question? Is the code safe or not?
knorv
Read my answer for my answer. I don't even have to look at code to always say "no, it's not safe" :)
brian d foy
brian: Thanks for taking your time to answer the question.
knorv
+9  A: 

If a symlink exists inside the homedir to somewhere outside, you're still in trouble.

Thomas
Good point. Beyond that, is the code safe or not?
knorv
+1  A: 

I'm going to violate your house rules and suggest that you do it like this:

use Cwd;
my $full_path = "${canonical_base_path}${untrusted_user_supplied_path}";
my $canonical_full_path = abs_path($full_path);
if (substr($canonical_full_path, 0, length($base_path)) != $base_path) {
      die("Tries to escape homedir.");
}

This should be watertight. It does require $base_path to be canonical, though.

Tom Anderson
Sorry, but that's not an answer to the question asked. If I had asked "how do I improve this code" then I'd flagged your message as the correct answer.
knorv
Shouldn't your `!=` be a `ne`?
Geo
Nope, it's a math comparison. != is correct.
Randal Schwartz
What math comparison? $base_path is "/home/username". The code is trying to ensure that $base_path is at the start of the string (although this is easier and clearer with index(...) == 0).
brian d foy
My perl is very rusty, i'm afraid. I mostly do shell script, where != is for strings and -ne is for numbers - if it's the other way round in perl, then yes, that should be a -ne.
Tom Anderson
+10  A: 

You're asking if your code is exploitable. Yes. All code is exploitable. You might not think it is because you think you've covered the situations that you can think about, but the other side typically finds a situation you haven't thought about.

Security is more than just the code. You have to consider the environment it runs it, what else the user was allowed to do before he ran your code, etc. etc.

If you're truly worried about what might happen with this code, create a risk matrix. Start with the part that you're worried about and list all of its assumptions. For instance, in your case you might start with:

  • /home/username is the directory I think it is (i.e. not a mount point, symlink, fake user, etc)
  • the supplied path is one I expect and is allowed to exist
  • the path is a regular file (e.g. not a special device)
  • the path has a certain owner, group, or mode
  • I'm running the perl I think I am (no path attack in finding executable)
  • PERL5LIB, PERL5OPT, or -I did not front-load module load paths (no path attack in finding modules)

And so on and so on. Once you develop all of your assumptions, you ensure that they are valid by locking down those cases. You also find all of their assumptions, and lock down those, and so on. Perl's taint checking will help with some of those (and I talk about it in more depth in Mastering Perl).

Successful attacks are often indirect ones. For instance, I was part of a job to secure some data in a very rich and paranoid bank. We did all the computery stuff we could do, and one of my co-workers, in idle conversation, asked how they did the task before we installed the server. They said, "Oh, the data is on a binder on so-and-so's desk". Despite all of our work, their pay, and everyone's time and effort, anyone on the inside who wanted the data could quite literally walk off with it no matter what we did with the server.

Now that you have your risk matrix, you start developing your risk tolerance. Nothing is ever going to be perfect, and you could work to the heat death of the universe locking everything down. Instead of being perfect, you settle for how much risk you're willing to take on for each part of the code. You figure out what could happen if one part is compromised and how much that would cost you (in dollars, reputation, whatever) and figure out how much work that is worth to you (or your employers). You do just enough work to be below your risk tolerance.

The problem is that even the best people will miss something. Small cracks in security might not seem that important, but if you put enough together you can eventually bootstrap yourself into an exploitable situation. Security is holistic.

brian d foy
Thanks Brian for your answer! Well-written answer as usual. I really dig your perl answers.
knorv