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

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

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

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2015-2291 — (1) IQVW32.sys 1.3.1.0 이전 버전 및 (2) IQVW64.sys 1.3.1.0 이전 버전(Windows용 Intel 이더넷 진단 드라이버에 포함됨)은 로컬 사용자가 제작된 (a) 0x80862013, (b) 0x8086200B, (c) 0x8086200F 또는 (d) 0x80862007 IOCTL 호출을 통해 서비스 거부를 일으키거나 커널 권한으로 임의 코드를 실행할 수 있도록 합니다. | Kitploit
도구/GitHubGitHub/gmh5225/cve-2015-2291
Privilege EscalationVulnerability AnalysisExploitationPapers & ResearchLearning & EducationBinary Exploitation
GitHubgmh5225/cve-2015-2291

CVE-2015-2291

(1) IQVW32.sys 1.3.1.0 이전 버전 및 (2) IQVW64.sys 1.3.1.0 이전 버전(Windows용 Intel 이더넷 진단 드라이버에 포함됨)은 로컬 사용자가 제작된 (a) 0x80862013, (b) 0x8086200B, (c) 0x8086200F 또는 (d) 0x80862007 IOCTL 호출을 통해 서비스 거부를 일으키거나 커널 권한으로 임의 코드를 실행할 수 있도록 합니다.

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

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2015-2291

(1) IQVW32.sys 1.3.1.0 이전 버전 및 (2) IQVW64.sys 1.3.1.0 이전 버전(Windows용 인텔 이더넷 진단 드라이버)은 로컬 사용자가 조작된 (a) 0x80862013, (b) 0x8086200B, (c) 0x8086200F 또는 (d) 0x80862007 IOCTL 호출을 통해 서비스 거부를 일으키거나 커널 권한으로 임의 코드를 실행할 수 있도록 합니다.

개요

이 저장소에는 해당 취약점에 대한 분석 자료와 64비트 Windows 7 SP1 및 Windows 10 20H2에서 작동하는 개념 증명 익스플로잇이 포함되어 있습니다. 드라이버 파일은 드라이버 파일 디렉터리에서 찾을 수 있습니다. 분석 자료/문서에서 오타를 발견하거나 특정 세부 사항에 대해 더 자세한 설명을 보고 싶다면 저장소에 이슈를 생성해 주세요! 최대한 빨리 수정하겠습니다.

동기

특히 이 디바이스 드라이버에 대한 익스플로잇을 작성하는 동기는 현재 이 드라이버가 악의적인 서명되지 않은 루트킷을 로드하기 위해 실제 환경에서 남용되고 있기 때문입니다. BYOVD(취약한 드라이버 가져오기) 방법을 사용하여 맬웨어는 상승된 권한으로 실행 중인지 확인하고, 취약한 드라이버 복사본을 드롭한 다음 드라이버를 로드하고, 이를 악용하여 커널 코드 실행 권한을 얻어 루트킷을 로드할 수 있습니다. 맬웨어 샘플을 성공적으로 리버스 엔지니어링하지 못했기 때문에 익스플로잇을 직접 만들기로 결정했습니다.

실제 환경에서 발견된 샘플: https://bazaar.abuse.ch/sample/84ed7fec67de5621806dbb43af5167a5fc60ab7f2403448519dc0eca2b8f9022/ https://bazaar.abuse.ch/sample/0925b8985b19d7925d68186d666b0050a4cb3f2a577d64765d770a57a2eab9ae/ https://bazaar.abuse.ch/sample/e8b7f42d544fe8b954c4021315cff2fdd44d67d11704009cdf3037d34e0c0a93/

CVE-2015-2291 - 익스플로잇 기술 분석

디바이스 드라이버 iqvw64e.sys는 네트워크 어댑터 진단을 수행하도록 설계된 드라이버입니다. 사용자 모드 구성 요소가 디바이스 드라이버와 상호 작용하여 다양한 커널 루틴을 수행할 수 있도록 몇 가지 IO 제어 코드(IOCTL이라고도 함)를 노출하며, 상호 작용 중 사용자 입력 버퍼에 "하위" IO 제어 코드가 제공됩니다. 취약한 코드 경로를 트리거하는 데 사용될 IO 제어 코드는 0x80862007입니다. 기본 제어 코드 외에도 이 분석에서 다룰 "하위" IO 제어 코드는 memmove 함수 호출을 트리거하는 0x33 코드와 memset 함수 호출 코드 경로를 트리거하는 0x30 코드입니다. 이 분석에서는 DriverEntry 루틴에 대한 세부 사항은 다루지 않습니다. 이에 대한 자세한 설명은 Microsoft 설명서 페이지에 충분히 나와 있습니다.

