Про раз в десять дней вручную понимаю, у меня та же история: я на тот сайт заходил по другой задаче и списки не посмотрел.
По mtime самое простое, что у меня прижилось: find /path/to/site -type f -name '*.php' -newermt '-24 hours' -not -path '*/cache/*'
Два уточнения, без них будет много ложных срабатываний: исключить каталоги кэша и логов, и хранить прошлый список, чтобы в уведомление шли только новые строки. Плюс раз в сутки wp core verify-checksums, он ловит подменённые файлы ядра, у которых дата может выглядеть старой.
По пользователям в том же cron: wp user list --role=administrator --field=user_login. Сравниваю с эталонным списком в файле, при расхождении уведомление. Тем же способом wp plugin list --status=active: чужой плагин видно сразу, даже если он маскируется под что-то безобидное.
И одна мелочь, которая мне помогла больше остального: слать это не на почту, а в телеграм. Почту в запарке проще пролистать, а такие уведомления приходят ровно в тот момент, когда некогда 🙂
Про Basic Auth соглашусь: это защита от перебора и ботов на форме входа, дыру в API она не закрывает. В моём случае и она бы не спасла по другой причине: пароль был настоящий, украденный, с ним прошли бы и через неё.
Что делаю после этой истории, помимо обновлений:
DISALLOW_FILE_MODS. Даже когда админский доступ уже у чужого, залить плагин или тему через админку не получится. У меня атакующий ставил себе инструменты один за другим именно через интерфейс, так что это закрывает самый удобный для него путь.
Раз в неделю два списка: wp user list и wp plugin list. Минута работы, а чужой админ виден сразу. В августе я как раз этого не сделал и подарил им три недели.
wp core verify-checksums плюс поиск свежих файлов по mtime, а не по именам. Имена у шеллов каждый раз новые, дата изменения врёт реже.
За ссылку на разбор wp2shell спасибо, гляну внимательнее 👍 У вас обновления автоматом или руками по расписанию?
В этом случае WordPress как раз ни при чём. Зашли по паролю администратора, который утёк с чьего-то компьютера. С таким паролем войдут в любую панель, хоть в самописную.
А в автоматическом режиме его долбят по скучной причине: это самая большая цель на рынке. Боту без разницы, какой там код, он перебирает известные дыры плагинов и ворованные пароли подряд по всему интернету. Была бы на этом месте другая система с такой же долей, доставалось бы ей 🤷
Про лапшу спорить не буду, код местами музейный 😄 Но выбор у парикмахерской или поставщика оборудования выглядит так: движок, который поправит любой подрядчик за пару тысяч рублей в час, либо своя разработка, которую держит один конкретный человек, и когда он пропадает, сайт замирает вместе с ним. Обычно выигрывает первое, и я понимаю почему.
Хотя тут соглашусь: будь этот сайт статикой, вся история свелась бы к «кто-то украл пароль от админки», и на этом бы кончилась.
Второй заход разобрал по логам, там сошлись две вещи.
Первая: июльская чистка пропустила закладку. Лежала она в плагинах, с виду обычный «инструмент доступности», а внутри обработчик, который принимает команду прямо в параметре запроса. В uploads, куда лезут первым делом, было чисто. Правда, стрелять эта штука уже не могла: хостинг за три дня до её появления прикрыл своим .htaccess прямой доступ к php внутри wp-content/plugins. Я в сентябре специально в неё постучался, получил 403.
Вторая, главная: пароль утёк повторно, уже после смены. Видно по неудачным входам: весь день одна подсеть долбилась в wp-login, и в поле пароля у неё лежал адрес самого сайта, log=admin&pwd=https://… Кто-то разобрал строку url:login:password со сдвигом на поле. Это формат стилерских выгрузок, то есть паролей из браузера. Доказать нечем, но только это и объясняет, почему после смены пароля вход снова оказался открыт и почему дальше шли с разных адресов, каждый со своим набором плагинов.
С тех пор сверяю плагины и темы со списком того, что там должно стоять. Ну и DISALLOW_FILE_MODS, Basic Auth на wp-login, отдельная учётка владельцу.
Про раз в десять дней вручную понимаю, у меня та же история: я на тот сайт заходил по другой задаче и списки не посмотрел.
По mtime самое простое, что у меня прижилось: find /path/to/site -type f -name '*.php' -newermt '-24 hours' -not -path '*/cache/*'
Два уточнения, без них будет много ложных срабатываний: исключить каталоги кэша и логов, и хранить прошлый список, чтобы в уведомление шли только новые строки. Плюс раз в сутки wp core verify-checksums, он ловит подменённые файлы ядра, у которых дата может выглядеть старой.
По пользователям в том же cron: wp user list --role=administrator --field=user_login. Сравниваю с эталонным списком в файле, при расхождении уведомление. Тем же способом wp plugin list --status=active: чужой плагин видно сразу, даже если он маскируется под что-то безобидное.
И одна мелочь, которая мне помогла больше остального: слать это не на почту, а в телеграм. Почту в запарке проще пролистать, а такие уведомления приходят ровно в тот момент, когда некогда 🙂
Про Basic Auth соглашусь: это защита от перебора и ботов на форме входа, дыру в API она не закрывает. В моём случае и она бы не спасла по другой причине: пароль был настоящий, украденный, с ним прошли бы и через неё.
Что делаю после этой истории, помимо обновлений:
DISALLOW_FILE_MODS. Даже когда админский доступ уже у чужого, залить плагин или тему через админку не получится. У меня атакующий ставил себе инструменты один за другим именно через интерфейс, так что это закрывает самый удобный для него путь.
Раз в неделю два списка: wp user list и wp plugin list. Минута работы, а чужой админ виден сразу. В августе я как раз этого не сделал и подарил им три недели.
wp core verify-checksums плюс поиск свежих файлов по mtime, а не по именам. Имена у шеллов каждый раз новые, дата изменения врёт реже.
За ссылку на разбор wp2shell спасибо, гляну внимательнее 👍 У вас обновления автоматом или руками по расписанию?
В этом случае WordPress как раз ни при чём. Зашли по паролю администратора, который утёк с чьего-то компьютера. С таким паролем войдут в любую панель, хоть в самописную.
А в автоматическом режиме его долбят по скучной причине: это самая большая цель на рынке. Боту без разницы, какой там код, он перебирает известные дыры плагинов и ворованные пароли подряд по всему интернету. Была бы на этом месте другая система с такой же долей, доставалось бы ей 🤷
Про лапшу спорить не буду, код местами музейный 😄 Но выбор у парикмахерской или поставщика оборудования выглядит так: движок, который поправит любой подрядчик за пару тысяч рублей в час, либо своя разработка, которую держит один конкретный человек, и когда он пропадает, сайт замирает вместе с ним. Обычно выигрывает первое, и я понимаю почему.
Хотя тут соглашусь: будь этот сайт статикой, вся история свелась бы к «кто-то украл пароль от админки», и на этом бы кончилась.
Точно не скажу, первый вход был ещё до меня.
Второй заход разобрал по логам, там сошлись две вещи.
Первая: июльская чистка пропустила закладку. Лежала она в плагинах, с виду обычный «инструмент доступности», а внутри обработчик, который принимает команду прямо в параметре запроса. В uploads, куда лезут первым делом, было чисто. Правда, стрелять эта штука уже не могла: хостинг за три дня до её появления прикрыл своим .htaccess прямой доступ к php внутри wp-content/plugins. Я в сентябре специально в неё постучался, получил 403.
Вторая, главная: пароль утёк повторно, уже после смены. Видно по неудачным входам: весь день одна подсеть долбилась в wp-login, и в поле пароля у неё лежал адрес самого сайта, log=admin&pwd=https://… Кто-то разобрал строку url:login:password со сдвигом на поле. Это формат стилерских выгрузок, то есть паролей из браузера. Доказать нечем, но только это и объясняет, почему после смены пароля вход снова оказался открыт и почему дальше шли с разных адресов, каждый со своим набором плагинов.
С тех пор сверяю плагины и темы со списком того, что там должно стоять. Ну и DISALLOW_FILE_MODS, Basic Auth на wp-login, отдельная учётка владельцу.