logo
DATABASE RESOURCES PRICING ABOUT US

3 6 0 Free WIFI encryption signature crack get the others Wi-plaintext-password-vulnerability warning-the black bar safety net

Description

| Vulnerability title | 3 6 0 Free WIFI encryption signature crack get the others Wi plaintext password(you can also brush the gold exchange carriers flow) ---|--- Relevant vendor | qihoo 3 6 0 The vulnerability of the author | thin Jiao dance Submit time | 2015-09-17 1 6:3 0 Open time | 2015-12-16 1 8:1 8 Vulnerability type | design errors/logic flaws Hazard level | high The self-assessment Rank | 1 5 Vulnerability status | vendors have confirmed Tags | [a client programming error](<http://www.secpulse.com/archives/tag/%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E9%94%99%E8%AF%AF>),[logic error](<http://www.secpulse.com/archives/tag/%E9%80%BB%E8%BE%91%E9%94%99%E8%AF%AF>) ## Vulnerability details First round:encryption and decryption break According to the characteristics of the positioning feature points code According to the http request method=Wifi. password for the feature,the location request package code exists on the qE class ! [wifipassword. png](/Article/UploadPic/2015-12/2 0 1 5 1 2 1 7 1 5 2 7 4 8 9 6 6. png) Next, the function of the hook analysis ! [hookpara. png](/Article/UploadPic/2015-12/2 0 1 5 1 2 1 7 1 5 2 7 5 2 1 4 6. png) Traced to its encryption method is DESede (DESede is by DES a symmetric encryption algorithm to improve after a symmetric encryption algorithm. The use of 1 to 6 8-bit key information on the three encryption mechanism ),the implementation class for the vA ! [des. png](/Article/UploadPic/2015-12/2 0 1 5 1 2 1 7 1 5 2 7 5 5 8 7 6. png) Next you want to do is locate the DESede key can be cracked complete http request encryption and decryption of the entire process and your own code to achieve. ! [init. png](/Article/UploadPic/2015-12/2 0 1 5 1 2 1 7 1 5 2 7 5 7 2 3 6. png) Now start tracking the key generation algorithm. From the following code can be that the init of the key is made public static String a(String arg2) method to get the. From the code that the key generation is actually by com. qihoo. freewifi. utils. SecurityUtils complete ! [getkey. png](/Article/UploadPic/2015-12/2 0 1 5 1 2 1 7 1 5 2 7 5 8 3 0 9. png) Where getkey is a native method (as can be seen in the app of the protected work primarily on the protection key on) public static native String getKey(String paramString1, String paramString2); The next step is to analysis so slightly. "strings libsecurity. so |grep-i getkey Java_com_qihoo_freewifi_utils_Securityutils_getkey And then the IDA F5 parameter type to be repaired is obtained as follows ! [getkeyn. png](/Article/UploadPic/2015-12/2 0 1 5 1 2 1 7 1 5 2 8 0 2 3 0. png) A hash process,this function is in so no that contains a direct reference to The dominant key generating factor 2 is the getKey(String paramString1, String paramString2) the second parameter. (Factor 1 is some fixed method of the string) SecurityUtils#b(Context arg1, String arg2, String arg3)arg3 introduction Back at the vA#a code public static String a(String arg2) { return SecurityUtils. b(Application. a(), arg2, vB. a(Application. a())); } vB#a get a similar UUID stuff incoming SecurityUtils#getKey get the key. (Here in can be a negative in front of the inferred class UUID string than and server related. Otherwise, the service client can not get the key to decrypt,the client will put the generated key the factor 2 is transmitted to the service end,in the http request is the m2 parameter. This service end you have to generate key of two factors to generate the key for decryption.) ! [param2. png](/Article/UploadPic/2015-12/2 0 1 5 1 2 1 7 1 5 2 8 0 6 3 3. png) The associated device id generation function vB#a analysis ,the main logic is as follows:the imei,deviceid,a splice after the md5 v0 = vB. b(arg6); String v1 = Settings$System. getString(arg6. getContentResolver(), "android_id"); String v2 = vB. a(); vB. a = vP. a("" + v0 + v1 + v2); Wherein v0 is determined by vB#b(Context arg2)generates a ,a case is returned to vB. b = arg2. getSystemService("phone"). getDeviceId() ,if empty then return"360_DEFAULT_IMEI" public static String b(Context arg2) { try { vB. b = wa. a(arg2, "APP_STORE_IMEI0", ""); if(! TextUtils. isEmpty(vB. b)) { String v0_1 = vB. b; return v0_1; } vB. b = arg2. getSystemService("phone"). getDeviceId(); if(TextUtils. isEmpty(vB. b)) { return "360_DEFAULT_IMEI"; } wa. b(arg2, "APP_STORE_IMEI0", vB. b); return vB. b; } catch(Exception v0) { } return "360_DEFAULT_IMEI"; } v1 is by the Settings$System. getString(arg6. getContentResolver(), "android_id") generate v2 is by vB#a() is generated,after the connection of the incoming vP#a(String arg1) calculates the md5 value. I.e., to obtain the generated key factor 2. public static String a() { String v0_3; String v1 = ""; try { Class v0_1 = Class. forName("android. os. SystemProperties"); Object v0_2 = v0_1. getMethod("get", String.class). invoke(v0_1, "ro. serialno"); } catch(Exception v0) { v0_3 = v1; } return v0_3; } The response packet to the encryption method and the request packet of the encryption method is consistent. Directly decrypt the response packet ! [passwd. png](/Article/UploadPic/2015-12/2 0 1 5 1 2 1 7 1 5 2 8 1 2 6 2. png) Wherein the pwd parameter is the wifi password,if not the query to null. Freshen up the entire process: 1. By splicing imie/android_id/deviceid, and then the md5 was m2 2. The m2 and the method incoming native function getkey to get the symmetric key key 3. By the key to request the corresponding packet within the data for DESede encryption and decryption Since the data encryption and decryption work has already been completed. Into the second part:the signature \--- Second round:the signature to break Which sign parameters by v0_1. add(new BasicNameValuePair("sign", tM. b(v0_1, v1))); Function to generate,v0_1 for the url parameter list of the collection,and the v1 is by tM. b()method to generate a 3 2-bit string tm#b generates a string of process and tM. c(); and vA. b(v1, "User. getConfig");associated private static String b() { String v0 = ""; String v1 = tM. c(); if(! TextUtils. isEmpty(((CharSequence)v1))) { try { v0 = vA. b(v1, "User. getConfig"); // DESede decrypt function } catch(Exception v1_1) { v1_1. printStackTrace(); } } return v0; } And in the tM. c()method in Main is called wa. a(Application. a(). getBaseContext(), "qlink_secret_key", "") private static String c() { String v0; if(! TextUtils. isEmpty(tM. a)) { v0 = tM. a; } else { tM. a = wa. a(Application. a(). getBaseContext(), "qlink_secret_key", ""); v0 = tM. a; } return v0; } wa#a(Context arg1, String arg2, String arg3)method call sV#b(Context arg2, String arg3, String arg4) public static String a(Context arg1, String arg2, String arg3) { return sV. b(arg1, arg2, arg3); } hook sV#b(Context arg2, String arg3, String arg4) input and output are as follows 09-15 1 1:0 2:27.749 1293-1293/? I/QihooWifi﹕ in sV#b(C|s|s) = last_update_date| para2 = 09-15 1 1:0 2:27.749 1293-1293/? I/QihooWifi: the out sV#b(C|s|s) = 2 0 1 5 0 9 1 5 09-15 1 1:5 6:55.622 2114-3083/? I/QihooWifi﹕ in sV#b(C|s|s) = qlink_secret_key| para2 = 09-15 1 1:5 6:55.632 2114-3083/? I/QihooWifi: the out sV#b(C|s|s) = Rd36RTbNXij5tjaqHZiEQY7ulZdvnrjbrwftciubivz6wpxjdamfyw== //DESede encryption after the 3 2-bit string 09-15 1 1:5 7:00.032 1244-1244/? I/QihooWifi﹕ in sV#b(C|s|s) = APP_STORE_IMEI| para2 = 09-15 1 1:5 7:00.032 1244-1244/? I/QihooWifi: the out sV#b(C|s|s) = 78856d3517649f2de7ceb7dc3e4a0e9 //m2 Wherein qlink_secret_key string of the incoming sV#b(Context arg7, String arg8) private static Cursor b(Context arg7, String arg8) { Cursor v0_2; Cursor v6 = null; if(arg7 != null && ! TextUtils. isEmpty(((CharSequence)arg8))) { ContentResolver v0 = arg7. getContentResolver(); try { v0_2 = v0. query(SharedPrefProvider. a, null, "key=\'" + arg8 + "\'", null, null); } catch(Throwable v0_1) { v0_2 = v6; } if(v0_2 == null) { try { String v0_3 = "select value from sharedpref where key=?"; if(sV. b == null || ! sV. b. isOpen()) { sV. b = new SPDBHelper(arg7). getReadableDatabase(); } v0_2 = sV. b. rawQuery(v0_3, new String[]{arg8}); } catch(Throwable v0_1) { v0_2 = v6; } } else { } } else { v0_2 = v6; } return v0_2; } From the code it can be seen qlink_secret_key the value from the table sharepref removed ! [sharedpref. png](/Article/UploadPic/2015-12/2 0 1 5 1 2 1 7 1 5 2 8 4 2 8 1. png) That this value is generated and stored to sqlite in? Will see tM#c()method,when member variable tM. a is empty by tM#a(String paramString) assignment. public static void a(String paramString) { a = paramString; wa. b(Application. a(). getBaseContext(), "qlink_secret_key", paramString); } Track to wa#b(Context paramContext, String paramString1, String paramString2) public static void b(Context paramContext, String paramString1, String paramString2) { sV. a(paramContext, paramString1, paramString2); } Continue to track sV#a(Context paramContext, String paramString1, String paramString2) public static void a(Context paramContext, String paramString1, String paramString2) { if (paramContext == null) {} for (;;) { return; paramContext = paramContext. getContentResolver(); ContentValues localContentValues = new ContentValues(); localContentValues. put("key", paramString1); localContentValues. put("value", paramString2); try { if (paramContext. update(SharedPrefProvider. a, localContentValues, "key=?", new String[] { paramString1 }) == 0) { paramContext. insert(SharedPrefProvider. a, localContentValues); return; } } catch (Throwable paramContext) {} } } Can be determined by tM#c()method to write qlink_secret_key this key value,and now you want to use xref to view the modified method calls. (Guess:this value is returned from the server,it so happens that the return package is to use the DESede encryption,here is also encrypted. Guess two:the previously mentioned update_key may be updated here is the key) There are two references,one is the rn#a(rp arg3) ,arg3. c is by taking the json data under the url key value. (May be evidence of guessing one) </code> public void a(rp arg3) { if(arg3 != null && arg3. c != null) { try { String v0_1 = arg3. c. optString("url"); if(TextUtils. isEmpty(((CharSequence)v0_1))) { goto label_9; } tM. a(v0_1); } catch(Exception v0) { } } label_9: rh. a(this. a, arg3); } </code> The second application in a tk#a(tz arg7) , wherein tk. a = "http://api.free.wifi.360.cn/intf.php"; method set forth for the User. getConfig(continue to support speculation A this return value is by here the url request) public static void a(tz arg7) { vO. a("ApiHelper", "getUserConfig"); tL v0 = tK. a(tk. a, "User. getConfig", null, null, null, null); //request the api vO. a("ApiHelper", "getUserConfig end:" + v0. h); JSONObject v1 = tk. a(v0); //from the return value of the removed data field both for qlink_secret_key if(v1 == null) { tk. a(v0, arg7, new Object[0]); } else { String v1_1 = v1. optString("url"); if(! TextUtils. isEmpty(((CharSequence)v1_1))) { tM. a(v1_1); } tk. a(v0, arg7, new Object[0]); } } Next, clear the app data after capture to capture this request,East static binding efficiency. ! [dataurl. png](/Article/UploadPic/2015-12/2 0 1 5 1 2 1 7 1 5 2 8 5 1 6 8. png) Reset the application after the first request is to get this parameter,then the problem came. Know that is used to calculate the sign,then the first request packet of the sign is how come? (Speculation:and the other two native function related) Back at the tM#a(String arg9, String arg10, List arg11, String arg12, boolean arg13) method,if the method for the User. getConfig then the v1 will be empty to calculate the sign.... v1 = "the User. getConfig". equals(arg10) ? "" : tM. b(); v0_1. add(new BasicNameValuePair("sign", tM. b(v0_1, v1))); Back at the tM#a(Context paramContext, String paramString1, String paramString2) method,if the para2 is null then the call is SecurityUtils. b(paramContext, paramString1)function </code> private static String a(Context paramContext, String paramString1, String paramString2) { if (TextUtils. isEmpty(paramString1)) { return ""; } for (;;) { synchronized (rz. a) { if (TextUtils. isEmpty(paramString2)) { paramContext = SecurityUtils. b(paramContext, paramString1); paramContext = paramContext. toLowerCase(); return paramContext; } } paramContext = SecurityUtils. a(paramContext, paramString1, paramString2); } } </code> And the tM#b(Context paramContext, String paramString) public static String b(Context paramContext, String paramString) { if ((paramContext == null) || (paramString == null) || (paramString. equals(""))) { if (paramContext == null) { return "contextisnull"; } if ((paramString == null) ||(paramString. length() == 0)) { return "signstrisnull"; } } if (! a) { a(paramContext); if (! a) { return paramString + "&loadsoerror=true"; } } try { paramContext = initnew(paramContext. getApplicationContext(), paramString, "", false); return paramContext; } catch (Throwable paramContext) {} return ""; } Want to view so when. ! [initnewn. png](/Article/UploadPic/2015-12/2 0 1 5 1 2 1 7 1 5 2 8 5 1 6 9. png) Here obviously made a packet determines,if like getkey, like a direct call certainly will return none,so analytically under isVaild function to try to bypass this restriction. In this case there are two options 1. path so in the judgment of the BEQ into BNE 2. Finally, a Boolean variable pass true.. Here select the second simple method. The calculated results are as follows 09-15 1 8:2 9:20.060 11255-11255/org. tick. qihoowifi I/Hi360: the MySign = 5c1c5d32e47638e464bd2ee7f8beea1b Comparison before hook results,to prove the guess is correct 09-15 1 5:0 9:14.610 6110-6110/? I/QihooWifi: the in tM#a(c|s|s) = channel=1 0 0 0 0 1&devtype=android&inviter_qid=0&m2= 78856d3517649f2de7ceb7dc3e4a0e94&manufacturer=LGE&method= User. getConfig&model=Nexus%2 0 5&nance=1 4 4 2 3 0 0 9 5 4 6 1 9&nettype=WIFI&os=4.4.4&qid=0&v=2 3 7 | para3 = 09-15 1 5:0 9:14.610 6110-6110/? I/QihooWifi: the out tM#a(c|s|s) = 5c1c5d32e47638e464bd2ee7f8beea1b nance is a time stamp generated in the following way: v3[1 8] = "The nance"; v3[1 9] = String. valueOf(System. currentTimeMillis()); Thus the sign of the crack is substantially complete. A simple combing of the entire process 1. The first url parameter is sequentially spliced into a string 2. If the method for the User. getConfig will splice the string for incoming native function initnew to calculate the sign value,and give the sign of the encryption salt Value data:url 3. If method is not equal to the User. getConfig will be stitching the string incoming native function sign, and to 2 obtain the encryption salt for DESede decrypted with incoming. (Note case sensitive) **[1] [[2]](<70119_2.htm>) [next](<70119_2.htm>)**