Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
blogpost_cve-2018-19987-analysis — 이 리포지토리에는 여러 D-Link 라우터에 영향을 미치는 인증된 OS 명령 주입 취약점인 CVE-2018-19987에 대한 분석 블로그 게시물이 있습니다. | Kitploit
도구/GitHubGitHub/nahueldsanchez/blogpost_cve-2018-19987-analysis
IoT SecurityVulnerability AnalysisExploitationWeb Application ExploitationPapers & ResearchLearning & EducationFirmware Analysis
GitHubnahueldsanchez/blogpost_cve-2018-19987-analysis

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

blogpost_cve-2018-19987-analysis

이 리포지토리에는 여러 D-Link 라우터에 영향을 미치는 인증된 OS 명령 주입 취약점인 CVE-2018-19987에 대한 분석 블로그 게시물이 있습니다.

저장소 보기
215년 전아직 검토되지 않음

CVE-2018-19987 (D-Link OS 명령 주입) 분석 Twitter URL

Twitter Follow

안녕하세요!

이 짧은 블로그 게시물에서는 CVE-2018-19987의 세부 사항을 더 잘 이해하기 위해 수행한 간단한 분석을 설명하겠습니다. 처음에는 이 CVE에 대한 공개 정보나 익스플로잇이 없다고 생각해서 이 CVE를 추적하기 시작했습니다. 첫 번째 분석을 수행한 직후, 여기와 여기에서 찾을 수 있는 두 개의 공개 PoC를 GitHub에서 발견했습니다.

이미 대부분의 작업을 수행했고 완전한 분석을 찾지 못했기 때문에 어쨌든 블로그 게시물을 작성하기로 결정했습니다.

재미있게 읽으시길 바랍니다!

업데이트: 음.. 이 블로그 게시물을 작성하는 동안 막혀서 구글링을 하다가 D-Link DIR-818에서 매우 유사한 취약점(CVE-2018-19986)을 설명하는 다음 기사를 발견했습니다. 라우터 취약점 분석 시리즈 (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, and DIR-890L Rev.A 1.21B02_BETA devices mishandle IsAccessPoint in /HNAP1/SetAccessPointMode. In the SetAccessPointMode.php source code, the IsAccessPoint parameter is saved in the ShellPath script file without any regex checking. After the script file is executed, the command injection occurs. A vulnerable /HNAP1/SetAccessPointMode XML message could have shell metacharacters in the IsAccessPoint element such as the `telnetd` string.

분석을 시작하려면 살펴볼 무언가가 필요했기 때문에 라우터의 파일 시스템(FS)을 추출했습니다.

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은 궁극적으로 htdocs/cgibin에 위치한 cgibin이라는 바이너리에 의해 처리됩니다. 하지만 저는 이것이 어떻게 구성되었는지 더 잘 이해하고 싶었고, 결국 HTTP 서버가 요청을 처리하도록 어떻게 구성되었는지 이해해야 했습니다. HTTP 서버를 구성하는 데 사용된다고 가정하고 httpd.conf 파일을 찾아보았고, /etc/services/ 폴더 아래에서 HTTP.php라는 파일을 발견했습니다. 이 파일에는 무엇보다도 다음과 같은 흥미로운 줄이 포함되어 있습니다:

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";
	}

이제 모든 조각이 모였습니다! 웹 서버가 /usr/sbin/hnap을 사용하여 /HNAP1에 대한 HTTP 요청을 처리하도록 구성되어 있다고 가정할 수 있으며, /dev/tty0 블로그 게시물을 기반으로 이것이 htdocs/cgibin 바이너리에 대한 링크라는 것을 알고 있습니다.

다음 단계는 cgibin 바이너리를 살펴보고 HNAP 요청을 어떻게 처리하는지 이해하는 것이었습니다. 다음 이미지에서 디컴파일된 main 함수의 일부를 볼 수 있습니다. 전달된 URL 경로는 hnap이 발견되고 hnap_main 함수가 호출될 때까지 다양한 경로(예: session.cgi, authentication.cgi, captcha.cgi 등)와 비교됩니다.

