Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
blogpost_cve-2018-19987-analysis — Этот репозиторий содержит пост в блоге о моём анализе CVE-2018-19987 — аутентифицированной инъекции команд ОС, затрагивающей несколько маршрутизаторов D-Link. | Kitploit
Инструменты/GitHubGitHub/nahueldsanchez/blogpost_cve-2018-19987-analysis
Безопасность IoTАнализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийСтатьи и ИсследованияОбучение и ОбразованиеАнализ Прошивок
GitHubnahueldsanchez/blogpost_cve-2018-19987-analysis

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

blogpost_cve-2018-19987-analysis

Этот репозиторий содержит пост в блоге о моём анализе CVE-2018-19987 — аутентифицированной инъекции команд ОС, затрагивающей несколько маршрутизаторов D-Link.

Репозиторий
2135 лет назадЕщё не проверено

Анализ CVE-2018-19987 (внедрение команд в ОС D-Link) Twitter URL

Twitter Follow

Всем привет!

В этой короткой записи в блоге я разберу быстрый анализ, который я провел, чтобы лучше понять детали CVE-2018-19987. Сначала я занялся этой CVE, потому что думал, что нет никакой публичной информации или эксплойта. Вскоре после первого анализа я нашел два публичных PoC на GitHub, которые можно найти здесь и здесь.

Так как я уже сделал большую часть работы и не нашел полного анализа, я решил всё же написать пост в блоге.

Надеюсь, вам понравится!

Обновление: Ну... после гугления, когда я застрял с этим постом, я нашел следующую статью, описывающую очень похожую уязвимость (CVE-2018-19986) в D-Link DIR-818. Анализ уязвимостей маршрутизаторов (серия 5): CVE-2018-19986 DIR-818LW&828 анализ и воспроизведение уязвимости внедрения команд (перевод Google) от Ogur1.

Анализ CVE-2018-19987

Я начал свой анализ со сбора всей возможной информации об устройстве:

  • Потребительское название: D-Link DIR-822-US
  • Страница продукта: https://us.dlink.com/en/products/dir-822-d-link-wifi-router-ac1200-dual-band
  • Страница(ы) поддержки: https://support.dlink.com/ProductInfo.aspx?m=DIR-822-US
  • Модель: DIR-822 Ревизия C (Другие устройства были затронуты)
  • Затронутая версия прошивки: FW v3.01B02
  • Имя файла затронутой прошивки: DIR822C1_FW301WWb02.bin (md5sum: 1bff7ec8b4da0643f65b4d44c630e92b)
  • Исправленная версия прошивки: FW v3.13
  • Имя файла исправленной прошивки: DIR822C1_FW313WWb01.bin (md5sum: aa16c7016f67be384e0784e439ce26d2)
  • Страница архива прошивок: ftp://ftp2.dlink.com/PRODUCTS/DIR-822-US/REVC/

Анализ первопричины

Примечание: Весь анализ я проводил с прошивкой v3.01B02.

Публичная информация об этой уязвимости, доступная на странице Mitre, предоставила достаточно информации для начала:

root@kitploit:~
Устройства D-Link DIR-822 Rev.B 202KRb06, DIR-822 Rev.C 3.10B06, DIR-860L Rev.B 2.03.B03, DIR-868L Rev.B 2.05B02, DIR-880L Rev.A 1.20B01_01_i3se_BETA и DIR-890L Rev.A 1.21B02_BETA неправильно обрабатывают IsAccessPoint в /HNAP1/SetAccessPointMode. В исходном коде SetAccessPointMode.php параметр IsAccessPoint сохраняется в файле скрипта ShellPath без какой-либо проверки регулярных выражений. После выполнения файла скрипта происходит внедрение команд. Уязвимое XML-сообщение /HNAP1/SetAccessPointMode может содержать метасимволы оболочки в элементе IsAccessPoint, такие как строка `telnetd`.

Для начала анализа мне нужно было что-то изучить, поэтому я приступил к извлечению файловой системы маршрутизатора.