먼저, 이 특정 디바이스 드라이버와 어떻게 상호 작용할 수 있는지 알아야 합니다. 디바이스 드라이버와 통신하는 가장 일반적인 방법은 DeviceIoControl이라는 함수를 사용하는 것입니다. 이 함수의 기본 개념은 CreateFileA로 생성된 유효한 드라이버 핸들을 전달하고, 원하는 커널 루틴에 해당하는 IO 제어 코드를 전달하고, 예상되는 구조체(또는 버퍼)를 전달하면 출력 버퍼에 데이터가 반환된다는 것입니다. 이러한 루틴이 때때로 필요할 수 있지만(예: 오버클러킹 목적의 모델별 레지스터 액세스), 보안에 심각한 위험을 초래하기도 합니다. 하지만 어떻게 말이죠?

CVE-2015-2291의 경우, 권한이 없는 사용자에 의해 취약점이 트리거될 수 있습니다. 검증 검사가 없고 취약점을 악용하는 데 관리자 권한이 필요하지 않기 때문에 보안 위험이 발생합니다. 이 두 가지 결함 아래에는 IO 제어 코드 인터페이스에 의해 노출된 memset 및 memmove 함수 호출을 완전히 제어할 수 있는 능력이 있습니다. 이전에 언급한 DeviceIoControl 함수를 기억하시나요? 커널 루틴에서 사용될 구조체를 전달할 수 있다고 했죠? 이 모든 것이 어떻게 연결되는지 보여줍니다.

잠시 뒤로 물러서 보겠습니다. 먼저 취약한 디바이스 드라이버와 관련된 드라이버 핸들을 얻어야 합니다. 하지만 그 전에도, 해당하는 명명된 디바이스 개체를 찾아야 합니다. 이 개체는 기호 링크(일반적으로 하드 코딩됨)를 통해 사용자 공간에 노출되며, SysInternals 제품군의 일부인 WinObj를 사용하여 찾을 수 있습니다. 문자열 덤프 유틸리티를 사용하여 기호 링크를 덤프하거나 디바이스 드라이버를 리버스 엔지니어링할 수도 있지만, 간단히 드라이버를 로드하고 WinObj를 사용하여 찾았습니다. 디바이스 드라이버와 관련된 기호 링크는 \\.\GLOBALROOT\Device\Nal입니다. 드라이버 핸들을 얻으려면 CreateFileA 함수를 호출하고 프로세스의 이후 단계에서 사용할 유효한 드라이버 핸들을 반환하도록 해야 합니다. 이 과정의 코드는 다음과 같습니다:```C if (h_nal == (HANDLE)-1) { printf("\n[-] Unable to obtain a driver handle to the Nal device driver. Error: %d (0x%x)", GetLastError(), GetLastError()); unused = getchar(); return 1; } printf("\n[+] Obtained a driver handle to the Nal device driver. Handle Value: 0x%p", h_nal);

우리는 exploitation 과정 후반에 드라이버 핸들을 사용할 것입니다. 지금은 익스플로잇 준비를 시작하겠습니다. 다음 단계는 [LoadLibraryA](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya) 함수를 사용하여 `ntdll.dll` 라이브러리를 로드하여 [모듈 핸들](https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types)을 반환받는 것입니다. 이를 통해 필요한 함수들을 동적으로 찾을 수 있습니다. `ntdll.dll` 라이브러리가 이미 우리 프로세스에 로드되어 있을 수 있지만, 그럼에도 사용할 수 있는 라이브러리 핸들을 얻어야 합니다. 익스플로잇에 필요한 함수들은 [NtQuerySystemInformation](https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation) (중간 프로세스 무결성으로 NT 커널의 베이스 주소를 유출하기 위해 exploitation 과정 후반에 사용)과 [NtQueryIntervalProfile](http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FProfile%2FNtQueryIntervalProfile.html) 함수(취약점을 트리거하기 위해)입니다. `ntdll.dll` 라이브러리를 로드하는 코드는 다음과 같습니다:```C
h_ntdll = LoadLibraryA("C:\\Windows\\System32\\ntdll.dll");
if (!h_ntdll)
{
	printf("\n[-] Failed to load the \"ntdll.dll\" API library. Error: %d (0x%x)", GetLastError(), GetLastError());
	unused = getchar();
	return 0;
}
printf("\n[+] Loaded the \"ntdll.dll\" API library. Handle Value: 0x%p", h_ntdll);