참고: 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 {
		// These actions will occur during auth. Process
		if ("GetCAPTCHAsetting" in HTTP_SOAPACTION) {
			sess_generate_captcha();
		} else {
			if ("Login" in HTTP_SOAPACTION) {
				perform_login();
			}
			// We'll land here once auth.
			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();
						// If we are auth. and NOT trying to logout
						// the code will try to perform the action
						// we requested
						} else {
							// If we arrive here we win
							// interesting code below
							goto LAB_004141d4;
						}

					}
				}
			}
			// If we are not authenticated we can't do anything
			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") {

		// Here arguments for the PHP are extracted
		parse_request_and_extract_xml()
    
		if (hnap_action == "GetFirmwareStatus") {
        	system("sh /etc/events/checkfw.sh > /dev/console");
		}

		// Here the final arguments for the xmldbc_ephp are crafted
        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 is executed (in our case SetAccessPointMode.php) and the shell
		// script is written to ShellPath 
        xmldbc_ephp(0,0,ARGS_FOR_XMLDBC_PHP,stdout);
        snprintf(hnap_action, 0x100, "%s", hnap_action);
       
	   	// Shell command is built to run the previously written shell file
		// (File written by the PHP script)
        shell_command = "sh %s%s.sh > /dev/console &";
        }
        snprintf(cmd_to_execute, 0x100, shell_command, &PATH, hnap_action);

		// File is executed containing the command injection
        system(cmd_to_execute);
    }
...

이 함수에 대한 분석이 완료된 후, SetAccessPointMode.php 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");
...

보시다시피, hnap_main 함수에 의해 채워지는 $ShellPath 변수와 사용자가 제어하고 전송된 XML 요청에 전달되는 $IsAccessPoint 변수가 있습니다. 이를 통해 PHP 파일에 의해 작성된 변수에서 OS 명령 주입이 어떻게 실행되는지 확인할 수 있습니다. 여기에서 이 문제를 익스플로잇하기 위해 pr0v3rbs가 개발한 전체 PoC를 찾을 수 있습니다.

영향을 받는 버전과 수정된 버전에 대해서는 나중에 조금 더 논의하겠습니다. 아래 표에서 볼 수 있듯이, 패치에 일종의 회귀(regression)가 있었던 것 같습니다. 이로 인해 이미 패치되었어야 할 버전에서 이 취약점이 다시 도입되었습니다.

분석된 펌웨어 버전

(*) 암호화되지 않은 해당 펌웨어 버전이 취약했기 때문에 이 펌웨어 버전들은 확인하지 않았습니다.

위 표에서 볼 수 있듯이, 취약점은 영향을 받는 PHP 파일 SetAccessPointMode.php를 제거함으로써 일부 펌웨어 버전에서 수정되었습니다. 파일이 존재하지 않으면 함수에서 수행되는 검사가 실패하고 아무것도 실행되지 않습니다. 펌웨어 버전 FW v3.131 및 3.15B02 WW에서 hnap_function을 분석하여 이를 확인했습니다. hnap_main의 코드는 이 문제와 관련하여 변경되지 않았지만 PHP 파일은 더 이상 존재하지 않았습니다.

더 흥미로운 점은 이 버그가 버전 3.11B01_icjg_WW에서 패치된 후, 어떻게든 펌웨어 버전 FW v3.11부터 FW v3.12B04까지 다시 도입되었다는 것입니다.

결론 및 다음 단계

첫 번째 결론으로, 이러한 기기를 진정한 보안 장치로 절대 신뢰하지 말아야 한다고 말하고 싶습니다 — 업데이트에서 일어난 일은 왜 그렇게 해서는 안 되는지에 대한 명확한 예입니다. 또한 수행한 분석을 바탕으로, 이 블로그 게시물에 나열된 첫 번째 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)로 평가되었기 때문에 분석하기로 결정했습니다. 적어도 이 버전의 경우, 공격자가 이를 익스플로잇하려면 자격 증명이 필요하다는 것이 분명합니다.

다음 단계로는 라우터 자체에 접근하지 않고도 이 취약점을 익스플로잇할 수 있도록 이 바이너리를 에뮬레이션하는 작업을 할 것입니다. 하지만 그것은 다음 게시물의 주제가 될 것입니다!

읽어주셔서 감사합니다.

참고 자료

  • CVE-2018-19986에 대한 Ogur1 분석 글
  • /dev/tty0 D-Link HNAP 블로그 게시물
  • Pedro Ribeiro의 HNAP 권고
  • CVE-2018-19987 PoC #0, Mario Ceballos 작성
  • CVE-2018-19987 PoC #1, Mingeun Kim 작성
  • CVE-2018-19987 세부 정보 링크
  • D-Link 펌웨어 복호화
  • Binwalk
  • pro0v3rbs PoC
도구 다운로드
펌웨어버전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예