Milarian kerentanan dina UC Browser

Milarian kerentanan dina UC Browser

perkenalan

Dina ahir Maret urang dilaporkeun, yén maranéhna manggihan pangabisa disumputkeun pikeun muka tur ngajalankeun kode unverified dina UC Browser. Dinten ieu kami bakal ningali sacara rinci kumaha undeuran ieu kajantenan sareng kumaha hacker tiasa ngagunakeunana pikeun tujuanana sorangan.

Sababaraha waktos kapengker, UC Browser diémbarkeun sareng disebarkeun sacara agrésif pisan: dipasang dina alat pangguna nganggo malware, disebarkeun tina sababaraha situs dina kedok file pidéo (nyaéta, pangguna panginten aranjeunna ngunduh, contona, pidéo porno, tapi. gantina narima APK kalawan browser ieu), dipaké spanduk pikasieuneun kalayan pesen yén browser éta luntur, rentan, jeung hal kawas éta. Dina grup UC Browser resmi dina VK aya poko, nu pamaké bisa ngawadul ngeunaan iklan adil, aya loba conto di dinya. Dina 2016 aya malah iklan video dina basa Rusia (enya, iklan pikeun panyungsi ad-blocking).

Dina waktos nyerat, UC Browser gaduh langkung ti 500 pamasangan dina Google Play. Ieu impressive - ngan Google Chrome boga leuwih. Diantara ulasan anjeun tiasa ningali seueur keluhan ngeunaan pariwara sareng alihan ka sababaraha aplikasi dina Google Play. Ieu mangrupikeun alesan pikeun panalungtikan urang: urang mutuskeun pikeun ningali naha UC Browser ngalakukeun anu goréng. Jeung tétéla manéhna teu!

Dina kode aplikasi, kamampuhan pikeun ngundeur tur ngajalankeun kode laksana kapanggih, anu bertentangan sareng aturan pikeun nyebarkeun aplikasi dina Google Play. Salian ngaunduh kodeu anu tiasa dieksekusi, UC Browser ngalakukeunana dina cara anu teu aman, anu tiasa dianggo pikeun ngaluncurkeun serangan MitM. Hayu urang tingali naha urang tiasa ngalaksanakeun serangan sapertos kitu.

Sadayana anu ditulis di handap ieu relevan pikeun vérsi UC Browser anu sayogi dina Google Play nalika diajar:

package: com.UCMobile.intl
versionName: 12.10.8.1172
versionCode: 10598
sha1 APK-файла: f5edb2243413c777172f6362876041eb0c3a928c

Vektor serangan

Dina manifest UC Browser anjeun tiasa mendakan jasa kalayan nami anu jelas com.uc.deployment.UpgradeDeployService.

    <service android_exported="false" android_name="com.uc.deployment.UpgradeDeployService" android_process=":deploy" />

Nalika layanan ieu dimimitian, browser ngajadikeun pamundut POST ka puds.ucweb.com/upgrade/index.xhtml, nu bisa ditempo dina lalulintas sababaraha waktu sanggeus mimiti. Salaku jawaban, anjeunna tiasa nampi paréntah pikeun ngaunduh sababaraha pembaruan atanapi modul énggal. Salila analisa, server henteu masihan paréntah sapertos kitu, tapi urang perhatikeun yén nalika urang nyobian muka PDF dina browser, éta nyuhunkeun pamundut kadua ka alamat anu dijelaskeun di luhur, saatos éta ngaunduh perpustakaan asli. Pikeun ngalaksanakeun serangan éta, kami mutuskeun pikeun ngagunakeun fitur UC Browser ieu: kamampuan pikeun muka PDF nganggo perpustakaan asli, anu henteu aya dina APK sareng anu diunduh tina Internét upami diperyogikeun. Perlu dicatet yén, sacara téoritis, UC Browser tiasa dipaksa pikeun ngaunduh hiji hal tanpa interaksi pangguna - upami anjeun nyayogikeun réspon anu saé pikeun pamundut anu dieksekusi saatos browser diluncurkeun. Tapi pikeun ngalakukeun ieu, urang kedah diajar protokol interaksi sareng server sacara langkung rinci, ku kituna urang mutuskeun yén éta bakal langkung gampang ngédit réspon anu disadap sareng ngagentos perpustakaan pikeun damel sareng PDF.

Janten, nalika pangguna hoyong muka PDF langsung dina panyungsi, paménta di handap ieu tiasa ditingali dina lalu lintas:

Milarian kerentanan dina UC Browser

Mimiti aya pamundut POST ka puds.ucweb.com/upgrade/index.xhtml, saterusna
Arsip sareng perpustakaan pikeun ningali format PDF sareng kantor diunduh. Éta logis mun nganggap yén pamundut kahiji ngirimkeun informasi ngeunaan sistem (sahenteuna arsitéktur nyadiakeun perpustakaan diperlukeun), sarta dina respon kana eta browser narima sababaraha émbaran ngeunaan perpustakaan nu kudu diundeur: alamat na, jigana. , kitu deui. Masalahna nyaéta pamundut ieu énkripsi.

Menta sempalan

Jawab sempalan

Milarian kerentanan dina UC Browser

Milarian kerentanan dina UC Browser

Perpustakaan sorangan dibungkus dina ZIP sareng henteu énkripsi.

Milarian kerentanan dina UC Browser

Milarian kodeu dekripsi lalu lintas

