В этой статье я покажу, как получить права суперпользователя на виртуальной машине Mischief с CTF-площадки Hack The Box. Этот забег даст нам навыки работы с протоколом SNMP, поможет понять принцип IPv6-маршрутизации и разобраться с механизмом распределения прав доступа ACL, а под занавес мы построим и протестируем полноценный ICMP-шелл на Python.

По уровню сложности эта виртуалка на Linux находится где-то между Medium и Hard (6,3 балла из 10), хотя изначальный ее рейтинг был определен как Insane. Если бы не некоторые ошибки создателя машины, она и правда была бы «безумной».

Вот что нас ждет на пути к финальному флагу:

  • сбор и анализ информации, предоставляемой протоколом SNMP, с последующим извлечением авторизационных данных из аргументов командной строки для простого Python-сервера;
  • получение IPv6-адреса машины из того же вывода SNMP (первый способ) либо через pivoting другого хоста на Hack The Box из его MAC-адреса (второй способ — алгоритм EUI-64);
  • обнаружение веб-сервера, живущего по найденному IPv6-адресу и содержащего панель удаленного выполнения команд на атакуемой машине;
  • обход фильтрации, который даст возможность инъекции произвольных команд, и захват авторизационных данных пользователя;
  • получение реверс-шелла по IPv6 в обход правил iptables для запуска su от имени www-data (так как оказывается, что пользователя блокирует механизм распределения прав доступа ACL) и получения root-сессии с паролем, забытым в .bash_history;
  • наконец, на сладкое создание ICMP-шелла с помощью модуля Scapy на Python. Он даст возможность просматривать результаты удаленного исполнения команд при помощи утилиты ping.
 

Разведка

 

Nmap

Итак, по традиции начнем подготовительный этап сбора информации со сканирования портов с помощью Nmap.

TCP

Сперва сканируем весь диапазон TCP-портов хоста простым сканом SYN.

root@kali:~# nmap -n -v -Pn --min-rate 5000 -oA nmap/initial -p- 10.10.10.92
root@kali:~# cat nmap/initial.nmap
# Nmap 7.70 scan initiated Mon Apr 1 16:17:45 2019 as: nmap -n -v -Pn --min-rate 5000 -oA nmap/initial -p- 10.10.10.92
Nmap scan report for 10.10.10.92
Host is up (0.045s latency).
Not shown: 65533 filtered ports
PORT STATE SERVICE
22/tcp open ssh
3366/tcp open creativepartnr

Read data files from: /usr/bin/../share/nmap
# Nmap done at Mon Apr 1 16:18:11 2019 -- 1 IP address (1 host up) scanned in 26.45 seconds

И теперь делаем точечный запрос на порты 22 и 3366, используя определение версии сервисов и дефолтные скрипты NSE.

root@kali:~# nmap -n -v -Pn -sV -sC -oA nmap/version -p22,3366 10.10.10.92
root@kali:~# cat nmap/version.nmap
# Nmap 7.70 scan initiated Mon Apr 1 16:18:20 2019 as: nmap -n -v -Pn -sV -sC -oA nmap/version -p22,3366 10.10.10.92
Nmap scan report for 10.10.10.92
Host is up (0.042s latency).

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 2a:90:a6:b1:e6:33:85:07:15:b2:ee:a7:b9:46:77:52 (RSA)
| 256 d0:d7:00:7c:3b:b0:a6:32:b2:29:17:8d:69:a6:84:3f (ECDSA)
|_ 256 3f:1c:77:93:5c:c0:6c:ea:26:f4:bb:6c:59:e9:7c:b0 (ED25519)
3366/tcp open caldav Radicale calendar and contacts server (Python BaseHTTPServer)
| http-auth:
| HTTP/1.0 401 Unauthorized\x0D
|_ Basic realm=Test
| http-methods:
|_ Supported Methods: GET HEAD
|_http-server-header: SimpleHTTP/0.6 Python/2.7.15rc1
|_http-title: Site doesn't have a title (text/html).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon Apr 1 16:18:44 2019 -- 1 IP address (1 host up) scanned in 24.05 seconds

Информации немного. Мы видим вот что.

  • Это относительно новая сборка Ubuntu. Проверив баннер со строкой версии SSH OpenSSH 7.6p1 Ubuntu 4 на launchpad.net — ресурсе, на котором хостятся репозитории пакетов для Ubuntu, — убеждаемся, что мы имеем дело с версией Bionic от 2018.03.07, поэтому искать эксплоиты для Secure Shell бессмысленно.
  • На 3366-м порте TCP работает простой Python HTTP-сервер с авторизацией. С самого начала начинать брутить вслепую что бы то ни было — откровенный моветон, поэтому расширим поверхность атаки сканированием UDP-портов.
