Определение уязвимостей XSS-атак

Я столкнулся с безжалостной XSS-атакой, которую не могу предотвратить. На моем сайте есть три формы ввода: одна для загрузки изображений, одна для добавления комментариев на страницу, а третья отправляет электронное письмо через php. Я так или иначе защищаю их всех, но почему-то уязвимость все еще присутствует.

Код моего комментария:

for($j = 0; $j < 3 ; $j++)
                    {
                            $s = $styles[array_rand($styles)];
                            if($song_arr[$k] != '' && $artist_arr[$k] != '' && $name_arr[$k] != '')
                            {
                            echo '<td>';    
                            echo '<div class="'.$s.'" style="clear:left" >';
                                echo '<p class="rendom">';
                                    echo 'Song:&nbsp;'.htmlspecialchars($song_arr[$k]).'<br>Artist:&nbsp;'.htmlspecialchars($artist_arr[$k]).'<br>Submitted By:&nbsp;'.htmlspecialchars($name_arr[$k]);
                                echo '</p>';
                            echo '</div>';
                            echo '</td>';
                            }
                        $k++;
                    }

Загрузить форму:

    if ((($_FILES["userfile"]["type"] == "image/jpg")
|| ($_FILES["userfile"]["type"] == "image/jpeg")
|| ($_FILES["userfile"]["type"] == "image/pjpeg"))
&& ($_FILES["userfile"]["size"] < 20000)) {
    if (is_uploaded_file($_FILES['userfile']['tmp_name'])) {
        if (move_uploaded_file ($_FILES['userfile']['tmp_name'],'userfile.jpg')) {
            $image = new SimpleImage();
            $image->load('userfile.jpg');
            $image->resize(29,136);
            $image->save('userfile.jpg');
            ?>
            <img src="img/text/uploadSuccess.jpg" alt="Image uploaded successfully." /><br />
                    <br />
                    <img src="userfile.jpg?rand=<? echo rand(1,10000); ?>" />
            <?
        } else {
            echo 'Moving uploaded file failed';
        }
    } else {
        echo 'File upload failed';
    }
} else {
echo 'Invalid Filetype';
}

Форма электронной почты:

<?php
// Process input variables (trim, stripslash, reformat, generally prepare for email)
    $recipients = trim($_POST['recipients']);
    $sender_email = trim($_POST['sender_email']);
    $sender_name = stripslashes(trim($_POST['sender_name']));
    $subject = stripslashes(str_replace(array("\r\n", "\n", "\r"), " ", trim($_POST['subject'])));
    $message = stripslashes(str_replace(array("\r\n", "\n", "\r"), "<br />", trim($_POST['message'])));

// Check email addresses for validity
    // Explode the comma-separated list of recipients + the sender email address into an array. Even if there is only one recipient, this will check for validity.
    $addresses = explode("," , $recipients.",".$sender_email);
    // For each email address specified...
    foreach ($addresses as $address) {
        // If the email address doesn't match the RFC8622 spec regex, assume invalid 
        if (!(preg_match("~^[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+(?:[A-Z]{2}|com|org|net|uk|edu|jp|de|br|ca|gov|au|info|nl|fr|us|ru|it|cn|ch|tw|es|se|be|dk|pl|at|il|tv|nz|biz)$~i", trim($address)))) {
            // Output error message for invalid email address and end script.
            echo '"' . $address . '" is not a valid email address. Please try again.';
            return;
        }
    }

// Check other vars are not empty
    if ((empty($sender_name)) OR (empty($subject)) OR (empty($message))) {
        // Output error message and end script.
        echo 'Please complete all form fields and try again.';
        return;
    }

// Send HTML email
    $headers = "MIME-Version: 1.0\r\nContent-type:text/html;charset=iso-8859-1\r\nFrom: ". $sender_name ." <". $sender_email ."> \n\n";
    if (mail($recipients,$subject,$message,$headers)) {
        // Mail successfully sent, output success message and end script
        echo 'Message sent. We will be in touch with you shortly.';
        return;
    } else {
        // Something unknown went wrong. =(
        echo 'Something went wrong which the little worker monkeys could not fix. Please try again.';
        return;
    }
?>

XSS продолжает отображаться в самом низу моей индексной страницы, на которой я include() все три вышеуказанных файла, содержимое которых находится в разных файлах.

Любые идеи?


person Dave Kiss    schedule 23.02.2010    source источник


Ответы (3)


В форме электронной почты вы возвращаете неверные адреса электронной почты, которые были отправлены, не экранируя их. Измените эту строку:

 echo '"' . $address . '" is not a valid email address. Please try again.';

to

 echo '"' . htmlspecialchars($address) . '" is not a valid email address. Please try again.';