Hayu urang coba decipher respon server. Hayu urang tingali kode kelas com.uc.deployment.UpgradeDeployService: ti métode onStartCommand indit ka com.uc.deployment.bx, sareng ti dinya ka com.uc.browser.core.dcfe:

    public final void e(l arg9) {
int v4_5;
String v3_1;
byte[] v3;
byte[] v1 = null;
if(arg9 == null) {
v3 = v1;
}
else {
v3_1 = arg9.iGX.ipR;
StringBuilder v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]product:");
v4.append(arg9.iGX.ipR);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]version:");
v4.append(arg9.iGX.iEn);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]upgrade_type:");
v4.append(arg9.iGX.mMode);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]force_flag:");
v4.append(arg9.iGX.iEo);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]silent_mode:");
v4.append(arg9.iGX.iDQ);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]silent_type:");
v4.append(arg9.iGX.iEr);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]silent_state:");
v4.append(arg9.iGX.iEp);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]silent_file:");
v4.append(arg9.iGX.iEq);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]apk_md5:");
v4.append(arg9.iGX.iEl);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]download_type:");
v4.append(arg9.mDownloadType);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]download_group:");
v4.append(arg9.mDownloadGroup);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]download_path:");
v4.append(arg9.iGH);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]apollo_child_version:");
v4.append(arg9.iGX.iEx);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]apollo_series:");
v4.append(arg9.iGX.iEw);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]apollo_cpu_arch:");
v4.append(arg9.iGX.iEt);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]apollo_cpu_vfp3:");
v4.append(arg9.iGX.iEv);
v4 = new StringBuilder("[");
v4.append(v3_1);
v4.append("]apollo_cpu_vfp:");
v4.append(arg9.iGX.iEu);
ArrayList v3_2 = arg9.iGX.iEz;
if(v3_2 != null && v3_2.size() != 0) {
Iterator v3_3 = v3_2.iterator();
while(v3_3.hasNext()) {
Object v4_1 = v3_3.next();
StringBuilder v5 = new StringBuilder("[");
v5.append(((au)v4_1).getName());
v5.append("]component_name:");
v5.append(((au)v4_1).getName());
v5 = new StringBuilder("[");
v5.append(((au)v4_1).getName());
v5.append("]component_ver_name:");
v5.append(((au)v4_1).aDA());
v5 = new StringBuilder("[");
v5.append(((au)v4_1).getName());
v5.append("]component_ver_code:");
v5.append(((au)v4_1).gBl);
v5 = new StringBuilder("[");
v5.append(((au)v4_1).getName());
v5.append("]component_req_type:");
v5.append(((au)v4_1).gBq);
}
}
j v3_4 = new j();
m.b(v3_4);
h v4_2 = new h();
m.b(v4_2);
ay v5_1 = new ay();
v3_4.hS("");
v3_4.setImsi("");
v3_4.hV("");
v5_1.bPQ = v3_4;
v5_1.bPP = v4_2;
v5_1.yr(arg9.iGX.ipR);
v5_1.gBF = arg9.iGX.mMode;
v5_1.gBI = arg9.iGX.iEz;
v3_2 = v5_1.gAr;
c.aBh();
v3_2.add(g.fs("os_ver", c.getRomInfo()));
v3_2.add(g.fs("processor_arch", com.uc.b.a.a.c.getCpuArch()));
v3_2.add(g.fs("cpu_arch", com.uc.b.a.a.c.Pb()));
String v4_3 = com.uc.b.a.a.c.Pd();
v3_2.add(g.fs("cpu_vfp", v4_3));
v3_2.add(g.fs("net_type", String.valueOf(com.uc.base.system.a.Jo())));
v3_2.add(g.fs("fromhost", arg9.iGX.iEm));
v3_2.add(g.fs("plugin_ver", arg9.iGX.iEn));
v3_2.add(g.fs("target_lang", arg9.iGX.iEs));
v3_2.add(g.fs("vitamio_cpu_arch", arg9.iGX.iEt));
v3_2.add(g.fs("vitamio_vfp", arg9.iGX.iEu));
v3_2.add(g.fs("vitamio_vfp3", arg9.iGX.iEv));
v3_2.add(g.fs("plugin_child_ver", arg9.iGX.iEx));
v3_2.add(g.fs("ver_series", arg9.iGX.iEw));
v3_2.add(g.fs("child_ver", r.aVw()));
v3_2.add(g.fs("cur_ver_md5", arg9.iGX.iEl));
v3_2.add(g.fs("cur_ver_signature", SystemHelper.getUCMSignature()));
v3_2.add(g.fs("upgrade_log", i.bjt()));
v3_2.add(g.fs("silent_install", String.valueOf(arg9.iGX.iDQ)));
v3_2.add(g.fs("silent_state", String.valueOf(arg9.iGX.iEp)));
v3_2.add(g.fs("silent_file", arg9.iGX.iEq));
v3_2.add(g.fs("silent_type", String.valueOf(arg9.iGX.iEr)));
v3_2.add(g.fs("cpu_archit", com.uc.b.a.a.c.Pc()));
v3_2.add(g.fs("cpu_set", SystemHelper.getCpuInstruction()));
boolean v4_4 = v4_3 == null || !v4_3.contains("neon") ? false : true;
v3_2.add(g.fs("neon", String.valueOf(v4_4)));
v3_2.add(g.fs("cpu_cores", String.valueOf(com.uc.b.a.a.c.Jl())));
v3_2.add(g.fs("ram_1", String.valueOf(com.uc.b.a.a.h.Po())));
v3_2.add(g.fs("totalram", String.valueOf(com.uc.b.a.a.h.OL())));
c.aBh();
v3_2.add(g.fs("rom_1", c.getRomInfo()));
v4_5 = e.getScreenWidth();
int v6 = e.getScreenHeight();
StringBuilder v7 = new StringBuilder();
v7.append(v4_5);
v7.append("*");
v7.append(v6);
v3_2.add(g.fs("ss", v7.toString()));
v3_2.add(g.fs("api_level", String.valueOf(Build$VERSION.SDK_INT)));
v3_2.add(g.fs("uc_apk_list", SystemHelper.getUCMobileApks()));
Iterator v4_6 = arg9.iGX.iEA.entrySet().iterator();
while(v4_6.hasNext()) {
Object v6_1 = v4_6.next();
v3_2.add(g.fs(((Map$Entry)v6_1).getKey(), ((Map$Entry)v6_1).getValue()));
}
v3 = v5_1.toByteArray();
}
if(v3 == null) {
this.iGY.iGI.a(arg9, "up_encode", "yes", "fail");
return;
}
v4_5 = this.iGY.iGw ? 0x1F : 0;
if(v3 == null) {
}
else {
v3 = g.i(v4_5, v3);
if(v3 == null) {
}
else {
v1 = new byte[v3.length + 16];
byte[] v6_2 = new byte[16];
Arrays.fill(v6_2, 0);
v6_2[0] = 0x5F;
v6_2[1] = 0;
v6_2[2] = ((byte)v4_5);
v6_2[3] = -50;
System.arraycopy(v6_2, 0, v1, 0, 16);
System.arraycopy(v3, 0, v1, 16, v3.length);
}
}
if(v1 == null) {
this.iGY.iGI.a(arg9, "up_encrypt", "yes", "fail");
return;
}
if(TextUtils.isEmpty(this.iGY.mUpgradeUrl)) {
this.iGY.iGI.a(arg9, "up_url", "yes", "fail");
return;
}
StringBuilder v0 = new StringBuilder("[");
v0.append(arg9.iGX.ipR);
v0.append("]url:");
v0.append(this.iGY.mUpgradeUrl);
com.uc.browser.core.d.c.i v0_1 = this.iGY.iGI;
v3_1 = this.iGY.mUpgradeUrl;
com.uc.base.net.e v0_2 = new com.uc.base.net.e(new com.uc.browser.core.d.c.i$a(v0_1, arg9));
v3_1 = v3_1.contains("?") ? v3_1 + "&dataver=pb" : v3_1 + "?dataver=pb";
n v3_5 = v0_2.uc(v3_1);
m.b(v3_5, false);
v3_5.setMethod("POST");
v3_5.setBodyProvider(v1);
v0_2.b(v3_5);
this.iGY.iGI.a(arg9, "up_null", "yes", "success");
this.iGY.iGI.b(arg9);
}

Urang tingali didieu formasi hiji pamundut POST. Urang nengetan kreasi hiji Asép Sunandar Sunarya 16 bait jeung keusikan na: 0x5F, 0, 0x1F, -50 (= 0xCE). Coincides jeung naon urang nempo dina pamundut di luhur.