root@kitploit:~
binwalk -eM DIR822C1_FW301WWb02.bin

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             DLOB firmware header, boot partition: "dev=/dev/mtdblock/1"
10380         0x288C          LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 4213444 bytes
1376372       0x150074        PackImg section delimiter tag, little endian size: 10505216 bytes; big endian size: 5021696 bytes
1376404       0x150094        Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 5019773 bytes, 2282 inodes, blocksize: 131072 bytes, created: 2016-03-18 09:35:31

Как видим, Binwalk обнаруживает файловую систему Linux. Если присмотреться к имеющейся информации, то можно заметить, что в бюллетене упоминается путь /HNAP1. Итак, мы можем начать с изучения того, как маршрутизатор обрабатывает эти URL-адреса.

Обработка запросов HNAP1

Как объясняется в отличном посте в блоге /dev/tty0, эти URL-адреса в конечном итоге обрабатываются бинарным файлом cgibin, расположенным в htdocs/cgibin. Но я хотел лучше понять, как это настроено, и в итоге мне пришлось разобраться, как настроен HTTP-сервер для обработки запросов. Я начал искать имя файла httpd.conf, предполагая, что он используется для настройки HTTP-сервера, и нашел файл с именем HTTP.php в папке /etc/services/, содержащий, среди прочего, следующие интересные строки:

root@kitploit:~
$httpd_conf = "/var/run/httpd.conf";
fwrite("a",$START, "xmldbc -P /etc/services/HTTP/httpcfg.php > ".$httpd_conf."\n");
fwrite("a",$START, "event PREFWUPDATE add /etc/scripts/prefwupdate.sh\n");
fwrite("a",$START, "httpd -f ".$httpd_conf."\n");
fwrite("a",$START, "event HTTP.UP\n");
fwrite("a",$START, "exit 0\n");

Я предположил, что в какой-то момент этот файл выполняется и записывает файл /var/run/httpd.conf. Чтобы узнать, как настроен веб-сервер, я проанализировал файл /etc/services/HTTP/httpcfg.php (я включил только соответствующие части):

root@kitploit:~
	if ($hnap > 0)
	{
		echo
		"		Control".							"\n".
		"		{".									"\n".
		"			Alias /HNAP1".					"\n".
		"			Location /htdocs/HNAP1".		"\n".
		"			External".						"\n".
		"			{".								"\n".
		"				/usr/sbin/hnap { hnap }".	"\n".
		"			}".								"\n".
		"			IndexNames { index.hnap }".		"\n".
		"		}".									"\n";
	}

Теперь у нас есть все фрагменты! Можно предположить, что веб-сервер настроен на обработку HTTP-запросов к /HNAP1 с помощью /usr/sbin/hnap, и, основываясь на посте /dev/tty0, мы знаем, что это будет ссылка на бинарный файл htdocs/cgibin.

Следующим шагом было изучение бинарного файла cgibin, чтобы понять, как он обрабатывает запросы HNAP. На следующем изображении мы видим часть декомпилированной функции main, где переданный путь URL сравнивается с различными путями (такими как session.cgi, authentication.cgi, captcha.cgi и другими), пока не будет найден hnap и не будет вызвана наша функция hnap_main.

примечание: При анализе функции main у меня возникли некоторые проблемы с идентификацией строки hnap, так как Ghidra не определил её как строку во время начального анализа.

Следующим шагом было понять, что делает эта функция. Я предоставлю только фрагменты кода для соответствующих частей, которые помогут лучше понять, что делает функция, а также дополню другие соответствующие части псевдокодом — я переименовал некоторые переменные для ясности их назначения.

root@kitploit:~
...
HTTP_SOAPACTION = getenv("HTTP_SOAPACTION");
REQUEST_METHOD = getenv("REQUEST_METHOD");
HNAP_AUTH = getenv("HTTP_HNAP_AUTH");
__haystack = getenv("HTTP_COOKIE");
pcVar1 = getenv("HTTP_REFERER");