이제 라이브러리에 대한 핸들을 획득했으므로, NtQueryIntervalProfile 함수를 찾는 것으로 시작하겠습니다. 시작하려면 이 함수가 문서화되지 않았기 때문에 해당 함수의 타입 정의가 필요합니다. 온라인에서 타입 정의를 찾을 수 있지만, 여기서 더 쉽게 접근할 수 있도록 제공합니다:```C typedef unsigned int(__stdcall* NtQueryIntervalProfile)( unsigned int ProfileSource, PULONG Interval );

이 함수를 사용하려면 `NtQueryIntervalProfile` 타입을 사용하여 변수(로컬 또는 전역, 선택)를 선언해야 합니다. 그렇다면 이 변수를 실제 함수로 어떻게 변환할까요? 이를 위해 [GetProcAddress](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress)라는 함수를 사용할 것입니다. 검색하려는 모듈에 대한 핸들(첫 번째 매개변수)을 전달하고 함수 이름(두 번째 매개변수)을 전달하면 모듈에서 원하는 함수를 찾아 해당 함수에 대한 포인터를 검색할 수 있습니다! 이 정보를 처리하는 데 도움이 되는 코드가 제공됩니다.```C
_NtQueryIntervalProfile = (NtQueryIntervalProfile)GetProcAddress(h_ntdll, "NtQueryIntervalProfile");
if (!_NtQueryIntervalProfile)
{
	printf("\n[-] Failed to locate the \"NtQueryIntervalProfile\" function. Error: %d (0x%x)", GetLastError(), GetLastError());
	unused = getchar();
	return 1;
}
printf("\n[+] Located the \"NtQueryIntervalProfile\" function. Function Address: 0x%p", _NtQueryIntervalProfile);

함수를 동적으로 로드하고 사용할 수 있는 이유는 함수 자체가 실행 가능한 코드에 대한 포인터이기 때문입니다. 함수의 실제 본문은 실행될 코드입니다.

이제 NtQueryIntervalProfile 함수 포인터를 해결했으므로, 여전히 NtQuerySystemInformation 함수의 주소를 검색해야 합니다. 마찬가지로 이전과 같이, 이 함수에 대한 형식 정의가 필요하며, 함수를 호출하기 위해 변수를 선언해야 합니다. 또한 이전과 같이, 접근 용이성을 위해 형식 정의를 제공했습니다.```C typedef NTSTATUS(WINAPI* NtQuerySystemInformation)( SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength );

그리고, 마찬가지로 이전과 같이, 우리는 함수를 찾아야 합니다. 이전 `GetProcAddress` 호출과 이번 호출의 유일한 차이점은 우리가 찾고 있는 함수입니다. 함수를 복사하고 두 번째 매개변수를 변경하여 두 번째 함수를 검색할 수 있습니다. 코드가 작성된 후에는 다음과 유사한 결과가 나와야 합니다:```C
_NtQuerySystemInformation = (NtQuerySystemInformation)GetProcAddress(h_ntdll, "NtQuerySystemInformation");
if (!_NtQuerySystemInformation)
{
	printf("\n[-] Failed to locate the \"NtQuerySystemInformation\" function. Error: %d (0x%x)", GetLastError(), GetLastError());
	unused = getchar();
	return 0;
}
printf("\n[+] Located the \"NtQuerySystemInformation\" function. Function Address: 0x%p", _NtQuerySystemInformation);

Perfect! 필요한 모든 비존재 함수들을 찾았습니다. 이제 NT 커널 베이스 주소를 유출해야 합니다. NtQuerySystemInformation의 도움으로 현재 로드된 모든 디바이스 드라이버의 베이스 주소 및 기타 정보를 반환하는 쿼리를 생성할 수 있습니다. NtQuerySystemInformation 함수의 첫 번째 매개변수는 열거형이며, 특히 공개적으로 문서화되지 않은 것입니다. 해당 열거형은 SystemModuleInformation이며, 해당 값은 0xB입니다. 그런 다음 반환된 구조체 중 하나에 대한 포인터를 전달해야 합니다. 필요한 구조체와 열거형은 아래에 제공되며, FuzzySecurity (@b33f)의 제공입니다:```C typedef enum _SYSTEM_INFORMATION_CLASS { SystemModuleInformation = 0xB, } SYSTEM_INFORMATION_CLASS;

typedef struct SYSTEM_MODULE { ULONG Reserved1; ULONG Reserved2; ULONG Reserved3; PVOID ImageBaseAddress; ULONG ImageSize; ULONG Flags; WORD Id; WORD Rank; WORD LoadCount; WORD NameOffset; CHAR Name[256]; } SYSTEM_MODULE, * PSYSTEM_MODULE;

도구 다운로드