Dina kelas anu sami anjeun tiasa ningali kelas nested anu ngagaduhan metode anu pikaresepeun:

        public final void a(l arg10, byte[] arg11) {
f v0 = this.iGQ;
StringBuilder v1 = new StringBuilder("[");
v1.append(arg10.iGX.ipR);
v1.append("]:UpgradeSuccess");
byte[] v1_1 = null;
if(arg11 == null) {
}
else if(arg11.length < 16) {
}
else {
if(arg11[0] != 0x60 && arg11[3] != 0xFFFFFFD0) {
goto label_57;
}
int v3 = 1;
int v5 = arg11[1] == 1 ? 1 : 0;
if(arg11[2] != 1 && arg11[2] != 11) {
if(arg11[2] == 0x1F) {
}
else {
v3 = 0;
}
}
byte[] v7 = new byte[arg11.length - 16];
System.arraycopy(arg11, 16, v7, 0, v7.length);
if(v3 != 0) {
v7 = g.j(arg11[2], v7);
}
if(v7 == null) {
goto label_57;
}
if(v5 != 0) {
v1_1 = g.P(v7);
goto label_57;
}
v1_1 = v7;
}
label_57:
if(v1_1 == null) {
v0.iGY.iGI.a(arg10, "up_decrypt", "yes", "fail");
return;
}
q v11 = g.b(arg10, v1_1);
if(v11 == null) {
v0.iGY.iGI.a(arg10, "up_decode", "yes", "fail");
return;
}
if(v0.iGY.iGt) {
v0.d(arg10);
}
if(v0.iGY.iGo != null) {
v0.iGY.iGo.a(0, ((o)v11));
}
if(v0.iGY.iGs) {
v0.iGY.a(((o)v11));
v0.iGY.iGI.a(v11, "up_silent", "yes", "success");
v0.iGY.iGI.a(v11);
return;
}
v0.iGY.iGI.a(v11, "up_silent", "no", "success");
}
}

Metoda nyokot Asép Sunandar Sunarya Asép Sunandar Sunarya ti bait salaku input sarta pariksa yen bait enol nyaeta 0x60 atawa bait katilu nyaeta 0xD0, sarta bait kadua 1, 11 atawa 0x1F. Kami ningali réspon ti server: bait enol nyaéta 0x60, anu kadua nyaéta 0x1F, anu katilu nyaéta 0x60. Hurung kawas naon urang kudu. Ditilik ku garis ("up_decrypt", contona), hiji metodeu kudu disebut di dieu anu bakal ngadekrip respon server urang.
Hayu urang ngaléngkah ka métode gj. Catet yén argumen kahiji nyaéta bait dina offset 2 (nyaéta 0x1F dina kasus urang), sareng anu kadua nyaéta réspon server tanpa
kahiji 16 bait.

     public static byte[] j(int arg1, byte[] arg2) {
if(arg1 == 1) {
arg2 = c.c(arg2, c.adu);
}
else if(arg1 == 11) {
arg2 = m.aF(arg2);
}
else if(arg1 != 0x1F) {
}
else {
arg2 = EncryptHelper.decrypt(arg2);
}
return arg2;
}

Jelas, di dieu kami milih algoritma dekripsi, sareng bait anu sami anu aya dina kami
bisi sarua jeung 0x1F, ngalambangkeun salah sahiji tilu pilihan mungkin.

Urang neruskeun nganalisis kode. Saatos sababaraha luncat, urang mendakan diri dina metode anu gaduh nami anu jelas decryptBytesByKey.

Di dieu dua bait deui dipisahkeun tina respon urang, sarta string anu dicandak ti aranjeunna. Ieu jelas yén ku cara kieu konci pikeun decrypting pesen dipilih.

    private static byte[] decryptBytesByKey(byte[] bytes) {
byte[] v0 = null;
if(bytes != null) {
try {
if(bytes.length < EncryptHelper.PREFIX_BYTES_SIZE) {
}
else if(bytes.length == EncryptHelper.PREFIX_BYTES_SIZE) {
return v0;
}
else {
byte[] prefix = new byte[EncryptHelper.PREFIX_BYTES_SIZE];  // 2 байта
System.arraycopy(bytes, 0, prefix, 0, prefix.length);
String keyId = c.ayR().d(ByteBuffer.wrap(prefix).getShort()); // Выбор ключа
if(keyId == null) {
return v0;
}
else {
a v2 = EncryptHelper.ayL();
if(v2 == null) {
return v0;
}
else {
byte[] enrypted = new byte[bytes.length - EncryptHelper.PREFIX_BYTES_SIZE];
System.arraycopy(bytes, EncryptHelper.PREFIX_BYTES_SIZE, enrypted, 0, enrypted.length);
return v2.l(keyId, enrypted);
}
}
}
}
catch(SecException v7_1) {
EncryptHelper.handleDecryptException(((Throwable)v7_1), v7_1.getErrorCode());
return v0;
}
catch(Throwable v7) {
EncryptHelper.handleDecryptException(v7, 2);
return v0;
}
}
return v0;
}

Ningali payun, kami dicatet yén dina tahap ieu kami henteu acan kéngingkeun konci, tapi ngan ukur "identifier" na. Meunangkeun konci téh saeutik leuwih pajeulit.

Dina metodeu salajengna, dua parameter deui ditambahkeun kana nu geus aya, nyieun opat di antarana: angka magic 16, identifier konci, data énkripsi, sarta string teu kaharti (bisi kami kosong).

    public final byte[] l(String keyId, byte[] encrypted) throws SecException {
return this.ayJ().staticBinarySafeDecryptNoB64(16, keyId, encrypted, "");
}

Sanggeus runtuyan transisi urang anjog ka metoda staticBinarySafeDecryptNoB64 panganteur com.alibaba.wireless.security.open.staticdataencrypt.IStaticDataEncryptComponent. Henteu aya kelas dina kode aplikasi utama anu ngalaksanakeun antarmuka ieu. Aya kelas sapertos dina file lib/armeabi-v7a/libsgmain.so, nu sabenerna mah a .kitu, tapi .jar. Metodeu anu dipikaresep ku urang dilaksanakeun sapertos kieu:

package com.alibaba.wireless.security.a.i;
// ...
public class a implements IStaticDataEncryptComponent {
private ISecurityGuardPlugin a;
// ...
private byte[] a(int mode, int magicInt, int xzInt, String keyId, byte[] encrypted, String magicString) {
return this.a.getRouter().doCommand(10601, new Object[]{Integer.valueOf(mode), Integer.valueOf(magicInt), Integer.valueOf(xzInt), keyId, encrypted, magicString});
}
// ...
private byte[] b(int magicInt, String keyId, byte[] encrypted, String magicString) {
return this.a(2, magicInt, 0, keyId, encrypted, magicString);
}
// ...
public byte[] staticBinarySafeDecryptNoB64(int magicInt, String keyId, byte[] encrypted, String magicString) throws SecException {
if(keyId != null && keyId.length() > 0 && magicInt >= 0 && magicInt < 19 && encrypted != null && encrypted.length > 0) {
return this.b(magicInt, keyId, encrypted, magicString);
}
throw new SecException("", 301);
}
//...
}

Di dieu daptar parameter urang geus supplemented dua integer: 2 jeung 0. Ditilik ku
sagalana, 2 hartina dekripsi, sakumaha dina metoda doFinal kelas sistem javax.crypto.Cipher. Sareng sadaya ieu ditransfer ka router anu tangtu kalayan nomer 10601 - ieu sigana nomer paréntah.