person ArIck    schedule 23.02.2010
comment
Хороший улов, как вы думаете, может ли XSS, вставленный сюда, каким-то образом остаться внизу страницы даже для последующих загрузок страницы на разных машинах? - person Dave Kiss; 24.02.2010
comment
Нет, не может. Этот тип вставки является непостоянным XSS (en.wikipedia.org/wiki /Cross-site_scripting#Non-persistent) и влияет только на пользователя, отправившего запрос. Твой противнее ;) ! - person Wookai; 24.02.2010
comment
Я собираюсь пойти с Вукаем и утверждать, что злоумышленник получил один из своих скриптов на вашем сервере. Кроме того, включение файла, путь которого вы получаете путем объединения inc/, страницы переменной GET и .inc.php вызывает проблемы. Если ваш PHP-код находится в /home/dave, а мой — в /home/eric, я могу открыть одну из ваших страниц с помощью page=../../eric/evil_script в строке запроса и добавить на вашу страницу мой evil_script .inc.php файл. - person ArIck; 24.02.2010
comment
Арик, по вашей рекомендации я проверил свой php error_log и обнаружил некоторые странные ошибки.... [11-Dec-2009 00:38:56] Предупреждение PHP: include(inc//../../../ ../../../var/log/apache2/access.log): не удалось открыть поток: нет такого файла или каталога в /home......../index2 copy.php в строке 137. у вас есть предложения о том, как я могу проверить ввод, или другой подход? - person Dave Kiss; 24.02.2010
comment
В общем, вы хотите просто иметь белый список одобренных файлов, чтобы включить его и выйти из него. Измените URL-адреса так, чтобы «страница» была просто числом от 0 до (количество страниц — 1). Измените способ включения страницы, объявив массив с именами файлов (мы назовем его $MY_PAGES), а затем включите ($MY_PAGES[$_GET[страница]]). - person ArIck; 24.02.2010
comment
спасибо за ваше предложение... я также рассматриваю эффективность $page = preg_replace('/[^-a-zA-Z0-9_]/', '', $_GET['page']); есть ли у вас какие-либо рекомендации против использования этого, кроме потенциально нежелательного включения локальных файлов? - person Dave Kiss; 24.02.2010
comment
Это должно быть хорошо. (Регулярное выражение удалит знаки фунта стерлингов и тильды, которые допустимы в имени файла в большинстве * nix ... но я предполагаю, что никто не хочет видеть ваши файлы резервных копий emacs.) - person ArIck; 24.02.2010

После беглого просмотра кажется, что единственное место, где вы показываете ненадежные данные, это комментарии. И вы использовали htmlspecialchars, который должен предотвратить интерпретацию любого HTML-кода.

Вы говорите, что вредоносный код находится внизу вашей страницы. Может быть, злоумышленник нашел способ загрузить и включить свой скрипт прямо на ваш сервер? Как выглядит включенный код? Это JavaScript, HTML?

person Wookai    schedule 23.02.2010
comment
XSS — это вставка javascript, которая использует document.write для вставки iframe, источником которого является внешний вредоносный сайт. Я использую только включения через php: ‹?php if (!isset($_GET[page])) { include(inc/home.inc.php); } else { include(inc/.$_GET[page]..inc.php); } ?› - person Dave Kiss; 23.02.2010
comment
В порядке. Код JS находится в середине вашего раздела комментариев или где-то еще? В последнем случае проблема может заключаться не в опубликованном вами коде. - person Wookai; 24.02.2010
comment
Код JS отображается в самом низу страницы index.php, а не в середине комментариев. - person Dave Kiss; 24.02.2010
comment
В этом случае я бы сказал, что ваши файлы были каким-то образом скомпрометированы. Если вы посмотрите на свой файл шаблона/PHP, который генерирует страницу, есть ли там что-нибудь? Может быть, злоумышленник использует .htacces для автоматического добавления кода ко всем вашим php-скриптам? Он присутствует на всех страницах или только на странице рекомендаций? - person Wookai; 24.02.2010
comment
Код присутствует только на индексной странице, которая представляет собой базовый файл, включающий элементы из различных файлов для создания страницы. В прошлом я изменил пароль своей учетной записи на что-то гораздо более безопасное, но безрезультатно.. я не уверен о .htaccess, но я предполагаю, что злоумышленнику потребуется доступ к учетной записи? - person Dave Kiss; 24.02.2010
comment
Все сводится к одному: сможете ли вы найти вредоносный код в одном из ваших PHP-файлов? Если да, то злоумышленник каким-то образом смог получить к ним доступ. Если нет, то он есть в базе (но похоже, что вы чистили вывод, так что это не должно быть так. Попробуйте очистить его, чтобы убедиться). - person Wookai; 24.02.2010

Это не ответ и не хорошая новость, но я видел что-то очень похожее на то, что вы описали в примере, в довольно тревожной видеорекламе от Symantec "Zeus: King of the Crimeware Toolkits" на Youtube: http://www.youtube.com/watch?v=hfjPO8_pGIk

Видео стоит посмотреть в любом случае.

У меня нет связи с Symantec.

person LarryW    schedule 02.03.2010