Узнаем версию ОС по баннеру SSH
Узнаем версию ОС по баннеру SSH

UDP

Как и раньше, сначала «прощупаем почву», используя на этот раз флаг -sU для диапазона UDP.

root@kali:~# nmap -n -v -Pn --min-rate 5000 -oA nmap/udp-initial -sU -p- 10.10.10.92
root@kali:~# cat nmap/udp-initial.nmap
# Nmap 7.70 scan initiated Mon Apr 1 16:26:41 2019 as: nmap -n -v -Pn --min-rate 5000 -oA nmap/udp-initial -sU -p- 10.10.10.92
Nmap scan report for 10.10.10.92
Host is up (0.048s latency).
Not shown: 65534 open|filtered ports
PORT STATE SERVICE
161/udp open snmp

Read data files from: /usr/bin/../share/nmap
# Nmap done at Mon Apr 1 16:27:08 2019 -- 1 IP address (1 host up) scanned in 26.56 seconds

И «добьем» расширенным запросом.

root@kali:~# nmap -n -v -Pn -sV -sC -oA nmap/udp-version -sU -p161 10.10.10.92
root@kali:~# cat nmap/udp-version.nmap
# Nmap 7.70 scan initiated Mon Apr 1 16:27:39 2019 as: nmap -n -v -Pn -sV -sC -oA nmap/udp-version -sU -p161 10.10.10.92
Nmap scan report for 10.10.10.92
Host is up (0.043s latency).

PORT STATE SERVICE VERSION
161/udp open snmp SNMPv1 server; net-snmp SNMPv3 server (public)
| snmp-info:
| enterprise: net-snmp
| engineIDFormat: unknown
| engineIDData: b6a9f84e18fef95a00000000
| snmpEngineBoots: 19
|_ snmpEngineTime: 16h02m33s
| snmp-interfaces:
| lo
| IP address: 127.0.0.1 Netmask: 255.0.0.0
| Type: softwareLoopback Speed: 10 Mbps
| Status: up
| Traffic stats: 0.00 Kb sent, 0.00 Kb received
| Intel Corporation 82545EM Gigabit Ethernet Controller (Copper)
| IP address: 10.10.10.92 Netmask: 255.255.255.0
| MAC address: 00:50:56:b9:7c:aa (VMware)
| Type: ethernetCsmacd Speed: 1 Gbps
| Status: up
|_ Traffic stats: 456.93 Kb sent, 39.49 Mb received
| snmp-netstat:
| TCP 0.0.0.0:22 0.0.0.0:0
| TCP 0.0.0.0:3366 0.0.0.0:0
| TCP 127.0.0.1:3306 0.0.0.0:0
| TCP 127.0.0.53:53 0.0.0.0:0
| UDP 0.0.0.0:161 *:*
| UDP 0.0.0.0:38577 *:*
|_ UDP 127.0.0.53:53 *:*
| snmp-processes:
| [... Вывод SNMP ...]
Service Info: Host: Mischief

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Mon Apr 1 16:30:03 2019 -- 1 IP address (1 host up) scanned in 143.80 seconds

Уже интереснее — есть SNMP-сервер на 161-м порте UDP и даже подробности, полученные скриптами Nmap. Хотя полный вывод опущен (от Nmap он длинный и не очень информативный), от этого можно смело оттолкнуться при поиске пути проникновения в систему.

 

Исследование SNMP — порт 161 UDP

Что такое SNMP? Статья в «Википедии» гласит:

SNMP (англ. Simple Network Management Protocol — простой протокол сетевого управления) — стандартный интернет-протокол для управления устройствами в IP-сетях на основе архитектур TCP/UDP. К поддерживающим SNMP устройствам относятся маршрутизаторы, коммутаторы, серверы, рабочие станции, принтеры, модемные стойки и другие. Протокол обычно используется в системах сетевого управления для контроля подключенных к сети устройств на предмет условий, которые требуют внимания администратора.

SNMP возглавляет составленный SANS Institute список «Common Default Configuration Issues» с вопросом изначальной установки строк сообщества на значения «public» и «private» и занимал десятую позицию в SANS Top 10 самых критических угроз интернет-безопасности за 2000 год.