Saatos ranté salajengna transisi urang manggihan hiji kelas nu implements panganteur dina Komponén IRouter jeung métode doCommand:

package com.alibaba.wireless.security.mainplugin;
import com.alibaba.wireless.security.framework.IRouterComponent;
import com.taobao.wireless.security.adapter.JNICLibrary;
public class a implements IRouterComponent {
public a() {
super();
}
public Object doCommand(int arg2, Object[] arg3) {
return JNICLibrary.doCommandNative(arg2, arg3);
}
}

Sareng ogé kelas Perpustakaan JNICL, dimana metode asli dinyatakeun doCommandNative:

package com.taobao.wireless.security.adapter;
public class JNICLibrary {
public static native Object doCommandNative(int arg0, Object[] arg1);
}

Ieu ngandung harti yén urang kedah milarian metode dina kode asli doCommandNative. Sareng ieu dimana kasenangan dimimitian.

Obfuscation kode mesin

Dina file libsgmain.jadi (anu sabenerna mangrupa .jar jeung nu urang kapanggih palaksanaan sababaraha interfaces patali enkripsi ngan luhur) aya hiji perpustakaan asli: libsgmainso-6.4.36.jadi. Urang mukakeunana dina IDA sareng kéngingkeun sakumpulan kotak dialog kalayan kasalahan. Masalahna nyaéta tabel lulugu bagian henteu sah. Hal ieu dilakukeun pikeun ngahesekeun analisis.

Milarian kerentanan dina UC Browser

Tapi henteu diperyogikeun: pikeun ngamuat file ELF kalayan leres sareng nganalisis éta, méja header program cekap. Kituna, urang ngan ngahapus tabel bagian, zeroing kaluar widang pakait dina lulugu.

Milarian kerentanan dina UC Browser

Buka deui file dina IDA.

Aya dua cara pikeun ngawartosan mesin virtual Java dimana persisna di perpustakaan asli palaksanaan metode anu dinyatakeun dina kode Java salaku asli ayana. Anu kahiji nyaéta méré ngaran spésiés Java_package_name_ClassName_MethodName.

Anu kadua nyaéta ngadaptar nalika ngamuat perpustakaan (dina fungsi JNI_OnLoad)
ngagunakeun panggero fungsi RegisterNatives.

Dina kasus urang, upami urang nganggo metodeu munggaran, nami kedah sapertos kieu: Java_com_taobao_wireless_security_adapter_JNICLlibrary_doCommandNative.

Henteu aya fungsi sapertos diantara fungsi anu diékspor, anu hartosna anjeun kedah milarian telepon RegisterNatives.
Hayu urang balik ka fungsi JNI_OnLoad sareng urang ningali gambar ieu:

Milarian kerentanan dina UC Browser

Aya naon di dieu? Dina glance kahiji, mimiti jeung tungtung fungsi has pikeun arsitektur ARM. Parentah munggaran dina tumpukan nyimpen eusi registers nu fungsi bakal dipaké dina operasi na (dina hal ieu, R0, R1 na R2), kitu ogé eusi LR register, nu ngandung alamat balik ti fungsi. . Parentah panungtungan restores nu registers disimpen, sarta alamat balik langsung disimpen dina PC register - sahingga balik ti fungsi. Tapi lamun kasampak raket, anjeun bakal aya bewara yén instruksi penultimate robah alamat balik disimpen dina tumpukan éta. Hayu urang ngitung kumaha bakal jadi sanggeus
palaksanaan kode. Alamat anu tangtu 1xB0 dimuat kana R130, 5 dikurangan ti dinya, teras ditransferkeun ka R0 sareng 0x10 ditambahkeun kana éta. Tétéla 0xB13B. Ku kituna, IDA nyangka yén instruksi panungtungan nyaéta fungsi normal balik, tapi dina kanyataanana bade ka alamat diitung 0xB13B.

Perlu diinget yén prosesor ARM gaduh dua mode sareng dua sét paréntah: ARM sareng Thumb. Saeutikna alamat anu paling penting nyarioskeun ka prosesor mana set instruksi anu dianggo. Hartina, alamatna sabenerna 0xB13A, sarta hiji dina bit sahenteuna signifikan nunjukkeun mode jempol.

A sarupa "adaptor" geus ditambahkeun kana awal unggal fungsi dina perpustakaan ieu sareng
kodeu runtah. Kami moal ngémutan aranjeunna sacara rinci - urang ngan émut
yén awal nyata ampir sakabéh fungsi anu saeutik leuwih jauh.

Kusabab kodeu henteu sacara eksplisit ngaluncat kana 0xB13A, IDA sorangan henteu mikawanoh yén kodeu aya di lokasi ieu. Pikeun alesan anu sarua, éta henteu mikawanoh lolobana kode dina perpustakaan salaku kode, nu ngajadikeun analisis rada hese. Kami nyarioskeun ka IDA yén ieu mangrupikeun kodeu, sareng ieu anu kajantenan:

Milarian kerentanan dina UC Browser

tabél jelas dimimitian dina 0xB144. Naon dina sub_494C?

Milarian kerentanan dina UC Browser

Nalika nelepon fungsi ieu dina register LR, urang meunang alamat tabel disebutkeun saméméhna (0xB144). Dina R0 - indéks dina tabel ieu. Hartina, nilai nu dicokot tina tabél, ditambahkeun kana LR sarta hasilna mangrupa
alamat nu bade ka. Coba itung: 0xB144 + [0xB144 + 8* 4] = 0xB144 + 0x120 = 0xB264. Kami angkat ka alamat anu ditampi sareng ningali sacara harfiah sababaraha petunjuk anu mangpaat sareng angkat deui ka 0xB140:

Milarian kerentanan dina UC Browser

Ayeuna bakal aya transisi di offset sareng indéks 0x20 tina tabél.

Ditilik ku ukuran tabel, bakal aya seueur transisi sapertos dina kode. Patarosan timbul naha kasebut nyaéta dimungkinkeun pikeun kumaha bae nungkulan ieu leuwih otomatis, tanpa sacara manual ngitung alamat. Sareng skrip sareng kamampuan pikeun nambal kode dina IDA ngabantosan kami:

def put_unconditional_branch(source, destination):
offset = (destination - source - 4) >> 1
if offset > 2097151 or offset < -2097152:
raise RuntimeError("Invalid offset")
if offset > 1023 or offset < -1024:
instruction1 = 0xf000 | ((offset >> 11) & 0x7ff)
instruction2 = 0xb800 | (offset & 0x7ff)
patch_word(source, instruction1)
patch_word(source + 2, instruction2)
else:
instruction = 0xe000 | (offset & 0x7ff)
patch_word(source, instruction)
ea = here()
if get_wide_word(ea) == 0xb503: #PUSH {R0,R1,LR}
ea1 = ea + 2
if get_wide_word(ea1) == 0xbf00: #NOP
ea1 += 2
if get_operand_type(ea1, 0) == 1 and get_operand_value(ea1, 0) == 0 and get_operand_type(ea1, 1) == 2:
index = get_wide_dword(get_operand_value(ea1, 1))
print "index =", hex(index)
ea1 += 2
if get_operand_type(ea1, 0) == 7:
table = get_operand_value(ea1, 0) + 4
elif get_operand_type(ea1, 1) == 2:
table = get_operand_value(ea1, 1) + 4
else:
print "Wrong operand type on", hex(ea1), "-", get_operand_type(ea1, 0), get_operand_type(ea1, 1)
table = None
if table is None:
print "Unable to find table"
else:
print "table =", hex(table)
offset = get_wide_dword(table + (index << 2))
put_unconditional_branch(ea, table + offset)
else:
print "Unknown code", get_operand_type(ea1, 0), get_operand_value(ea1, 0), get_operand_type(ea1, 1) == 2
else:
print "Unable to detect first instruction"

