
CVE-2021-26084에 대한 기술 분석 및 개념 증명 익스플로잇으로, Atlassian Confluence Server의 OGNL 주입 취약점입니다. 근본 원인 분석, 취약한 매개변수 매핑 및 탐지 지침을 포함합니다.
영향 범위
원인, 악용 방법
Confluence는 프레임워크를 사용하여 URL을 Java 클래스에 매핑하고, 소위 "action"이라고 하는 것을 생성합니다. Action URL은 ".action"으로 끝나며, confluence-.jar의 xwork.xml 파일과 번들 플러그인의 JAR 파일 내 atlassian-plugin.xml 파일에 정의됩니다. 각 action에는 action의 이름을 결정하는 name 속성, action을 수행하는 Java 클래스를 결정하는 class 속성, 그리고 action 호출 후 action의 result에 따라 표시할 Velocity 템플릿을 결정하는 result 요소가 최소한 하나씩 포함됩니다. action에서 반환되는 일반적인 값은 "error", "input", "success"이지만, XWork XML의 result 요소와 일치한다면 다른 결과 값도 사용할 수 있습니다. action에는 지정된 Java 클래스의 특정 메서드를 호출할 수 있게 해주는 method 속성이 포함될 수 있습니다. method가 지정되지 않으면 doDefault() 메서드가 호출됩니다. 아래는 createpage-entervariables action에 대한 action 항목입니다:

com.atlassian.confluence.pages.actions.PageVariablesAction 클래스의 doEnter() 메서드는 doenterpagevariables.action에 대한 요청을 처리하고 "error", "input", "success" 값을 반환합니다. 이에 따라 Velocity 템플릿이 표시됩니다.
여기서 action 요소의 name 속성 값은 /.action 경로에 해당하며, result 요소는 error/success 등에 따라 응답의 일부로 어떤 템플릿이 표시될지 결정합니다. 따라서 이 예시에서는 /pages/doenterpagevariables.action에 접근하기만 하면 velocity 템플릿 파일이 표시됩니다.

HTML 페이지에서 velocity 템플릿이 어떻게 표시되는지 확인할 수 있습니다.

템플릿의 태그 이름을 매개변수로 입력하면, 해당 값이 request 매개변수에서 가져와져 response에 반환되는 것을 확인할 수 있습니다.

#tag 사용 방법: #tag (“attribute1”, “attribute2”, “attribute3”)
이러한 attribute는 렌더링 과정에서 AbstrctTagDirective.applyAttributes()에서 획득됩니다.

#tag ("Hidden" "name='queryString'" "value='ahihihi'")
attribute들이 AbstrctTagDirective.applyAttributes() 메서드에 의해 추출된 후, AbstrctUITag.doEndTag() → AbstractUITag.evaluateParams()로 전달됩니다.

그런 다음 expression 형태로 WebWorkTagSupport.findValue() → OgnlValueFinder.findValue()에 전달됩니다.

이후 SafeExpressionUtil.isSafeExpression()로 전달됩니다.

여기서 expression은 compile 과정을 거쳐 blacklist를 확인하고 cache에 저장됩니다. compile 단계를 거치면 ASTConst 형태로 컴파일되며, 평가될 때 이전에 컴파일된 문자열을 반환합니다.

입력에서 expression에 작은따옴표(')가 추가되면 HTML 엔티티 형태로 이스케이프됩니다.

이스케이프 지점은 HtmlAnnotationEscaper.annotatedValueInsert()입니다.

여기서 ognl.JavaCharStream.readChar() 메서드가 호출되어 Unicode escape 문자를 평가하므로, \u0027을 전달하면 작은따옴표(')로 변환됩니다. 따라서 이를 통해 이스케이프하고 OGNL expression을 추가로 연결할 수 있습니다.

하지만 다음과 같은 OGNL의 blacklist를 우회해야 합니다.

Array accessor를 사용하면 getClass 메서드나 .class 속성을 사용하지 않고 우회할 수 있습니다.
queryString=aaa\u0027%2b#{\u0022\u0022[\u0022class\u0022]}%2b\u0027bbb

탐지 방법
요청 URI의 경로 구성 요소가 아래 표의 "URI Path" 열에 있는 문자열 중 하나를 포함하는 모든 HTTP 트래픽 요청을 모니터링합니다.
URI Path | Vulnerable Parameters
/users/darkfeatures.action | featureKey
/users/enabledarkfeature.action | featureKey
/users/disabledarkfeature.action | featureKey
/login.action | token
/dologin.action | token
/signup.action | token
/dosignup.action | token
/pages/createpage-entervariables.action | queryString, linkCreation
/pages/doenterpagevariables.action | queryString
/pages/createpage.action | queryString
/pages/createpage-choosetemplate.action | queryString
/pages/docreatepagefromtemplate.action | queryString
/pages/docreatepage.action | queryString
/pages/createblogpost.action | queryString
/pages/docreateblogpost.action | queryString
/pages/copypage.action | queryString
/pages/docopypage.action | queryString
/plugins/editor-loader/editor.action | syncRev
이러한 요청이 발견되면 HTTP 요청 메서드를 확인해야 합니다. 요청 메서드가 POST인 경우 위 표의 해당 Vulnerable Parameters를 HTTP 요청 본문에서 찾고, 요청 메서드가 GET인 경우 HTTP 요청의 request-URI에서 매개변수를 찾습니다. 어떤 Vulnerable Parameters의 값에 "\u0027" 문자열 또는 해당 문자열의 URL 인코딩 형태가 포함되어 있는지 확인합니다. 그렇다면 해당 트래픽은 악성으로 간주되며 이 취약점을 악용하려는 공격이 진행 중일 수 있습니다.