🇰🇷 한글 설명
Apache OpenNLP의 세 가지 코드 경로(GeneratorFactory, StreamFactoryRegistry.getFactory, StringInterners)에서 클래스명을 검증 없이 Class.forName()으로 로드하고 기본 생성자를 호출하여 임의 클래스 인스턴스화가 가능합니다. 공격자가 조작된 모델 파일이나 포맷명을 제공하면 classpath에 있는 특정 클래스가 실행될 수 있으며, 이는 즉각적인 원격 코드 실행은 아니지만 부작용이 있는 클래스와 결합 시 위험합니다.
💡 쉬운 설명
Apache OpenNLP라는 자연어 처리 도구가 외부에서 주어진 이름의 프로그램 부품을 검사 없이 실행할 수 있는 문제입니다. 악성 모델 파일을 사용하면 공격자가 원하는 동작을 일으킬 수 있으니 업데이트가 필요합니다.
🇺🇸 원문 (English)
Arbitrary Class Instantiation via XML Feature Generator Descriptor and Format Name in Apache OpenNLP
Versions Affected:
- before 2.5.10
- before 3.0.0-M5
Description:
Three code paths in Apache OpenNLP load a class by its fully-qualified name via Class.forName() and invoke its no-arg constructor without any prior validation of the class name or its type.
The affected paths are:
(1) GeneratorFactory, which reads the class attribute of generator elements in an XML feature generator descriptor; such descriptors are embedded as artifacts in model archives (e.g. TokenNameFinder and POSTagger models) and are parsed during model loading, so an attacker who can supply a crafted model archive controls the class name directly.
(2) StreamFactoryRegistry.getFactory(Class, String), which falls back to interpreting an unregistered format name as the fully-qualified class name of an ObjectStreamFactory; this is exploitable in applications that pass untrusted format names (e.g. exposing the -format parameter of the command-line tooling to external input).
(3) StringInterners, which instantiates the interner implementation named by the opennlp.interner.class system property; this value is normally deployer-controlled, so it is hardened as defense in depth rather than being independently attacker-reachable.
Exploitation requires a class with attacker-useful side effects in its static initializer or no-arg constructor (JNDI lookup, outbound network I/O, filesystem access) to be present on the classpath, so this is not drop-in remote code execution. T
Mitigation:
Upgrade to a fixed release.
The fix routes all three paths through ExtensionLoader.instantiateExtension(...), which consults a package-prefix allowlist before Class.forName() is invoked, so a disallowed class is never loaded, initialized, or constructed.
Classes under the opennlp. prefix remain permitted by default. Deployments that load models referencing feature generator factories, object stream factories, or string interners outside opennlp.* must opt those packages in, either programmatically via ExtensionLoader.registerAllowedPackage(String) before the first model load, or by setting the OPENNLP_EXT_ALLOWED_PACKAGES system property to a comma-separated list of allowed package prefixes.
Users who cannot upgrade immediately should ensure all model files and format names are sourced from trusted origins and should audit their classpath for classes with side-effecting static initializers or constructors.
📍 영향받는 시스템
Apache OpenNLP 2.5.10 미만 및 3.0.0-M5 미만 버전
⚔️ 공격 벡터
조작된 모델 아카이브 또는 신뢰할 수 없는 포맷명을 통해 classpath의 부작용 있는 클래스를 인스턴스화
🛡️ 대응 방법
OpenNLP를 2.5.10 이상 또는 3.0.0-M5 이상으로 업그레이드하고, 필요시 OPENNLP_EXT_ALLOWED_PACKAGES로 허용 패키지를 제한
🔧 검증 코드
출력된 Implementation-Version이 2.5.10 또는 3.0.0-M5 이상이면 패치된 버전이며, 그보다 낮으면 취약한 버전이므로 업그레이드가 필요합니다.
find / -name 'opennlp-*.jar' 2>/dev/null | xargs -I{} sh -c 'unzip -p {} META-INF/MANIFEST.MF 2>/dev/null | grep -i version'