То есть SNMP позволяет собирать и расшаривать информацию о том, что происходит на хостах в сети. Информация такого рода инкапсулируется в базу управляющей информации MIB (Management Information Base), а идентификаторы объектов OID (Object Identifiers) однозначно определяют записи в этой базе. К примеру, идентификатор 1.3.6.1.2.1.4.34 описывает сущность ipAddressTable (таблица IP-адресов), а 1.3.6.1.2.1.4.34.1.3 описывает сущность ipAddressIfIndex (индекс интерфейса).

MIB основана на нотации ASN.1 и используется для упрощения представления данных в формате, понятном человеку, следовательно, она не является необходимым компонентом SNMP. Ближайшая аналогия — DNS-сервер, резолвящий легко читаемые доменные имена в такие чуждые нам цифры IP-адресов.

Рассмотрим, как можно выжать информацию из службы SNMP штатными средствами Kali Linux.

Настройка snmpwalk

Для анализа информации, которую целевой хост предоставляет по SNMP, воспользуемся snmpwalk — стандартной утилитой для разведки SNMP в Linux.

Если запустить snmpwalk при базовых настройках, ничего, кроме непонятных для человеческого взгляда идентификаторов OID, мы не получим. Здесь на помощь приходит пакет snmp-mibs-downloader, который загружает и инсталлирует базу MIB. Установим его.

root@kali:~# apt install snmp-mibs-downloader -y

А затем разрешим использование MIB, закомментировав единственную значащую строку в /etc/snmp/snmp.conf.

Собираем дамп

С помощью snmpwalk сдампим весь трафик SNMP с указанием версии протокола 2c (самая распространенная) и строки сообщества public, которая, по сути, служит паролем по умолчанию для местного способа аутентификации.

root@kali:~# snmpwalk -v 2c -c public 10.10.10.92 | tee snmpwalk.out

Вывод массивный, поэтому он был перенаправлен в файл snmpwalk.out для дальнейшей работы.

К слову: если тебе нужно было оставаться более «бесшумным», было бы рационально запросить у snmpwalk только ту информацию, которая тебе нужна. Например, чтобы получить список запущенных процессов, достаточно уточнить запрос опцией hrSWRunName (OID 1.3.6.1.2.1.25.4.2.1.2).

root@kali:~# snmpwalk -v 2c -c public 10.10.10.92 hrSWRunName
HOST-RESOURCES-MIB::hrSWRunName.1 = STRING: "systemd"
HOST-RESOURCES-MIB::hrSWRunName.2 = STRING: "kthreadd"
HOST-RESOURCES-MIB::hrSWRunName.4 = STRING: "kworker/0:0H"
HOST-RESOURCES-MIB::hrSWRunName.6 = STRING: "mm_percpu_wq"
HOST-RESOURCES-MIB::hrSWRunName.7 = STRING: "ksoftirqd/0"
HOST-RESOURCES-MIB::hrSWRunName.8 = STRING: "rcu_sched"
HOST-RESOURCES-MIB::hrSWRunName.9 = STRING: "rcu_bh"
HOST-RESOURCES-MIB::hrSWRunName.10 = STRING: "migration/0"
HOST-RESOURCES-MIB::hrSWRunName.11 = STRING: "watchdog/0"
HOST-RESOURCES-MIB::hrSWRunName.12 = STRING: "cpuhp/0"
HOST-RESOURCES-MIB::hrSWRunName.13 = STRING: "kdevtmpfs"
HOST-RESOURCES-MIB::hrSWRunName.14 = STRING: "netns"
HOST-RESOURCES-MIB::hrSWRunName.15 = STRING: "rcu_tasks_kthre"
...

Список запущенных процессов

Вспомним, что мы видели питоновский HTTP-сервер на 3366-м порте TCP и он запрашивал авторизацию. Логин с паролем для такого сервака подаются питону в качестве аргументов командной строки в виде SimpleHTTPAuthServer [-h] [--dir DIR] [--https] port key, поэтому мы можем попробовать отыскать их в захваченном дампе.

Для этого среди записей типа hrSWRunName найдем процесс интерпретатора Python:

root@kali:~# cat snmpwalk.out | grep hrSWRunName | grep python
HOST-RESOURCES-MIB::hrSWRunName.593 = STRING: "python"

И далее по полученному индексу 593 выведем все, что относится к этому процессу в табличке hrSWRunTable.

