點(diǎn)評(píng):記得曾經(jīng)有段時(shí)間很多SRC平臺(tái)被刷了大量APP本地拒絕服務(wù)漏洞,移動(dòng)安全團(tuán)隊(duì)愛(ài)內(nèi)測(cè)(ineice.com)發(fā)現(xiàn)了一個(gè)安卓客戶(hù)端的通用型拒絕服務(wù)漏洞覆履,來(lái)看看他們的詳細(xì)分析吧。
0xr0ot和Xbalien交流所有可能導(dǎo)致應(yīng)用拒絕服務(wù)的異常類(lèi)型時(shí),發(fā)現(xiàn)了一處通用的本地拒絕服務(wù)漏洞硝全。該通用型本地拒絕服務(wù)可以造成大面積的app拒絕服務(wù)栖雾。
針對(duì)序列化對(duì)象而出現(xiàn)的拒絕服務(wù)主要是由于應(yīng)用中使用了getSerializableExtra() 的API,由于應(yīng)用開(kāi)發(fā)者沒(méi)有對(duì)傳入的數(shù)據(jù)做異常判斷伟众,惡意應(yīng)用可以通過(guò)傳入畸形數(shù)據(jù)析藕,導(dǎo)致應(yīng)用本地拒絕服務(wù)。
漏洞應(yīng)用代碼片段:
1 Intent i = getIntent();
2 if(i.getAction().equals("serializable_action")){
3 i.getSerializableExtra("serializable_key"); //未做異常判斷
4 }
攻擊應(yīng)用代碼片段:
1 Intent i = new Intent();
2 i.setAction("serializable_action");
3 i.setClassName("com.exp.serializable", "com.exp.serializable.MainActivity");
4 i.putExtra("seriadddddlizable_dkey",XXX); //此處是傳入畸形數(shù)據(jù)
5 startActivity(i);
比如XXX處傳入BigInteger.valueOf(1)極有可能發(fā)生轉(zhuǎn)型異常錯(cuò)誤java.lang.ClassCastException赂鲤。
但后來(lái)交流中發(fā)現(xiàn)噪径,當(dāng)傳入一個(gè)自定義的序列化對(duì)象Serializable或getParcelable對(duì)象時(shí),接收Intent的目標(biāo)組件在getSerializableExtra()数初、getParcelable()等會(huì)拋出類(lèi)未定義的異常java.lang.NoClassDefFoundError找爱。這是因?yàn)楫?dāng)你給漏洞應(yīng)用傳入一個(gè)應(yīng)用本身并沒(méi)有的序列化類(lèi)對(duì)象,在應(yīng)用上下文中肯定是找不到這個(gè)類(lèi)的泡孩。
自定義的序列化類(lèi)很簡(jiǎn)單:
1 public class DataSchema implements Serializable {
2 private static final long serialVersionUID = -3601187837704976264L;
3 public DataSchema() {
4 super();
5 }
6 }
對(duì)應(yīng)的攻擊代碼中XXX處傳入new DataSchema(),我們發(fā)現(xiàn)傳入的key不管是否與漏洞應(yīng)用相同车摄,都會(huì)拋出類(lèi)未定義的異常。
隨著測(cè)試的深入仑鸥,我們通過(guò)logcat發(fā)現(xiàn)吮播,在錯(cuò)誤日志里不一定是getSerializableExtra()、getParcelable()導(dǎo)致的眼俊。然后我們就延伸了下意狠,試著向getXXXExtra()傳入我們自定義的序列化類(lèi)對(duì)象,發(fā)現(xiàn)都會(huì)拋出類(lèi)未定義的異常疮胖。
測(cè)試app代碼片段:
1 protected void onCreate(Bundle savedInstanceState) {
2 Intent intent = getIntent();
3 intent.getStringExtra("ROIS"); //此處依然會(huì)由于NoClassDefFoundError crash
4 }
接著我們測(cè)試了市面上大量主流應(yīng)用环戈,涵蓋BAT等。發(fā)現(xiàn)這種方法可以通殺澎灸。我們開(kāi)始覺(jué)得這個(gè)是android本身的問(wèn)題院塞,開(kāi)始翻源代碼。
01 public String getStringExtra(String name) {
02 return mExtras == null ? null : mExtras.getString(name);
03 }
04 /frameworks/base/core/java/android/os/Bundle.java
05 public String getString(String key) {
06 unparcel(); //處理數(shù)據(jù)
07 ...
08 }
09 /* package */ synchronized void unparcel() {
10 ...
11 mParcelledData.readMapInternal(mMap, N, mClassLoader);
12 ...
13 }
14
15 /frameworks/base/core/java/android/os/Parcel.java
16 readMapInternal解析傳遞進(jìn)來(lái)的數(shù)據(jù)