Автогенерируемые аудиокапчи (баг в NetCat 5.2)

Сегодняшний рабочий день мы провели очень интересно - полдня поднимали сервер. Подняли, конечно, и вот решили кратко отчитаться о том, что произошло. История очень показательна, и является блестяще иллюстрированным ответом на вопрос "а зачем нашему сайту платная техподдержка?".

Эта история наверняка касается версии NetCat 5.2 всех редакций, а также модуля "Защита картинкой" и техподдержки NetCat :).
Также она может касаться соседних версий, но точно не 5.5, где этот баг исправлен.

Что случилось?

Итак, все началось где-то на той неделе и проявилось в субботу, когда на нашем сервере неожиданно закончилось место и он начал подтупливать и подглючивать. Сегодня с утра я взялся за всестороннюю диагностику и выяснил, примерно следующую последовательность фактов:

  • начиная с субботы, некий ботнет, состоящий преимущественно из взломанных сайтов низшего эшелона (порносайты, знакомства, "женские истории" и т.д.) начал неторопливо "прощупывать" один из наших сайтов на NetCat
  • предполагаю, что он искал SQL Injection Netcat 5.0, так как ломился на капчу
  • данная уязвимость на сайте закрыта, поэтому ботнет к успеху не пришел. Однако NetCat настолько... ммм... своеобразен, что начал реагировать на "прощупывания", инициализируя процесс генерации аудиокатч.
    • следует заметить, что опция (аудиокапчи) в админке вообще-то отключена, но об этом ниже
  • в результате аудиокапчи (то есть маленькие mp3-файлики со случайными комбинациями букв) постепенно генерились и генерились до тех пор, пока их не нагенерилось на 5 ГБ.
  • так как у нашего сайта на сервере не стояло квоты на использование дискового пространства, место на диске в итоге закончилось полностью
  • сервер завис и все сломалось.

Как я все пофиксил?

  • сначала я продиагностировал сервер и выяснил, что проблема в огромном множестве mp3-файлов в директории netcat_files/captcha/current_voice.
  • я зашел в админку и обнаружил что данный функционал модуля, вообще-то, выключен! В поле "использовать аудиокачу" стоит ноль!
  • я удалил все эти файлы, однако они немедленно начали появляться вновь, таким образом проблема не была решена;
  • затем я позвонил в NetCat и попробовал узнать, в курсе ли они такой проблемы. Дело в том, что я вроде уже сталкивался с чем-то похожим когда-то.
  • по телефону я не получил никакого ответа, кроме предложения писать тикет. Но это я предполагаю чем закончится: у вас кончилась лицензия, продлите лицензию, о, у вас старая версия, поставьте обновление, о, проблема решена и появилось две новые? пожалуйста, создайте два новых тикета. Я, конечно, утрирую, но ясно, что быстрого решения мне не добиться. Поэтому ковыряюсь сам дальше.
  • после анализа error.log выяснилось, что проблема как-то проявляется вот здесь:
