
Бесплатный анализатор компрометации журналов доступа: взаимодействия с веб-шеллами, шаблоны эксплуатации и всплески брутфорса в ваших журналах Apache/nginx — серьёзность, достоверность, рекомендации по устранению. Только чтение.
Ваши журналы веб-сервера уже знают, подверглись ли вы атаке. weblogchecker читает их.
phpscan сообщает, уязвим ли ваш PHP. phpscan hunt ищет шеллы в
корневой директории сайта. weblogchecker отвечает на третий вопрос — воспользовался ли кто-нибудь ими на самом деле? — опираясь на единственную запись, которая уже есть у большинства сайтов и которую никто не читает: журнал доступа.
Он потоково обрабатывает журналы доступа Apache и nginx, которыми вы владеете, находит значимые взаимодействия — веб-шелл, отвечающий на запросы, всплеск брутфорса, заканчивающийся редиректом, шаблон эксплойта, получивший ответ 200, — и сообщает о каждом из них с указанием серьёзности, уверенности, фактических строк журнала в качестве доказательства и того, что с этим делать.
weblogchecker analyze /var/log/apache2/access.log
Коды выхода: 0 = индикаторов нет, 1 = индикаторы найдены, 2 = ошибка использования.
Добавьте --format json для машиночитаемого вывода, --since 2026-10-01, чтобы
ограничить окно. Логи .gz читаются напрямую; - читает stdin.
Новое в 0.2.0 — сравнение с базовой линией. Списки сигнатур знают только те шеллы, у которых уже есть имена. Шелл, который попадёт на ваш сайт, имеет случайное имя. Дайте weblogchecker доверенный старый лог с того же сайта, и он сообщит об исполняемых файлах, которых там раньше никогда не было:
weblogchecker analyze access.log --baseline access.log.last-month
Каждый исполняемый путь (.php, .phtml, .cgi, .asp, .jsp…), который появляется
впервые, оценивается по пяти слабым сигналам только на основе лога —
отвечал 2xx/3xx, использовался POST/PUT, без referrer, запрошен не более чем с 2 IP,
находится в каталоге upload/cache/temp — и выводится как NEW
с сигналами, счётчиками и строками лога в качестве доказательств. Первое появление само по себе —
это замечание низкой важности; серьёзность растёт только по мере накопления сигналов (подробности
ниже), поэтому плагин, установленный вами на прошлой неделе, не воспринимается как
инцидент.
Одна строка, из PyPI (Python 3.11+, только стандартная библиотека — без зависимостей):
pip install weblogchecker
Первый релиз на PyPI ожидается. Пока доверенный издатель PyPI не настроен, установите идентичный код с GitHub:
pip install git+https://github.com/PHPatch/weblogchecker.git(или скачайте подписанный архив релиза ниже). Строкаpip install weblogcheckerвыше заработает, как только выйдет первый релиз на PyPI.
В системах, которые отказывают с ошибкой "externally-managed-environment" (Debian/Ubuntu и Homebrew Python), используйте вместо этого pipx:
python3 -m pip install --user pipx # if you don't have pipx yet
pipx install weblogchecker
Подписанные релизы (sdist + wheel + PGP-подписи + SBOM) доступны на
странице релизов GitHub.
Проверяйте подписи с помощью ключа в pgp-key.asc — отпечаток
BAA1 586A AD37 18C0 CE41 D288 FE23 A624 54E3 5307. См. SECURITY.md.
| Паттерн в вашем логе | Уровень серьёзности / уверенность | Почему это важно |
|---|---|---|
| Известный веб-шелл (c99, r57, FilesMan, b374k, WSO), отвечающий 2xx | высокий / высокая | Шелл существует и обслужил запрос |
| Те же имена запрашивались, но 404/403 | низкий / низкая | Кто-то искал; ничего не найдено — контекст, а не тревога |
eval-stdin.php (phpunit) отвечает | высокий / высокая | Шелл UnitTest из волны php2shell октября 2026 выполняет код, отправленный через POST |
Исполняемый файл (.php и т.п.) внутри /uploads/, /media/, /files/… отвечает, особенно на POST | высокий / высокая | Каталоги загрузок никогда не должны выполнять код |
| POST/PUT к статическому файлу (.jpg, .css…) с ответом 2xx | высокий / средняя | Браузеры не отправляют POST к изображениям; «изображение» часто оказывается скриптом |
Паттерн эксплойта в URI (traversal, eval(, php://, длинный base64-токен) с ответом 2xx | высокий / средняя | Попытка могла увенчаться успехом |
| Те же паттерны заблокированы / 404 | низкий / низкая | Фоновый шум; полезен только как контекст кампании |
| Всплеск брутфорса на wp-login.php / xmlrpc.php (≥20 POST / 10 мин) | средний / средняя | Один IP, нечеловеческий темп |
| 302 внутри этого всплеска после повторных неудач | высокий / средняя | Признак верного пароля — возможный захват аккаунта |
| User-agent сканеров (sqlmap, nuclei, nikto…) | низкий / низкая | Информационно; сканирование — это не компрометация |
Путь исполняемого файла отсутствует в вашем логе --baseline, отвечает на запросы | низкий → высокий / ≤ средняя | Шелл с неизвестным именем, которого не знает ни один блоклист; серьёзность растёт с POST-запросами, отсутствующими referrer, малым числом IP, каталогами загрузок |
Каждый класс находок сопровождается текстом рекомендаций: поместить файл в карантин, сменить
учётные данные, проверить всё, к чему обращался этот IP. Находки веб-шеллов указывают на
сопутствующий инструмент — phpscan hunt (pip install phpscan,
github.com/PHPatch/phpscan) — который
сканирует сам webroot на предмет шеллов, на которые указывают эти паттерны логов.
Этот инструмент создан по той же доктрине, что и phpscan:
Разбор выполняется потоково по строкам: файл никогда не загружается в память целиком, а агрегация хранит не более пяти строк доказательств на находку. Замерено на генераторе фикстур этого проекта (366 306 строк, 72 МБ реалистичного комбинированного лога): 7,6 секунды, пиковый RSS 12,8 МБ на скромной виртуальной машине. Для лога в 2 ГБ потребуется та же память и пропорционально больше времени.
$ weblogchecker analyze access.log
weblogchecker 0.2.0 - access-log compromise analysis
Log: access.log
Lines read: 13 | parsed: 13 | unparseable (skipped): 0