Teundeun kursor dina garis 0xB26A, ngajalankeun skrip tur tingal transisi ka 0xB4B0:

Milarian kerentanan dina UC Browser

IDA deui henteu mikawanoh wewengkon ieu salaku kode. Kami ngabantosan anjeunna sareng ningali desain anu sanés di dinya:

Milarian kerentanan dina UC Browser

Parentah sanggeus BLX sigana teu make loba akal, éta leuwih kawas sababaraha jenis kapindahan. Hayu urang tingali sub_4964:

Milarian kerentanan dina UC Browser

Jeung memang, di dieu a dword dicokot dina alamat bohong di LR, ditambahkeun kana alamat ieu, nu satutasna nilai dina alamat hasilna dicokot sarta ditunda tumpukan. Ogé, 4 ditambahkeun kana LR ku kituna sanggeus balik ti fungsi nu, offset sarua ieu skipped. Saatos éta paréntah POP {R1} nyandak nilai anu dihasilkeun tina tumpukan. Upami anjeun ningali naon anu aya di alamat 0xB4BA + 0xEA = 0xB5A4, anjeun bakal ningali anu sami sareng tabel alamat:

Milarian kerentanan dina UC Browser

Pikeun nambal desain ieu, anjeun kedah nampi dua parameter tina kode: offset sareng nomer register dimana anjeun badé nempatkeun hasilna. Pikeun unggal pendaptaran anu mungkin, anjeun kedah nyiapkeun sapotong kode sateuacanna.

patches = {}
patches[0] = (0x00, 0xbf, 0x01, 0x48, 0x00, 0x68, 0x02, 0xe0)
patches[1] = (0x00, 0xbf, 0x01, 0x49, 0x09, 0x68, 0x02, 0xe0)
patches[2] = (0x00, 0xbf, 0x01, 0x4a, 0x12, 0x68, 0x02, 0xe0)
patches[3] = (0x00, 0xbf, 0x01, 0x4b, 0x1b, 0x68, 0x02, 0xe0)
patches[4] = (0x00, 0xbf, 0x01, 0x4c, 0x24, 0x68, 0x02, 0xe0)
patches[5] = (0x00, 0xbf, 0x01, 0x4d, 0x2d, 0x68, 0x02, 0xe0)
patches[8] = (0x00, 0xbf, 0xdf, 0xf8, 0x06, 0x80, 0xd8, 0xf8, 0x00, 0x80, 0x01, 0xe0)
patches[9] = (0x00, 0xbf, 0xdf, 0xf8, 0x06, 0x90, 0xd9, 0xf8, 0x00, 0x90, 0x01, 0xe0)
patches[10] = (0x00, 0xbf, 0xdf, 0xf8, 0x06, 0xa0, 0xda, 0xf8, 0x00, 0xa0, 0x01, 0xe0)
patches[11] = (0x00, 0xbf, 0xdf, 0xf8, 0x06, 0xb0, 0xdb, 0xf8, 0x00, 0xb0, 0x01, 0xe0)
ea = here()
if (get_wide_word(ea) == 0xb082 #SUB SP, SP, #8
and get_wide_word(ea + 2) == 0xb503): #PUSH {R0,R1,LR}
if get_operand_type(ea + 4, 0) == 7:
pop = get_bytes(ea + 12, 4, 0)
if pop[1] == 'xbc':
register = -1
r = get_wide_byte(ea + 12)
for i in range(8):
if r == (1 << i):
register = i
break
if register == -1:
print "Unable to detect register"
else:
address = get_wide_dword(ea + 8) + ea + 8
for b in patches[register]:
patch_byte(ea, b)
ea += 1
if ea % 4 != 0:
ea += 2
patch_dword(ea, address)
elif pop[:3] == 'x5dxf8x04':
register = ord(pop[3]) >> 4
if register in patches:
address = get_wide_dword(ea + 8) + ea + 8
for b in patches[register]:
patch_byte(ea, b)
ea += 1
patch_dword(ea, address)
else:
print "POP instruction not found"
else:
print "Wrong operand type on +4:", get_operand_type(ea + 4, 0)
else:
print "Unable to detect first instructions"

Urang nempatkeun kursor di awal struktur nu urang hoyong ngaganti - 0xB4B2 - tur ngajalankeun skrip:

Milarian kerentanan dina UC Browser

Salian struktur anu parantos disebatkeun, kodeu ogé ngandung ieu:

Milarian kerentanan dina UC Browser

Saperti dina kasus saméméhna, sanggeus instruksi BLX aya hiji offset:

Milarian kerentanan dina UC Browser

Kami nyandak offset ka alamat tina LR, tambahkeun ka LR sareng angkat ka dinya. 0x72044 + 0xC = 0x72050. Skrip pikeun desain ieu cukup saderhana:

def put_unconditional_branch(source, destination):
offset = (destination - source - 4) >> 1
if offset > 2097151 or offset < -2097152:
raise RuntimeError("Invalid offset")
if offset > 1023 or offset < -1024:
instruction1 = 0xf000 | ((offset >> 11) & 0x7ff)
instruction2 = 0xb800 | (offset & 0x7ff)
patch_word(source, instruction1)
patch_word(source + 2, instruction2)
else:
instruction = 0xe000 | (offset & 0x7ff)
patch_word(source, instruction)
ea = here()
if get_wide_word(ea) == 0xb503: #PUSH {R0,R1,LR}
ea1 = ea + 6
if get_wide_word(ea + 2) == 0xbf00: #NOP
ea1 += 2
offset = get_wide_dword(ea1)
put_unconditional_branch(ea, (ea1 + offset) & 0xffffffff)
else:
print "Unable to detect first instruction"

Hasil palaksanaan naskah:

Milarian kerentanan dina UC Browser

Sakali sagalana geus patched dina fungsi, anjeun tiasa nunjuk IDA ka awal nyata na. Bakal sapotong babarengan sakabeh kode fungsi, sarta eta bisa decompiled maké HexRays.

Decoding string

Kami geus diajar nungkulan obfuscation kode mesin di perpustakaan libsgmainso-6.4.36.jadi ti UC Browser sareng nampi kodeu fungsi JNI_OnLoad.

