Skip to content

Commit

Permalink
Fix security vulnerability that the blacklists are bypassed. (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
ujjboy committed Sep 6, 2018
1 parent 2f125fc commit 09e9cf4
Show file tree
Hide file tree
Showing 9 changed files with 607 additions and 48 deletions.
26 changes: 0 additions & 26 deletions src/main/java/com/caucho/hessian/io/Hessian2Input.java
Original file line number Diff line number Diff line change
Expand Up @@ -2200,12 +2200,6 @@ public Object readObject(Class cl)
if (cl == null || cl == Object.class)
return readObject();

// add by zhiyuan @2018-7-10 if in blacklist will throw exception
ClassNameResolver resolver = findSerializerFactory().getClassNameResolver();
if (resolver != null) {
resolver.resolve(cl.getCanonicalName());
}

int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();

switch (tag) {
Expand All @@ -2214,9 +2208,6 @@ public Object readObject(Class cl)

case 'M': {
String type = readType();
if (resolver != null) {
type = resolver.resolve(type);
}

// hessian/3bb3
if ("".equals(type)) {
Expand Down Expand Up @@ -2652,11 +2643,6 @@ public Object readObject()

case 'M': {
String type = readType();
// add by zhiyuan @2018-7-10
ClassNameResolver resolver = findSerializerFactory().getClassNameResolver();
if (resolver != null) {
type = resolver.resolve(type);
}

return findSerializerFactory().readMap(this, type);
}
Expand Down Expand Up @@ -2720,12 +2706,6 @@ private void readObjectDefinition(Class cl)
{
String type = readLenString();

// add by zhanggeng @2017-7-23
ClassNameResolver resolver = findSerializerFactory().getClassNameResolver();
if (resolver != null) {
type = resolver.resolve(type);
}

int len = readInt();

String[] fieldNames = new String[len];
Expand All @@ -2745,12 +2725,6 @@ private Object readObjectInstance(Class cl, ObjectDefinition def)
{
String type = def.getType();

// add by zhanggeng @2017-7-23
ClassNameResolver resolver = findSerializerFactory().getClassNameResolver();
if (resolver != null) {
type = resolver.resolve(type);
}

String[] fieldNames = def.getFieldNames();

if (cl != null) {
Expand Down
11 changes: 1 addition & 10 deletions src/main/java/com/caucho/hessian/io/Hessian2Output.java
Original file line number Diff line number Diff line change
Expand Up @@ -458,16 +458,7 @@ public void writeObject(Object object)
return;
}

Serializer serializer;

// add by zhanggeng @2017-7-23
Class clazz = object.getClass();
ClassNameResolver resolver = findSerializerFactory().getClassNameResolver();
if (resolver != null) {
resolver.resolve(clazz.getName());
}

serializer = findSerializerFactory().getSerializer(clazz);
Serializer serializer = findSerializerFactory().getSerializer(object.getClass());

serializer.writeObject(object, this);
}
Expand Down
12 changes: 0 additions & 12 deletions src/main/java/com/caucho/hessian/io/HessianInput.java
Original file line number Diff line number Diff line change
Expand Up @@ -1052,12 +1052,6 @@ public Object readObject(Class cl)
case 'M': {
String type = readType();

// add by zhiyuan @2018-7-10
ClassNameResolver resolver = findSerializerFactory().getClassNameResolver();
if (resolver != null) {
type = resolver.resolve(type);
}

// hessian/3386
if ("".equals(type)) {
Deserializer reader;
Expand Down Expand Up @@ -1191,12 +1185,6 @@ public Object readObject()
case 'M': {
String type = readType();

// add by zhiyuan @2018-7-10
ClassNameResolver resolver = findSerializerFactory().getClassNameResolver();
if (resolver != null) {
type = resolver.resolve(type);
}

return _serializerFactory.readMap(this, type);
}

Expand Down
24 changes: 24 additions & 0 deletions src/main/java/com/caucho/hessian/io/SerializerFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,14 @@ public Serializer getSerializer(Class cl)
if (serializer != null)
return serializer;

if (classNameResolver != null) {
try {
classNameResolver.resolve(cl.getName());
} catch (Exception e) {
throw new HessianProtocolException(e);
}
}

for (int i = 0; serializer == null && _factories != null && i < _factories.size(); i++) {
AbstractSerializerFactory factory;

Expand Down Expand Up @@ -265,6 +273,14 @@ public Deserializer getDeserializer(Class cl)
if (deserializer != null)
return deserializer;

if (classNameResolver != null) {
try {
classNameResolver.resolve(cl.getName());
} catch (Exception e) {
throw new HessianProtocolException(e);
}
}

for (int i = 0; deserializer == null && _factories != null && i < _factories.size(); i++) {
AbstractSerializerFactory factory;
factory = (AbstractSerializerFactory) _factories.get(i);
Expand Down Expand Up @@ -428,6 +444,14 @@ public Deserializer getDeserializer(String type)
if (deserializer != null)
return deserializer;

if (classNameResolver != null) {
try {
type = classNameResolver.resolve(type);
} catch (Exception e) {
throw new HessianProtocolException(e);
}
}

if (type.startsWith("[")) {
Deserializer subDeserializer = getDeserializer(type.substring(1));
deserializer = new ArrayDeserializer(subDeserializer);
Expand Down
101 changes: 101 additions & 0 deletions src/test/java/com/alipay/stc/ArrayInjectTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alipay.stc;

import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.SerializerFactory;
import org.junit.Assert;
import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
* 通过数组等其他方式绕过安全黑名单的case
*/
public class ArrayInjectTest {

@Test
public void testHessian2Array() throws IOException {
SerializerFactory factory = new SerializerFactory();
String s = "567400075b6f626a6563746e025674001e5b636f6d2e73756e2e726f777365742e4a646263526f77536574496d706c6e014fad786f6d2e73756e2e726f777365742e4a646263526f77536574496d706cac07636f6d6d616e640355524c0a64617461536f757263650a726f77536574547970650b73686f7744656c657465640c717565727954696d656f7574076d6178526f77730c6d61784669656c6453697a650b636f6e63757272656e637908726561644f6e6c791065736361706550726f63657373696e670969736f6c6174696f6e08666574636844697209666574636853697a6504636f6e6e02707302727306726f77734d44057265734d440d694d61746368436f6c756d6e730f7374724d61746368436f6c756d6e730c62696e61727953747265616d0d756e69636f646553747265616d0b617363696953747265616d0a6368617253747265616d036d6170096c697374656e65727306706172616d736f904e4e4ecbec46909090cbf0545492cbe8904e4e4e4e4e567400106a6176612e7574696c2e566563746f726e0a8f8f8f8f8f8f8f8f8f8f7a76929a4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e7692904d7400136a6176612e7574696c2e486173687461626c657a7a4a027a";
byte[] bs = hex2byte(s.getBytes());
Assert.assertTrue(s.equalsIgnoreCase(byte2hex(bs)));

ByteArrayInputStream input = new ByteArrayInputStream(bs, 0, bs.length);
Hessian2Input hin = new Hessian2Input(input);
hin.setSerializerFactory(factory);

try {
hin.readObject();
Assert.fail();
} catch (Exception e) {
Assert.assertTrue(e instanceof IOException);
}
}

@Test
public void testHessian1Array() throws IOException {
SerializerFactory factory = new SerializerFactory();
String s = "567400075b6f626a6563746e025674001e5b636f6d2e73756e2e726f777365742e4a646263526f77536574496d706c6e014fad786f6d2e73756e2e726f777365742e4a646263526f77536574496d706cac07636f6d6d616e640355524c0a64617461536f757263650a726f77536574547970650b73686f7744656c657465640c717565727954696d656f7574076d6178526f77730c6d61784669656c6453697a650b636f6e63757272656e637908726561644f6e6c791065736361706550726f63657373696e670969736f6c6174696f6e08666574636844697209666574636853697a6504636f6e6e02707302727306726f77734d44057265734d440d694d61746368436f6c756d6e730f7374724d61746368436f6c756d6e730c62696e61727953747265616d0d756e69636f646553747265616d0b617363696953747265616d0a6368617253747265616d036d6170096c697374656e65727306706172616d736f904e4e4ecbec46909090cbf0545492cbe8904e4e4e4e4e567400106a6176612e7574696c2e566563746f726e0a8f8f8f8f8f8f8f8f8f8f7a76929a4e4e4e4e4e4e4e4e4e4e4e4e4e4e4e7692904d7400136a6176612e7574696c2e486173687461626c657a7a4a027a";
byte[] bs = hex2byte(s.getBytes());
Assert.assertTrue(s.equalsIgnoreCase(byte2hex(bs)));

ByteArrayInputStream input = new ByteArrayInputStream(bs, 0, bs.length);
HessianInput hin = new HessianInput(input);
hin.setSerializerFactory(factory);

try {
hin.readObject();
Assert.fail();
} catch (Exception e) {
Assert.assertTrue(e instanceof IOException);
}
}

private String byte2hex(byte[] b) {
StringBuilder hs = new StringBuilder();
String stmp;
for (int n = 0; b != null && n < b.length; n++) {
stmp = Integer.toHexString(b[n] & 0XFF);
if (stmp.length() == 1)
hs.append('0');
hs.append(stmp);
}
return hs.toString().toUpperCase();
}

/**
* 十六转byte
*
* @param b
* @return
*/
private byte[] hex2byte(byte[] b) {
if ((b.length % 2) != 0)
throw new IllegalArgumentException();
byte[] b2 = new byte[b.length / 2];
for (int n = 0; n < b.length; n += 2) {
String item = new String(b, n, 2);
b2[n / 2] = (byte) Integer.parseInt(item, 16);
}
return b2;
}
}
Loading

0 comments on commit 09e9cf4

Please sign in to comment.