root@kali:~# cat snmpwalk.out | grep 593
HOST-RESOURCES-MIB::hrSWRunIndex.593 = INTEGER: 593
HOST-RESOURCES-MIB::hrSWRunName.593 = STRING: "python"
HOST-RESOURCES-MIB::hrSWRunID.593 = OID: SNMPv2-SMI::zeroDotZero
HOST-RESOURCES-MIB::hrSWRunPath.593 = STRING: "python"
HOST-RESOURCES-MIB::hrSWRunParameters.593 = STRING: "-m SimpleHTTPAuthServer 3366 loki:godofmischiefisloki --dir /home/loki/hosted/"
HOST-RESOURCES-MIB::hrSWRunType.593 = INTEGER: application(4)
HOST-RESOURCES-MIB::hrSWRunStatus.593 = INTEGER: runnable(2)
HOST-RESOURCES-MIB::hrSWRunPerfCPU.593 = INTEGER: 1129
HOST-RESOURCES-MIB::hrSWRunPerfMem.593 = INTEGER: 13852 KBytes
HOST-RESOURCES-MIB::hrSWInstalledIndex.593 = INTEGER: 593
HOST-RESOURCES-MIB::hrSWInstalledName.593 = STRING: "tzdata-2018d-1"
HOST-RESOURCES-MIB::hrSWInstalledID.593 = OID: SNMPv2-SMI::zeroDotZero
HOST-RESOURCES-MIB::hrSWInstalledType.593 = INTEGER: application(4)
HOST-RESOURCES-MIB::hrSWInstalledDate.593 = STRING: 0-1-1,0:0:0.0

Запись hrSWRunParameters дает нам параметры запуска сервера -m SimpleHTTPAuthServer 3366 loki:godofmischiefisloki --dir /home/loki/hosted/, где находятся нужные нам авторизационные данные loki:godofmischiefisloki.

IPv6-адрес

Просматривая список процессов, я увидел запущенный apache2.

root@kali:~# cat snmpwalk.out| grep hrSWRunName | grep apache
HOST-RESOURCES-MIB::hrSWRunName.770 = STRING: "apache2"
HOST-RESOURCES-MIB::hrSWRunName.2549 = STRING: "apache2"
HOST-RESOURCES-MIB::hrSWRunName.2550 = STRING: "apache2"
HOST-RESOURCES-MIB::hrSWRunName.2551 = STRING: "apache2"
HOST-RESOURCES-MIB::hrSWRunName.2552 = STRING: "apache2"
HOST-RESOURCES-MIB::hrSWRunName.2553 = STRING: "apache2"

При этом Nmap его не показал... Это может означать, что сервер крутится в мире IPv6, и было бы неплохо вытащить соответствующий IP-адрес, чтобы позже инициировать сканирование Nmap повторно (но на этот раз для IPv6-адреса).

root@kali:~# cat snmpwalk.out| grep ipAddressType | grep ipv6
IP-MIB::ipAddressType.ipv6."00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:01" = INTEGER: unicast(1)
IP-MIB::ipAddressType.ipv6."de:ad:be:ef:00:00:00:00:02:50:56:ff:fe:b9:7c:aa" = INTEGER: unicast(1)
IP-MIB::ipAddressType.ipv6."fe:80:00:00:00:00:00:00:02:50:56:ff:fe:b9:7c:aa" = INTEGER: unicast(1)

root@kali:~# ping6 -c2 dead:beef::0250:56ff:feb9:7caa
PING dead:beef::0250:56ff:feb9:7caa(dead:beef::250:56ff:feb9:7caa) 56 data bytes
64 bytes from dead:beef::250:56ff:feb9:7caa: icmp_seq=1 ttl=63 time=43.5 ms
64 bytes from dead:beef::250:56ff:feb9:7caa: icmp_seq=2 ttl=63 time=42.9 ms

--- dead:beef::0250:56ff:feb9:7caa ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 4ms
rtt min/avg/max/mdev = 42.922/43.214/43.507/0.358 ms

Видим маршрутизируемый IPv6-адрес de:ad:be:ef::02:50:56:ff:fe:b9:7c:aa и link-local IPv6-адрес fe:80::02:50:56:ff:fe:b9:7c:aa, которые, кстати, будут меняться при каждом ресете виртуалки.

EUI-64

Рассмотрим, как работает механизм автоматической генерации link-local IPv6-адреса на основе идентификатора EUI-64 из MAC-адреса на примере Mischief.