...
if (HTTP_SOAPACTION != "") {
	if  (HTTP_SOAPACTION == GetDeviceSettings) {
		...
	} else {
		// Эти действия будут происходить во время аутентификации. Процесс
		if ("GetCAPTCHAsetting" in HTTP_SOAPACTION) {
			sess_generate_captcha();
		} else {
			if ("Login" in HTTP_SOAPACTION) {
				perform_login();
			}
			// Мы попадем сюда после аутентификации.
			if (HNAP_AUTH != "") {
				if ("uid=" in HTTP_COOKIE){
					is_valid_auth = perform_auth_process()
					if (is_valid_auth) {
						if("logout" in HTTP_SOAPACTION){
							perform_logout();
						// Если мы аутентифицированы и НЕ пытаемся выйти
						// код попытается выполнить запрошенное действие
						} else {
							// Если мы попали сюда, мы победили
							// интересный код ниже
							goto LAB_004141d4;
						}

					}
				}
			}
			// Если мы не аутентифицированы, мы ничего не можем сделать
			Return "You need proper authorization to use this resource"
		}
	}
} else {
	...
}

LAB_004141d4:
    hnap_action = get_hnap_operation(HTTP_SOAPACTION);
    if (HTTP_SOAPACTION != "") {
    	hnap_action_len = strlen(hnap_action);
	}
	snprintf(path_to_hnap_php_file,0x100,"%s/%s.php","/etc/templates/hnap/",hnap_action);
	if (!check_file_access(path_to_hnap_php_file)){
		return "HNAP ACTION DOES NOT EXIST (FAIL)"
	}
	if (REQUEST_METHOD == "POST") {

		// Здесь извлекаются аргументы для PHP
		parse_request_and_extract_xml()
    
		if (hnap_action == "GetFirmwareStatus") {
        	system("sh /etc/events/checkfw.sh > /dev/console");
		}

		// Здесь формируются окончательные аргументы для xmldbc_ephp
        snprintf(ARGS_FOR_XMLDBC_PHP,0x100,"%s%s.php\nShellPath=%s%s.sh\nPrivateKey=%s\n",
                 "/etc/templates/hnap/", hnap_action, &ShellPath, hnap_action, &PRIVATE_KEY);

		// PHP выполняется (в нашем случае SetAccessPointMode.php) и shell
		// скрипт записывается в ShellPath 
        xmldbc_ephp(0,0,ARGS_FOR_XMLDBC_PHP,stdout);
        snprintf(hnap_action, 0x100, "%s", hnap_action);
       
	   	// Строится команда оболочки для выполнения ранее записанного shell файла
		// (Файл, записанный PHP-скриптом)
        shell_command = "sh %s%s.sh > /dev/console &";
        }
        snprintf(cmd_to_execute, 0x100, shell_command, &PATH, hnap_action);

		// Файл выполняется, содержащий внедрение команд
        system(cmd_to_execute);
    }
...

Завершив анализ этой функции, я решил взглянуть на PHP-файл SetAccessPointMode.php — который в итоге и содержал ошибку — и попытался собрать все части вместе:

root@kitploit:~
...
$IsAccessPoint	= query("/runtime/hnap/SetAccessPointMode/IsAccessPoint");
...
fwrite("w",$ShellPath, "#!/bin/sh\n");
fwrite("a",$ShellPath, "echo [$0] $1 ... > /dev/console\n");
fwrite("a",$ShellPath, "echo IsAccessPoint = ".$IsAccessPoint." > /dev/console\n");
fwrite("a",$ShellPath, "echo Result = ".$Result."\n");
...

Как видим, у нас есть переменная $ShellPath, которая заполняется функцией hnap_main, и переменная $IsAccessPoint, контролируемая пользователем и передаваемая в XML-запросе. С помощью этого мы можем подтвердить, как происходит внедрение команд ОС в переменную, записываемую PHP-файлом. Здесь вы можете найти полный PoC, разработанный pr0v3rbs для эксплуатации этой проблемы.