int __fastcall real_JNI_OnLoad(JavaVM *vm)
{
int result; // r0
jclass clazz; // r0 MAPDST
int v4; // r0
JNIEnv *env; // r4
int v6; // [sp-40h] [bp-5Ch]
int v7; // [sp+Ch] [bp-10h]
v7 = *(_DWORD *)off_8AC00;
if ( !vm )
goto LABEL_39;
sub_7C4F4();
env = (JNIEnv *)sub_7C5B0(0);
if ( !env )
goto LABEL_39;
v4 = sub_72CCC();
sub_73634(v4);
sub_73E24(&unk_83EA6, &v6, 49);
clazz = (jclass)((int (__fastcall *)(JNIEnv *, int *))(*env)->FindClass)(env, &v6);
if ( clazz
&& (sub_9EE4(),
sub_71D68(env),
sub_E7DC(env) >= 0
&& sub_69D68(env) >= 0
&& sub_197B4(env, clazz) >= 0
&& sub_E240(env, clazz) >= 0
&& sub_B8B0(env, clazz) >= 0
&& sub_5F0F4(env, clazz) >= 0
&& sub_70640(env, clazz) >= 0
&& sub_11F3C(env) >= 0
&& sub_21C3C(env, clazz) >= 0
&& sub_2148C(env, clazz) >= 0
&& sub_210E0(env, clazz) >= 0
&& sub_41B58(env, clazz) >= 0
&& sub_27920(env, clazz) >= 0
&& sub_293E8(env, clazz) >= 0
&& sub_208F4(env, clazz) >= 0) )
{
result = (sub_B7B0(env, clazz) >> 31) | 0x10004;
}
else
{
LABEL_39:
result = -1;
}
return result;
}

Hayu urang nempo leuwih deukeut garis handap:

  sub_73E24(&unk_83EA6, &v6, 49);
clazz = (jclass)((int (__fastcall *)(JNIEnv *, int *))(*env)->FindClass)(env, &v6);

Dina fungsi sub_73E24 ngaran kelas jelas keur decrypted. Salaku parameter pikeun fungsi ieu, hiji pointer ka data sarupa data énkripsi, panyangga tangtu jeung nomer anu diliwatan. Jelas, saatos nyauran fungsina, bakal aya garis anu didekripsi dina panyangga, sabab disalurkeun kana fungsina. FindClass, nu nyokot ngaran kelas salaku parameter kadua. Ku alatan éta, jumlahna nyaéta ukuran panyangga atawa panjang garis. Hayu urang coba mun decipher ngaran kelas, éta kudu ngabejaan urang naha urang bade di arah nu bener. Hayu urang nempo leuwih deukeut naon kajadian di sub_73E24.

int __fastcall sub_73E56(unsigned __int8 *in, unsigned __int8 *out, size_t size)
{
int v4; // r6
int v7; // r11
int v8; // r9
int v9; // r4
size_t v10; // r5
int v11; // r0
struc_1 v13; // [sp+0h] [bp-30h]
int v14; // [sp+1Ch] [bp-14h]
int v15; // [sp+20h] [bp-10h]
v4 = 0;
v15 = *(_DWORD *)off_8AC00;
v14 = 0;
v7 = sub_7AF78(17);
v8 = sub_7AF78(size);
if ( !v7 )
{
v9 = 0;
goto LABEL_12;
}
(*(void (__fastcall **)(int, const char *, int))(v7 + 12))(v7, "DcO/lcK+h?m3c*q@", 16);
if ( !v8 )
{
LABEL_9:
v4 = 0;
goto LABEL_10;
}
v4 = 0;
if ( !in )
{
LABEL_10:
v9 = 0;
goto LABEL_11;
}
v9 = 0;
if ( out )
{
memset(out, 0, size);
v10 = size - 1;
(*(void (__fastcall **)(int, unsigned __int8 *, size_t))(v8 + 12))(v8, in, v10);
memset(&v13, 0, 0x14u);
v13.field_4 = 3;
v13.field_10 = v7;
v13.field_14 = v8;
v11 = sub_6115C(&v13, &v14);
v9 = v11;
if ( v11 )
{
if ( *(_DWORD *)(v11 + 4) == v10 )
{
qmemcpy(out, *(const void **)v11, v10);
v4 = *(_DWORD *)(v9 + 4);
}
else
{
v4 = 0;
}
goto LABEL_11;
}
goto LABEL_9;
}
LABEL_11:
sub_7B148(v7);
LABEL_12:
if ( v8 )
sub_7B148(v8);
if ( v9 )
sub_7B148(v9);
return v4;
}

fungsi sub_7AF78 nyiptakeun conto wadah pikeun arrays bait tina ukuran nu ditangtukeun (urang moal Huni on peti ieu di jéntré). Di dieu dua wadah sapertos anu dijieun: hiji ngandung garis "DcO/lcK+h?m3c*q@" (Éta gampang pikeun nebak yén ieu téh konci), nu séjén ngandung data énkripsi. Salajengna, duanana obyék disimpen dina struktur nu tangtu, nu dibikeun ka fungsi sub_6115C. Hayu urang ogé cirian widang kalayan nilai 3 dina struktur ieu.

int __fastcall sub_611B4(struc_1 *a1, _DWORD *a2)
{
int v3; // lr
unsigned int v4; // r1
int v5; // r0
int v6; // r1
int result; // r0
int v8; // r0
*a2 = 820000;
if ( a1 )
{
v3 = a1->field_14;
if ( v3 )
{
v4 = a1->field_4;
if ( v4 < 0x19 )
{
switch ( v4 )
{
case 0u:
v8 = sub_6419C(a1->field_0, a1->field_10, v3);
goto LABEL_17;
case 3u:
v8 = sub_6364C(a1->field_0, a1->field_10, v3);
goto LABEL_17;
case 0x10u:
case 0x11u:
case 0x12u:
v8 = sub_612F4(
a1->field_0,
v4,
*(_QWORD *)&a1->field_8,
*(_QWORD *)&a1->field_8 >> 32,
a1->field_10,
v3,
a2);
goto LABEL_17;
case 0x14u:
v8 = sub_63A28(a1->field_0, v3);
goto LABEL_17;
case 0x15u:
sub_61A60(a1->field_0, v3, a2);
return result;
case 0x16u:
v8 = sub_62440(a1->field_14);
goto LABEL_17;
case 0x17u:
v8 = sub_6226C(a1->field_10, v3);
goto LABEL_17;
case 0x18u:
v8 = sub_63530(a1->field_14);
LABEL_17:
v6 = 0;
if ( v8 )
{
*a2 = 0;
v6 = v8;
}
return v6;
default:
LOWORD(v5) = 28032;
goto LABEL_5;
}
}
}
}
LOWORD(v5) = -27504;
LABEL_5:
HIWORD(v5) = 13;
v6 = 0;
*a2 = v5;
return v6;
}

Parameter switch mangrupakeun widang struktur anu saméméhna ditugaskeun nilai 3. Tingali dina kasus 3: kana fungsi sub_6364C parameter disalurkeun tina struktur nu ditambahkeun aya dina fungsi saméméhna, nyaéta konci na data énkripsi. Lamun nempo deukeut sub_6364C, Anjeun tiasa mikawanoh algoritma RC4 di dinya.

Kami ngagaduhan algoritma sareng konci. Hayu urang coba decipher ngaran kelas. Ieu kajadian: com / taobao / nirkabel / kaamanan / adaptor / JNICLlibrary. Hebat! Kami dina jalur anu leres.