Для этого нам нужно находиться на одном канальном уровне (OSI layer 2) с тем хостом, адрес которого мы хотим узнать. Чтобы посмотреть, как это работает, залогинимся на другой виртуальной машине с Hack The Box, которая называется Hawk. Так как все запущенные инстансы находятся в одном логическом сегменте (виртуальной) сети 10.10.10.0/24, то мы можем достучаться с Hawk до Mischief. Другими словами, пусть Hawk станет нашим связующим звеном — Pivot Point.

Дадим пинг от Hawk до Mischief и запросим ARP-таблицу для того, чтобы вытащить MAC Mischief.

root@hawk:~$ ping 10.10.10.92
PING 10.10.10.92 (10.10.10.92) 56(84) bytes of data.
64 bytes from 10.10.10.92: icmp_seq=1 ttl=64 time=64.0 ms
^C
--- 10.10.10.92 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 64.063/64.063/64.063/0.000 ms

root@hawk:~$ arp -a
_gateway (10.10.10.2) at 00:50:56:aa:f1:dd [ether] on ens33
? (10.10.10.92) at 00:50:56:b9:7c:aa [ether] on ens33

Добыли MAC-адрес — 00:50:56:b9:7c:aa. Чтобы получить из него link-local IPv6-адрес, нужно провести следующие нехитрые манипуляции:

  1. Сгруппируем MAC в привычной для IPv6 форме, а именно по два октета — 0050:56b9:7caa.
  2. В начало MAC допишем fe80::fe80::0050:56b9:7caa.
  3. В середину MAC вставим ff:fefe80::0050:56ff:feb9:7caa.
  4. Инвертируем шестой бит MAC — fe80::0250:56ff:feb9:7caa (было 0000 0000, стало 0000 0010, или 0x02).
  5. Через символ процента укажем интерфейс (так как в мире IPv6 адреса привязываются к интерфейсам, а не к узлам и, если не указать интерфейс, трафик не будет знать, куда ему идти) — fe80::0250:56ff:feb9:7caa%ens33.

Проверяем, что получилось.

root@hawk:~$ ping6 -c4 fe80::0250:56ff:feb9:7caa%ens33
PING fe80::0250:56ff:feb9:7caa%ens33(fe80::250:56ff:feb9:7caa%ens33) 56 data bytes
64 bytes from fe80::250:56ff:feb9:7caa%ens33: icmp_seq=1 ttl=64 time=136 ms
64 bytes from fe80::250:56ff:feb9:7caa%ens33: icmp_seq=2 ttl=64 time=0.236 ms
64 bytes from fe80::250:56ff:feb9:7caa%ens33: icmp_seq=3 ttl=64 time=0.240 ms
64 bytes from fe80::250:56ff:feb9:7caa%ens33: icmp_seq=4 ttl=64 time=0.272 ms

--- fe80::0250:56ff:feb9:7caa%ens33 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3031ms
rtt min/avg/max/mdev = 0.236/34.259/136.290/58.907 ms

It’s alive! Теоретически можно было бы продолжать прохождение через проксирование Hawk, реализуя схему Proxy Pivoting, если бы была такая необходимость. Но к счастью, нас ждет другой путь.

WWW

Еще несколько инструментов для взаимодействия с SNMP.

  • snmp-check — «из коробки» дает читабельный (но не самый подробный) результат без необходимости ставить MIB. Входит в состав Kali Linux.
  • onesixtyone — утилита для брутфорса строк сообщества. Пригодилась бы нам, если бы дефолтная строка public не подошла.
  • enyx — небольшой скрипт на Python, позволяющий по SNMP узнать IPv6-адрес хоста в одно действие. Интересно, что написал скрипт создатель самой ВМ Mischief.

Продолжение доступно только участникам

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», увеличит личную накопительную скидку и позволит накапливать профессиональный рейтинг Xakep Score! Подробнее

Check Also

Разгоняем микроконтроллер. Как я выжал 620 МГц из совместимой с Arduino платы

Производительности всегда не хватает. Иногда проблему можно решить, просто обновившись до …

4 комментария

  1. Аватар

    Laglag

    19.07.2019 at 13:53

    Вы очень крутые

  2. Аватар

    s00mbre

    22.07.2019 at 06:37

    Качественная статья. Видно затраченное время и усилия, все подробно, как в мануале. Спасибо!

  3. Аватар

    volunteer

    24.07.2019 at 16:10

    Статья супер! К слову о статье(опросе) от главреда — Вот ТАКИХ статей надо больше!

  4. Аватар

    xakep.sub

    26.07.2019 at 18:32

    Тоже подумал об опросе в колонке главреда и отметил про себя тогда, что хочется больше именно такого. Очень круто!

Оставить мнение