Позже мы обсудим немного больше о затронутых и исправленных версиях. Как вы можете видеть в таблице ниже, похоже, что в патче произошла некая регрессия, которая повторно ввела эту уязвимость в версиях, которые уже должны были быть исправлены.

Проанализированные версии прошивок

(*) Я не проверял эти версии прошивок, так как их незашифрованные аналоги были уязвимы.

Как видно из таблицы выше, уязвимость была исправлена в некоторых версиях прошивок путем удаления затронутого PHP-файла SetAccessPointMode.php. Когда файл отсутствует, проверки, выполняемые в функции, завершаются ошибкой, и ничего не выполняется. Я подтвердил это, проанализировав функцию hnap_function в версиях прошивок FW v3.131 и 3.15B02 WW; код для hnap_main не изменился по отношению к этой проблеме, но PHP-файла больше не было.

Что еще более интересно, так это то, что каким-то образом эта ошибка была повторно введена в версиях прошивок FW v3.11 вплоть до FW v3.12B04 после того, как была исправлена в версии 3.11B01_icjg_WW.

Выводы и следующие шаги

В качестве первого вывода я бы сказал: никогда не доверяйте этим устройствам как по-настоящему безопасным — то, что произошло с обновлениями, является ярким примером того, почему не стоит этого делать. Также после проведенного анализа я могу заключить, что первый PoC, перечисленный в этом посте, не будет работать для этой конкретной версии, так как мы увидели, что для выполнения уязвимого PHP-файла необходимо выполнить некоторые условия.

И самый важный вывод: будьте очень осторожны при определении критичности уязвимости на основе ее оценки CVSS. Я решил проанализировать эту CVE, поскольку она имела оценку 9.8 (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H), и очевидно, что, по крайней мере для этой версии, злоумышленнику потребуются учетные данные для ее эксплуатации.

В качестве следующих шагов я буду работать над возможностью эмулировать этот бинарный файл для эксплуатации этой уязвимости без доступа к самому маршрутизатору, но это будет материалом для другого поста!

Спасибо за чтение.

Ссылки

  • Запись Ogur1 для CVE-2018-19986
  • Пост /dev/tty0 о D-Link HNAP
  • Бюллетень Pedro Ribeiro по HNAP
  • PoC CVE-2018-19987 #0 от Mario Ceballos
  • PoC CVE-2018-19987 #1 от Mingeun Kim
  • Детали CVE-2018-19987 Ссылка
  • Расшифровка прошивок D-Link
  • Binwalk
  • PoC от pro0v3rbs
Скачать инструмент
ПрошивкаВерсияMD5 хэшДата релизаУязвима
DIR822C1_FW315WWb02.bin3.15B02 WW7121771c3e1706ba76fbf244023efad306.11.2019НЕТ
DIR822C1_FW313WWb01.binFW v3.13aa16c7016f67be384e0784e439ce26d210.07.2019НЕТ
DIR822C1_FW303WWb04_i4sa_middle.binFW v3.12B04c3b9a3f115c02e739690616aba2f2d9926.04.2019ДА
DIR822C1_FW312WWb04.binFW v3.12B04eb11afbd136a5b29cea18141f727bfa826.04.2019ДА (*)
DIR822C1_FW311WWb01.binFW v3.116d7c90eaaae835667faea65c862b3c8201.01.2019ДА
DIR822C1_FW311bWWb01_icjg.bin3.11B01_icjg_WW75e361e1465604aeda5d5dbcaecca97721.12.2018НЕТ
DIR822C1_FW303WWb04_i4sa_middle.binFW v3.10B06c3b9a3f115c02e739690616aba2f2d9917.08.2018ДА
DIR822C1_FW310WWb06.binFW v3.10B06e33db75d0801fddb1c90308982e69fe517.08.2018ДА (*)
DIR-822_C1_FW302WWb05.binFW v3.020dbf840c0ff5d3a5b593d33690e15d8214.09.2017ДА
DIR822C1_FW301WWb02.binFW v3.01B021bff7ec8b4da0643f65b4d44c630e92b27.04.2016ДА