Subject: | File:Temp::_is_safe() allows unsafe traversal of symlinks |
Example...
As user "attacker":
ln -s /tmp /tmp/exploit
As user "victim":
perl -MFile::Temp -e 'File::Temp->safe_level(File::Temp::HIGH); print
File::Temp::tempdir("/tmp/exploit/meXXXX") . "\n";'
The temporary directory path that is returned includes the symlink owned
by the "attacker" user.
Subject: | symlink-safety.patch |
From b0fc1b4b83b545c09d2fccb34486052654abca20 Mon Sep 17 00:00:00 2001
From: John Lightsey <jd@cpanel.net>
Date: Mon, 27 Jun 2011 13:07:44 -0500
Subject: [PATCH] symlink safety
Add check for unsafe symbolic links to _is_safe() directory check.
---
Temp.pm | 20 +++++++++++++++++++-
1 files changed, 19 insertions(+), 1 deletions(-)
diff --git a/Temp.pm b/Temp.pm
index a2d4ae0..0d515a9 100644
--- a/Temp.pm
+++ b/Temp.pm
@@ -668,7 +668,25 @@ sub _is_safe {
my $err_ref = shift;
# Stat path
- my @info = stat($path);
+ my @info = lstat($path);
+ my $symlink_test_path = $path;
+ my $symlink_loop_count = 0;
+ while (-l _) {
+ if (++$symlink_loop_count >= 50) {
+ $$err_ref = "50 levels of symlinks encountered at $path";
+ return 0;
+ }
+ if ( $info[4] <= File::Temp->top_system_uid() || $info[4] == $>) {
+ # safe to traverse
+ $symlink_test_path = readlink($symlink_test_path);
+ @info = lstat($symlink_test_path);
+ }
+ else {
+ $$err_ref = "Unsafe symlink at $path";
+ return 0;
+ }
+ }
+
unless (scalar(@info)) {
$$err_ref = "stat(path) returned no values";
return 0;
--
1.7.2.5