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

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CallbackHell — CVE-2021-40449 - Win32k 권한 상승 취약점(LPE)을 위한 익스플로잇 | Kitploit
도구/GitHubGitHub/ly4k/callbackhell
Privilege EscalationVulnerability AnalysisExploitationShellcodePost-ExploitationPayload DevelopmentBinary Exploitation
GitHubly4k/callbackhell

CallbackHell

CVE-2021-40449 - Win32k 권한 상승 취약점(LPE)을 위한 익스플로잇

저장소 보기
481954년 전Kitploit 검토 완료

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CallbackHell

CVE-2021-40449 (Win32k - LPE) 취약점 익스플로잇

  • CallbackHell
    • 설명
    • 기술적 분석
    • PoC
    • 참고 자료

설명

CVE-2021-40449는 Win32k에서 발생하는 use-after-free 취약점으로, 로컬 권한 상승을 가능하게 합니다.

이 취약점은 Kaspersky에 의해 실제 공격 환경에서 발견되었습니다.

발견된 익스플로잇은 다음 Windows 제품을 지원하도록 작성되었습니다.

  • Microsoft Windows Vista
  • Microsoft Windows 7
  • Microsoft Windows 8
  • Microsoft Windows 8.1
  • Microsoft Windows Server 2008
  • Microsoft Windows Server 2008 R2
  • Microsoft Windows Server 2012
  • Microsoft Windows Server 2012 R2
  • Microsoft Windows 10 (빌드 14393)
  • Microsoft Windows Server 2016 (빌드 14393)
  • Microsoft Windows 10 (빌드 17763)
  • Microsoft Windows Server 2019 (빌드 17763)

하지만 현재 이 익스플로잇은 다음 버전에서만 테스트되었습니다.

  • Microsoft Windows 10 (빌드 14393)
  • Microsoft Windows 10 (빌드 17763)

기술적 분석

진행하기 전에 Kaspersky의 기술적 분석을 먼저 읽어보시길 강력히 권장합니다.

Kaspersky의 기술적 분석에서 언급했듯이, 취약점은 GreResetDCInternal에 존재합니다. 공격자가 hdcOpenDCW 호출 중에 호출되는 사용자 모드 콜백 DrvEnablePDEV를 후킹하면, ResetDC를 호출하여 원래 장치 컨텍스트를 파괴할 수 있으며, 이는 사용자 모드 콜백이 반환될 때 커널에서 use-after-free를 유발합니다.

다음 의사 코드는 유출된 Windows XP 소스 코드와 최신 패치 이전 Win32kfull.sys의 GreResetDCInternal 리버스 엔지니어링을 통해 일부 작성되었습니다. 관련 없는 부분은 [...]로 제거했습니다. VULN: 주석을 찾아보세요.

root@kitploit:~
BOOL GreResetDCInternal(
    HDC hdc,
    DEVMODEW *pdmw,
    BOOL *pbBanding,
    DRIVER_INFO_2W *pDriverInfo2,
    PVOID ppUMdhpdev)
{
    // [...]
    HDC hdcNew;

    {
        // Create DCOBJ from HDC
        DCOBJ dco(hdc);

        if (!dco.bValid())
        {
            SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
        }
        else
        {
            // Create DEVOBJ from `dco`
            PDEVOBJ po(dco.hdev());

            // [...]

            // Create the new DC
            // VULN: Can result in a usermode callback that destroys old DC, which
            // invalidates `dco` and `po`
            hdcNew = hdcOpenDCW(L"",
                                pdmw,
                                DCTYPE_DIRECT,
                                po.hSpooler,
                                prton,
                                pDriverInfo2,
                                ppUMdhpdev);

            if (hdcNew)
            {
                po->hSpooler = NULL;

                DCOBJ dcoNew(hdcNew);

                if (!dcoNew.bValid())
                {
                    SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
                }
                else
                {
                    // Transfer any remote fonts

                    dcoNew->pPFFList = dco->pPFFList;
                    dco->pPFFList = NULL;

                    // Transfer any color transform

                    dcoNew->pCXFList = dco->pCXFList;
                    dco->pCXFList = NULL;

                    PDEVOBJ poNew((HDEV)dcoNew.pdc->ppdev());

                    // Let the driver know
                    // VULN: Method is taken from old (possibly destroyed) `po`
                    PFN_DrvResetPDEV rfn = po->ppfn[INDEX_DrvResetPDEV];

                    if (rfn != NULL)
                    {
                        (*rfn)(po->dhpdev, poNew->dhpdev);
                    }

                    // [...]
                }
            }
        }
    }

    // Destroy old DC
    // [...]
}

