Новый метод атаки через reverse-ip 0. INTRO Вобщем не буду делать большое вступление. Недавно имело место хекать сайт. Шел был успешно залит на соседний, но вот беда на сервере грамотно выставленны права. Пришлось включать голову и думать. И в результате этих дум у меня появился новый способ о чем я ниже и напишу. Этот способ подходит для следующих ситуаций: Грамотно выставленны права и порутать сервер не удалось На сервере включенны open_basedir и safe_mode без возможности обхода оных Не знание пути к целевому сайту Какие то другие ситуации, я еще не придумал ^_^ Для реализации подобной атаки требуется: На целевом сайте требуется хранение важной информации в сессиях Само собой необходим шелл на соседнем сайте Необходимы права на запись в папку где хранятся файлы сессий 1. ОПИСАНИЕ/ИСПОЛЬЗОВАНИЕ Может быть вы уже догадались этот способ основан на созданиях файлов с сессиями где можно вписать произвольные данные. В данный момент не могу привести в пример цмсок/форумов с храненией инфы сессиях бо просто не помню, мб кто нить ниже отпишет ^_^. Случай №1 Вот представим какую нить ебучую цмс. Эта цмс допустим располагается на хосте lamo.com, на этом же сервере есть другой сайт xack.com на который вы без труда смогли залить веб шелл. Но к сожалению вы не можете пролезть к lamo.com за отсутствием прав, либо еще чего то там. Но в той цмс что там стоит есть вот такой файл admin.php Code: <?php if($_SESSION['admin']===true){ //тут типа выполнение каких нить администраторских действий ... }else die('Fuck off!'); ?> Теперь опишу как хранятся данные в файлах сессии: Code: [имя_переменной]|[тип_переменной]:[длина]:[значение_переменной];[имя_переменной2]|... и тд где тип переменной задается так: s- строковая переменная (string) i- числовая переменная (integer) b- булевая переменная (boolean) a- массив переменных (array) (!)Для строковой переменной [значение_переменной] задается в кавычках "". Для булевых переменных значения хранятся следующим образом 1-true, 0-false Для перменных типа булевых и числовых отсутствует параметр [длина] разумеется один разделитель ":" так же нужно будет убрать. Описание хранение массива я тут приводить не буду, кому нужно будет - разберется. Что ж прояснив ситуацию со стандартом хранения сессий в файлах, начнем создавать файл сессии для описанного выше случая, он будет выглядеть так: Code: admin|b:1; Как говорится все гениальное просто. Теперь сохраняем этот файл как sess_13cacf9c6032d82cf2f0a19bb479bd26 и загружаем его на сервер в папку где хранятся все файлы сессий (по дефолту /tmp но узнать точно можно сделав вывод phpinfo() и посмотрев параметр session.save_path). Залил? Молодец! Обязательно поставь chmod 0777 на только что загруженный файл. Теперь твоя задача создать в браузере куку с именем PHPSESSID (имя глядеть в phpinfo() параметр session.name, PHPSESSID - это по дефолту обычно никто не меняет) со значением 13cacf9c6032d82cf2f0a19bb479bd26 (надеюсь вы уловите взаимосвязь между именем файла сессии и значением куки). Открываем http://lamo.com/admin.php и нас пускают внутрь! Случай №2 Опять же представим эту цмс, только файлик admin.php будет выглядеть вот так: Code: <?php ... if(!empty($_SESSION['pass'])){ $result=@mysql_query("SELECT * FROM admin WHERE pass='".$_SESSION['pass']."'"); if(mysql_num_rows($result)!= 0){ //тут типа выполнение каких нить администраторских действий ... }else die('Fuck off!'); }else die('Fuck off!'); ?> То есть в сессии содержится пароль администратора. Только не надо опять думать что это безвыходная ситуация. Создаем по аналогии с предыдщим пунктом файл сессии: Code: pass|s:11:"1' OR 1=1/*"; Для тех кто не понял, в большинстве случаев программисты доверяют данным из сессий и почти, да что почти, можно сказать никогда не ставят проверки на них, а в данном случае мы используем это для реализации sql inject, и благодаря чему становимся администратором. Случай №3 А теперь такая ситуация на серве включены register_globals и magic_qoutes. А файлик admin.php выглядит так: Code: <?php ... if(!empty($pass)){ $result=@mysql_query("SELECT * FROM admin WHERE pass='".$pass."'"); if(mysql_num_rows($result)!= 0){ //тут типа выполнение каких нить администраторских действий ... }else die('Fuck off!'); }else die('Fuck off!'); ?> Вроде бы все равно хочешь не хочешь $pass будет слешироваться. Но это не так magic_qoutes слеширует только(!) GET, POST, COOKIE а SESSION остается таким как и был. А вот register_globals превратит все из SESSION в глобальные переменные. Для эксплуатации используем содержание файла сессий как и в предыдущем пункте. Случай №4 Что делать если не прокатили предыдущие способы? Можно тупо почитать все сессии что хранятся в папке с файлами сессий, в поисках паролей/логинов к целевому сайту. Но к сожалению не всегда выставленные права дают прочитать эти файлы и все же... Конечно подобных файлов очень много. Но если посмотреть, то большинство из них пустые. Так вот разумеется читать следует остальные, непустые файлы. Никто не даст вам гарантию что этот файл принадлежит именно целевому сайту, но пытаться нужно. Этот случай есть чисто теория, я не уверен что этот способ будет кто то применять, но думаю написать стоит. 2. OUTRO Да я согласен это не очень часто встречаемый случай, но именно этот способ позволил мне получить веб шелл на целевом веб сайте, может быть и вам он поможет также. Отдельный привет я хочу выразить тестерам halkfild и Grey. (c) Dr.Z3r0 01.06.08
защита: не делать критических переменных в виде булевых значений, а также инт 1, 0, которые могут узнать все, не хранить в сессиях пароли и другие важные данные. иногда можно читать и файлы сессий всем ... всякое бывает. поставить проверку из 3 строк: PHP: if(sizeof($_SESSION)){ foreach($_SESSION as $key => $value){ $_SESSION[$key] = $this->secure->mres($this->secure->remove_html($value)); } }
Либо я чего-то упустил, либо где тут reverce-ip? Он тут если и есть, то где-то в уголке тихо курит. Способ не новый, его даже в видео в Хакере показывали, но за статью +
найти более поддающиеся сайты на этом же сервере. вывод напрашивается один: защищать сессии и не хранить в них ничего важного
Ну так тогда большую половину инклудов reverse-ip назвать можно. Еще один метод защиты - использовать свои handler'ы для работы с сессиями - хранить в мускуле, кпримеру (благо есть таблицы типа Memory).
только если отпарсить результаты лайв ком и тд.. Code: http://search.live.com/results.aspx?q=ip%3A77.88.21.11&go=&form=QBRE
PHP: function curl_get($url, $post) { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_HEADER, False); curl_setopt($curl, CURLOPT_RETURNTRANSFER, True); curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5'); curl_setopt($curl, CURLOPT_REFERER, $url); curl_setopt($curl, CURLOPT_POSTFIELDS, $post); $result = curl_exec($curl); curl_close($curl); return $result; } function reverseip($domain) { $sites = array(); $raw = curl_get('http://wservices.ru/reverseip.php', 'domain_input='.$domain); $start = strpos($raw, '</b> хостятся:<p>') + 17; $end = strpos($raw, '<br></td></tr>'); $raw = substr($raw, $start, $end - $start); $sites = explode('<br>', $raw); $count = count($sites); for ($i = 0; $i < $count; $i++) { $row = $sites[$i]; $sites[$i] = explode('</a> - ', substr($row, strpos($row, '">') + 2)); } /* Array ( [0] => Array ( [0] => domain [1] => title ) } */ return $sites; }
2 BlackSun http://2ip.ru/server.php?ip=[site] - выдаёт побольше результов да и пост не надо юзать .. обойтись можно ф-ией file_get_contents
Да, я тоже думал парсить сервисы по выдаче такой инфы, но подумал, что лучше написать свой скрипт для этого. Ведь те же 2ip.ru как то работают - первоиссточником что является для них?
Если требуется быстро просканить некоторок количество сайтов и их ближайшие IP на маленький список возможных уязвимостей, то вот скрипт: Code: #! /usr/bin/perl -w use Net::DNS; if (@ARGV<2) { print <<END; ============================================================ Usage: SCRIPT.PL TOP BOTTOM ip4scan.pl 10 15 > out.txt TOP & BOTTOM: scope around ip example: ip = 64.125.86.120, TOP = 10 BOTTOM = 15 get range to scan: 64.125.86.105 ... 64.125.86.130 in.txt: list hostnames for scan ipbase.txt: note base of scaned hostname format hostname -> ip ============================================================ END exit;} open(IN, "<in.txt"); open(IPBASE, ">>ipbase.txt"); @hostname = <IN>; chomp @hostname; # Строим хэш $hostname -> $IP-адрес (только первый IP из возвращаемых) foreach $hostname (@hostname) { $ip{$hostname} = &resolve($hostname); } # Записываем эти пары в одну кучу в файл без проверки на повторы foreach $hostname (sort keys %ip) { print IPBASE "$hostname -> $ip{$hostname}\n"; } # Строим диапазоны для сканирования вокруг целевых IP-адресов # Нижнее и верхнее значение задается в параметрах, передаваемых скрипту foreach $hostname (sort keys %ip) { $top = &ip2int( $ip{$hostname} ) + $ARGV[0]; $bottom = &ip2int( $ip{$hostname} ) - $ARGV[1]; @range = map {&int2ip($bottom + $_)} (0..$top-$bottom); print join ("\n", @range),"\n"; } # Подпрограмма определения ip-адреса по имени хоста sub resolve { my $res = Net::DNS::Resolver->new; my $query = $res->search("$hostname"); if ($query) { foreach my $rr ($query->answer) { next unless $rr->type eq "A"; return $rr->address; } } else { warn "query failed: ", $res->errorstring, "\n"; } } # Подпрограмма перевода IP-адреса в 32-разрядное число # Лучше подпрограмм ip2int и int2ip не придумалось sub ip2int { @a = split(/\./,$_[0]); return $a[0]*256**3+$a[1]*256**2+$a[2]*256+$a[3]; } # Подпрограмма перевода 32-разрядного числа в IP-адрес sub int2ip { $d[0] = int($_[0]/256/256/256); $d[1] = int(($_[0]-$d[0]*256**3)/256/256); $d[2] = int(($_[0]-$d[0]*256**3-$d[1]*256**2)/256); $d[3] = int($_[0]-$d[0]*256**3-$d[1]*256**2-$d[2]*256); return join (".", @d); } Список с именами хостов находится в файле in.txt.На выходе в файле out.txt получаются диапазоны IP с заданными границами.