Tangkal paréntah

Ayeuna urang kedah milarian tantangan RegisterNatives, nu bakal nunjuk urang ka fungsi doCommandNative. Hayu urang nempo fungsi disebut ti JNI_OnLoad, sarta kami manggihan eta di sub_B7B0:

int __fastcall sub_B7F6(JNIEnv *env, jclass clazz)
{
char signature[41]; // [sp+7h] [bp-55h]
char name[16]; // [sp+30h] [bp-2Ch]
JNINativeMethod method; // [sp+40h] [bp-1Ch]
int v8; // [sp+4Ch] [bp-10h]
v8 = *(_DWORD *)off_8AC00;
decryptString((unsigned __int8 *)&unk_83ED9, (unsigned __int8 *)name, 0x10u);// doCommandNative
decryptString((unsigned __int8 *)&unk_83EEA, (unsigned __int8 *)signature, 0x29u);// (I[Ljava/lang/Object;)Ljava/lang/Object;
method.name = name;
method.signature = signature;
method.fnPtr = sub_B69C;
return ((int (__fastcall *)(JNIEnv *, jclass, JNINativeMethod *, int))(*env)->RegisterNatives)(env, clazz, &method, 1) >> 31;
}

Sareng leres, metode asli sareng nami didaptarkeun di dieu doCommandNative. Ayeuna urang terang alamatna. Hayu urang tingali naon anu anjeunna lakukeun.

int __fastcall doCommandNative(JNIEnv *env, jobject obj, int command, jarray args)
{
int v5; // r5
struc_2 *a5; // r6
int v9; // r1
int v11; // [sp+Ch] [bp-14h]
int v12; // [sp+10h] [bp-10h]
v5 = 0;
v12 = *(_DWORD *)off_8AC00;
v11 = 0;
a5 = (struc_2 *)malloc(0x14u);
if ( a5 )
{
a5->field_0 = 0;
a5->field_4 = 0;
a5->field_8 = 0;
a5->field_C = 0;
v9 = command % 10000 / 100;
a5->field_0 = command / 10000;
a5->field_4 = v9;
a5->field_8 = command % 100;
a5->field_C = env;
a5->field_10 = args;
v5 = sub_9D60(command / 10000, v9, command % 100, 1, (int)a5, &v11);
}
free(a5);
if ( !v5 && v11 )
sub_7CF34(env, v11, &byte_83ED7);
return v5;
}

Ku nami anjeun tiasa nebak yén ieu mangrupikeun titik éntri sadaya fungsi anu diputuskeun ku pamekar pikeun mindahkeun ka perpustakaan asli. Kami museurkeun nomer fungsi 10601.

Anjeun tiasa ningali tina kode yén nomer paréntah ngahasilkeun tilu nomer: paréntah / 10000, paréntah% 10000 / 100 и paréntah% 10, i.e., bisi urang, 1, 6 jeung 1. Tilu angka ieu, kitu ogé pointer ka JNIEnv jeung argumen diliwatan kana fungsi nu ditambahkeun kana struktur sarta disalurkeun. Ngagunakeun tilu angka diala (hayu urang denote aranjeunna N1, N2 na N3), hiji tangkal paréntah diwangun.

Sapertos kieu:

Milarian kerentanan dina UC Browser

Tangkal dieusi sacara dinamis JNI_OnLoad.
Tilu angka encode jalur dina tangkal. Unggal daun tangkal ngandung alamat pocked tina fungsi pakait. Koncina aya dina titik indungna. Milarian tempat dina kode dimana fungsi anu urang peryogikeun kana tangkal henteu sesah upami anjeun ngartos sadayana struktur anu dianggo (kami henteu ngajelaskeun aranjeunna supados henteu ngambekan tulisan anu parantos ageung).

Beuki obfuscation

Kami nampi alamat fungsi anu kedah ngadekrip lalu lintas: 0x5F1AC. Tapi teuing awal pikeun girang: pamekar UC Browser parantos nyiapkeun kejutan anu sanés pikeun urang.

Sanggeus narima parameter tina Asép Sunandar Sunarya nu kabentuk dina kode Java, urang meunang
ka fungsi dina alamat 0x4D070. Sareng di dieu aya jinis obfuscation kode anu sanés ngantosan urang.

Kami nempatkeun dua indéks dina R7 sareng R4:

Milarian kerentanan dina UC Browser

Urang mindahkeun indéks munggaran ka R11:

Milarian kerentanan dina UC Browser

Pikeun kéngingkeun alamat tina méja, paké indéks:

Milarian kerentanan dina UC Browser

Saatos angkat ka alamat kahiji, indéks kadua dianggo, nyaéta dina R4. Aya 230 elemen dina tabél.

Naon anu kudu dipigawé ngeunaan eta? Anjeun tiasa ngabejaan IDA yén ieu téh switch a: Edit -> lianna -> Sebutkeun switch idiom.

Milarian kerentanan dina UC Browser

Kodeu hasilna pikasieuneun. Tapi, ngaliwat leuweung, anjeun tiasa perhatikeun telepon ka fungsi anu parantos wawuh ka urang sub_6115C:

Milarian kerentanan dina UC Browser

Aya switch nu bisi 3 aya dekripsi ngagunakeun algoritma RC4. Sareng dina hal ieu, struktur anu disayogikeun kana fungsina dieusi tina parameter anu disalurkeun ka doCommandNative. Hayu urang émut naon anu aya di dinya magicInt kalawan nilai 16. Urang tingali dina kasus nu saluyu - sarta sanggeus sababaraha transisi urang manggihan kodeu nu algoritma nu bisa dicirikeun.

Milarian kerentanan dina UC Browser

Ieu AES!

Algoritma aya, ngan ukur kéngingkeun parameterna: modeu, konci sareng, kamungkinan, vektor initialization (aya ayana gumantung kana mode operasi algoritma AES). Struktur sareng aranjeunna kedah dibentuk dimana waé sateuacan nelepon fungsi sub_6115C, Tapi ieu bagian tina kode ieu utamana ogé obfuscated, jadi timbul ide pikeun patch kode supados sadaya parameter tina fungsi dekripsi nu dumped kana file.

Tambalan

Pikeun henteu nyerat sadaya kode patch dina basa rakitan sacara manual, anjeun tiasa ngaluncurkeun Android Studio, nyerat fungsi di dinya anu nampi parameter input anu sami sareng fungsi dekripsi urang sareng nyerat kana file, teras salin-témpél kodeu anu bakal dikompiler. ngabangkitkeun.

Babaturan urang ti tim UC Browser ogé ngurus genah pikeun nambahkeun kode. Hayu urang émut yén dina awal unggal fungsi kami ngagaduhan kode sampah anu gampang diganti ku anu sanés. Kacida merenah 🙂 Sanajan kitu, dina awal fungsi target teu cukup spasi pikeun kode nu ngaheéat sakabéh parameter kana file a. Kuring kungsi dibeulah jadi bagian sarta ngagunakeun blok sampah ti fungsi tatangga. Jumlahna aya opat bagian.

Bagian kahiji:

Milarian kerentanan dina UC Browser