의사 코드에서 볼 수 있듯이, hdcOpenDCW 호출의 사용자 모드 콜백에서 이전 장치 컨텍스트가 해제될 수 있으며, 이후 DrvResetPDEV 메서드가 이전 장치 컨텍스트에서 가져와 (po->dhpdev, poNew->dhpdev)와 함께 호출됩니다.

장치 컨텍스트를 생성하고 후킹하려면 다음을 수행하면 됩니다.

  • EnumPrinters로 사용 가능한 프린터를 찾습니다.
  • OpenPrinter, GetPrinterDriver 및 LoadLibraryExA를 사용하여 프린터 드라이버를 메모리에 로드합니다.
  • GetProcAddress 및 DrvEnableDriver를 사용하여 프린터 드라이버의 사용자 모드 콜백 테이블을 가져옵니다.
  • VirtualProtect를 사용하여 프린터 드라이버의 사용자 모드 콜백 테이블 보호를 해제합니다.
  • 프린터 드라이버의 원하는 사용자 모드 콜백 테이블 항목을 덮어씁니다.
  • CreateDC(NULL, printerName, NULL, NULL)를 사용하여 프린터의 장치 컨텍스트를 생성합니다.

이제 후킹된 사용자 모드 콜백이 있는 프린터의 장치 컨텍스트가 있어야 합니다.

우리가 관심을 가지는 것은 하나의 후크, 즉 DrvEnablePDEV입니다. 이 후크는 앞서 설명한 대로 두 가지 측면에서 흥미롭습니다. UAF를 트리거하고 인수를 제어할 수 있다는 점입니다. UAF 취약점을 트리거하기 위해 후크 내에서 ResetDC를 호출하여 이전 장치 컨텍스트를 파괴합니다. 후크에서 반환되면, 여전히 첫 번째 GreResetDCInternal 내부에 있으며, 곧 이어 DrvEnablePDEV에서 반환된 두 인수(이전 및 새로운 DHPDEV)와 함께 이전에 파괴된 장치 컨텍스트에서 DrvResetPDEV의 함수 포인터를 가져와 호출합니다.

프로세스가 중간 무결성 수준에서 실행 중인 경우 EnumDeviceDrivers 및 NtQuerySystemInformation의 도움을 받으면 KASLR은 문제가 되지 않습니다.

Kaspersky는 원래 익스플로잇이 임의 메모리 읽기/쓰기를 달성하기 위해 GDI 팔레트 객체와 단일 커널 함수 호출을 사용했다고 언급합니다. 이 익스플로잇은 큰 풀에 BitMapHeader를 할당하는 기술과 RtlSetAllBits를 사용하여 현재 프로세스 토큰의 모든 권한을 활성화합니다. BitMapHeader는 현재 프로세스 토큰의 _SEP_TOKEN_PRIVILEGES를 가리킵니다. RtlSetAllBits(BitMapHeader)를 호출하면 단일 커널 함수 호출로 현재 프로세스 토큰의 모든 권한을 활성화할 수 있습니다. 여기에서 새로운 권한을 남용하여 SYSTEM을 얻을 수 있습니다. 이 익스플로잇은 SeDebugPrivilege를 사용하여 winlogon.exe 프로세스에 셸코드를 주입합니다.

PoC

./poc.png

참고 자료

  • https://securelist.com/mysterysnail-attacks-with-windows-zero-day/104509/
  • https://github.com/siberas/CVE-2016-3309_Reloaded/
  • https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/how-kernel-exploits-abuse-tokens-for-privilege-escalation
  • https://github.com/KaLendsi/CVE-2021-40449-Exploit
  • https://mp.weixin.qq.com/s/AcFS0Yn9SDuYxFnzbBqhkQ
도구 다운로드