[Mon Apr 06 14:55:00 2015] [error] [client 173.252.101.112] PHP Warning:  copy(/var/www/*/data/www/*/netcat_files/captcha/current_voice/33843462e319929356b2806dfc07e579.mp3) [<a href='function.copy'>function.copy</a>]: failed to open stream: \xd0\x9e\xd1\x82\xd0\xba\xd0\xb0\xd0\xb7\xd0\xb0\xd0\xbd\xd0\xbe \xd0\xb2 \xd0\xb4\xd0\xbe\xd1\x81\xd1\x82\xd1\x83\xd0\xbf\xd0\xb5 in /var/www/*/data/www/*/netcat/modules/captcha/function.inc.php on line 73
  • я посмотрел на код в районе 73-й строчки:
  1.  
  2.     // Обновление захешированных файлов для аудиокаптчи
  3.     $res = $nc_core->db->get_results("SELECT * FROM `Captchas_Settings`", ARRAY_A);
  4.     if (!empty($res))
  5.             foreach ($res as $v)
  6.             $captcha_settings[$v['Key']] = $v['Value'];
  7.  
  8.     if ($captcha_settings && is_writable($nc_core->FILES_FOLDER) && is_dir($nc_core->MODULE_FOLDER.'captcha/voice/'.$MODULE_VARS['captcha']['VOICE'].'/') && time() - 3600 >= strtotime($captcha_settings['time'])) {
  9.         $db->query("UPDATE `Captchas_Settings` SET `Value`= Now() WHERE `Key` = 'time'");
  10.         $from = $nc_core->MODULE_FOLDER.'captcha/voice/'.$MODULE_VARS['captcha']['VOICE'].'/';
  11.         $to = $nc_core->FILES_FOLDER.'captcha/current_voice/';
  12.         $nc_core->files->create_dir($to);
  13.  
  14.         $enc_mp3_files[] = '';
  15.         $enc_mp3_folder = opendir($to);
  16.         while ($one = readdir($enc_mp3_folder)) {
  17.             if ($one != '.' && $one != '..' && substr(strrchr($one, '.'), 1) == 'mp3') {
  18.                 $enc_mp3_files[] = $one;
  19.             }
  20.         }
  21.  
  22.         $normal_mp3_folder = opendir($from);
  23.         while ($one = readdir($normal_mp3_folder)) {
  24.             $file_hash = nc_captcha_generate_hash();
  25.             if ($one != '.' && $one != '..' && substr(strrchr($one, '.'), 1) == 'mp3') {
  26.                 if ($captcha_settings['current_voice'] != $MODULE_VARS['captcha']['VOICE'] || !in_array($captcha_settings[$one], $enc_mp3_files)) {
  27.                     $db->query("UPDATE `Captchas_Settings` SET `Value`= '".$MODULE_VARS['captcha']['VOICE']."' WHERE `Key` = 'current_voice'");
  28.                     if ($captcha_settings['current_voice'] != $MODULE_VARS['captcha']['VOICE']) {
  29.                         unlink($to.$captcha_settings[$one]);
  30.                     }
  31.                     copy($from.$one, $to.$file_hash.'.mp3');
  32.                     $db->query("UPDATE `Captchas_Settings` SET `Value`='".$db->escape($file_hash).".mp3' WHERE `Key` ='".$one."'");
  33.                 } else {
  34.                     rename($to.$captcha_settings[$one], $to.$file_hash.'.mp3');
  35.                     $db->query("UPDATE `Captchas_Settings` SET `Value`='".$db->escape($file_hash).".mp3' WHERE `Key` ='".$one."'");
  36.                 }
  37.             }
  38.         }
  39.     }
  • я внимательно посмотрел на этот код. Еще внимательнее... Еще внимательнее... И понял, что в нем нет проверки включенности аудиокапчи.
  • взял дистрибутив версии 5.5 и посмотрел аналогичное место. Эврика! В нем код слегка переписан, и как раз появилась недостающая проверка настроек модуля, значит здесь действительно ошибка, и ее уже исправили.

Так как мне не хотелось обновляться (ибо это чревато новыми багами и проблемами) и уж тем более править код самому, в итоге я еще раз проанализировал код и... просто назначил полю VOICE несуществующее значение. Получилось вот так:

Собственно, вот оно и решение данной проблемы, рекомендуемое к превентивному применению всем владельцами версии 5.2 и других соседних, содержащих такой же код.

Блог

Что с Мастерхостом? Когда заработает?!

Этот вопрос всё чаще задают в Интернете начиная примерно с 12:00 дня 2 марта. А всё потому, что он накрылся!

далее

Автоматизированная Система Управления Бэкапами

Автоматизированная Система Управления Бэкапами позволяет добиться полного контроля над резервными копиями сайтов внутри инфраструктуры веб-студии. Если вы поддерживаете десятки сайтов на разных хостингах, без подобной системы вы не можете быть на 100% уверены в том, что каждый из них был корректно зарезервирован прошлой ночью.

далее

WebSocket: интеграция с NetCat

Хотите добавить на сайт под управлением CMS NetCat поддержку технологии WebSocket? Обращайтесь к нам! Посетители сайта смогут получать мгновенные уведомления о событиях сайта без обращений к серверу и перезагрузок страниц. Превратите свой сайт в интерактивную площадку, работающую в реальном времени!

далее

NetCat: техническая поддержка и доработка сайтов

Мы работаем с CMS NetCat уже больше 10 лет. У нас большой опыт и ответственный подход к делу.

далее

Весь блог тут