Dina arsitéktur ARM, opat parameter fungsi munggaran dialirkeun ngaliwatan registers R0-R3, sésana, lamun sagala, ngaliwatan tumpukan. The LR register mawa alamat balik. Sadaya ieu kedah disimpen supados fungsina tiasa dianggo saatos urang ngaleungitkeun parameterna. Urang ogé kudu ngahemat sagala registers nu urang bakal dipaké dina prosés, sangkan ngalakukeun PUSH.W {R0-R10,LR}. Dina R7 kami meunang alamat daptar parameter disalurkeun kana fungsi via tumpukan.

Ngagunakeun fungsi fopen hayu urang buka file /data/local/tmp/aes dina modeu "ab".
i.e. pikeun tambahan. Dina R0 kami muka alamat nami file, di R1 - alamat jalur anu nunjukkeun modeu. Sarta di dieu kode sampah ends, sangkan ngaléngkah ka fungsi salajengna. Supados eta neruskeun dianggo, urang nempatkeun di awal transisi ka kode nyata fungsi, bypassing sampah, sarta tinimbang sampah urang tambahkeun hiji tuluyan tina patch.

Milarian kerentanan dina UC Browser

Nelepon fopen.

Tilu parameter mimiti fungsi AES gaduh tipe int. Kusabab urang disimpen registers ka tumpukan di awal, urang ngan saukur bisa lulus fungsi nulis alamat maranéhanana dina tumpukan.

Milarian kerentanan dina UC Browser

Salajengna urang gaduh tilu struktur anu ngandung ukuran data sareng pointer kana data pikeun konci, vektor initialization sareng data énkripsi.

Milarian kerentanan dina UC Browser

Dina tungtungna, tutup file, balikkeun registers sarta mindahkeun kontrol ka fungsi nyata AES.

Urang ngumpulkeun hiji APK kalawan perpustakaan patched, asup, unggah ka alat / émulator, tur ngajalankeun eta. Urang nempo yén dump urang keur dijieun, sarta loba data keur ditulis di dinya. Browser ngagunakeun enkripsi henteu ngan pikeun lalu lintas, sareng sadaya enkripsi ngalangkungan fungsi anu dimaksud. Tapi pikeun sababaraha alesan henteu aya data anu diperyogikeun, sareng pamundut anu diperyogikeun henteu katingali dina lalu lintas. Dina raraga teu antosan dugi UC Browser deigns nyieun pamundut diperlukeun, hayu urang nyandak réspon énkripsi ti server narima saméméhna tur patch aplikasi deui: tambahkeun dekripsi onCreate tina aktivitas utama.

    const/16 v1, 0x62
new-array v1, v1, [B
fill-array-data v1, :encrypted_data
const/16 v0, 0x1f
invoke-static {v0, v1}, Lcom/uc/browser/core/d/c/g;->j(I[B)[B
move-result-object v1
array-length v2, v1
invoke-static {v2}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object v2
const-string v0, "ololo"
invoke-static {v0, v2}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

Urang ngumpul, asup, masang, ngajalankeun. Simkuring nampi NullPointerException sabab metoda balik null.

Salila analisis salajengna kode, kapanggih hiji fungsi nu deciphers garis metot: "META-INF /" jeung ".RSA". Sigana mah aplikasina nuju marios sertipikatna. Atawa malah dibangkitkeun konci ti dinya. Kuring teu hayang pisan nungkulan naon anu lumangsung kalawan sertipikat, jadi urang ngan bakal dieunakeun eta sertipikat bener. Hayu urang patch garis énkripsi ambéh tinimbang "META-INF /" urang meunang "BLABLINF /", nyieun folder kalawan ngaran nu di APK tur nambahkeun sertipikat browser bajing dinya.

Urang ngumpul, asup, masang, ngajalankeun. Bingo! Urang boga konci!

MitM

Kami nampi konci sareng vektor initialization sami sareng konci. Hayu urang cobian ngadekrip réspon server dina modeu CBC.

Milarian kerentanan dina UC Browser

Kami ningali URL arsip, anu sami sareng MD5, "extract_unzipsize" sareng nomer. Kami pariksa: MD5 arsipna sami, ukuran perpustakaan anu teu dibungkus sami. Urang nyobian patch perpustakaan ieu sareng masihan ka browser nu. Pikeun nunjukkeun yén perpustakaan kami anu ditambal parantos dimuat, kami bakal ngaluncurkeun Hajat pikeun nyiptakeun SMS nganggo téks "PWNED!" Urang bakal ngaganti dua réspon ti server: puds.ucweb.com/upgrade/index.xhtml sarta pikeun ngundeur arsip. Dina kahiji urang ngaganti MD5 (ukuranana teu robah sanggeus unpacking), dina kadua urang masihan arsip jeung perpustakaan patched.

Browser nyobian ngaunduh arsip sababaraha kali, saatos éta masihan kasalahan. Tétéla kitu
anjeunna teu resep. Salaku hasil analisa format murky ieu, tétéla yén server ogé ngirimkeun ukuran arsip:

Milarian kerentanan dina UC Browser

Ieu disandikeun dina LEB128. Saatos patch, ukuran arsip jeung perpustakaan robah saeutik, jadi browser nu dianggap yén arsip ieu diundeur crookedly, sarta sanggeus sababaraha usaha eta threw kasalahan.

Urang nyaluyukeun ukuran arsip ... Jeung - meunangna! 🙂 hasilna aya dina video.

https://www.youtube.com/watch?v=Nfns7uH03J8

Konsékuansi jeung réaksi pamekar

Dina cara anu sami, peretas tiasa nganggo fitur UC Browser anu teu aman pikeun nyebarkeun sareng ngajalankeun perpustakaan jahat. Perpustakaan ieu bakal tiasa dianggo dina konteks browser, ku kituna aranjeunna bakal nampi sadaya idin sistemna. Hasilna, kamampuhan pikeun nembongkeun jandéla phishing, kitu ogé aksés ka file gawé tina bajing Cina jeruk, kaasup logins, kecap akses tur cookies disimpen dina database.

Kami ngahubungi pamekar UC Browser sareng ngawartosan aranjeunna ngeunaan masalah anu kami mendakan, nyobian nunjukkeun kerentanan sareng bahaya na, tapi aranjeunna henteu ngabahas nanaon sareng kami. Samentara éta, browser terus flaunt fitur bahaya na di tetempoan polos. Tapi sakali kami ngungkabkeun rinci ngeunaan kerentanan, éta henteu deui mungkin pikeun malire deui sapertos sateuacanna. 27 Maret éta
versi anyar tina UC Browser 12.10.9.1193 dileupaskeun, nu diaksés server via HTTPS: puds.ucweb.com/upgrade/index.xhtml.

Salaku tambahan, saatos "fix" sareng dugi ka waktos nyerat tulisan ieu, nyobian muka PDF dina browser nyababkeun pesen kasalahan kalayan téks "Aduh, aya anu salah!" Paménta ka server henteu dilakukeun nalika nyobian muka PDF, tapi pamenta dilakukeun nalika browser diluncurkeun, anu nunjukkeun kamampuan pikeun ngaunduh kode anu tiasa dieksekusi ngalanggar aturan Google Play.

sumber: www.habr.com

Tambahkeun komentar