漏洞概要 关注数(24) 关注此漏洞
缺陷编号:wooyun-2015-0162907
漏洞标题:讲解一步步逆向破解华住酒店集团官网APP的http包加密算法以及一系列漏洞打包
相关厂商:汉庭酒店
漏洞作者: soFree
提交时间:2015-12-28 12:42
修复时间:2016-02-08 18:23
公开时间:2016-02-08 18:23
漏洞类型:设计缺陷/逻辑错误
危害等级:高
自评Rank:20
漏洞状态:厂商已经确认
漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]
Tags标签: 无
漏洞详情
披露状态:
2015-12-28: 细节已通知厂商并且等待厂商处理中
2015-12-28: 厂商已经确认,细节仅向厂商公开
2016-01-07: 细节向核心白帽子及相关领域专家公开
2016-01-17: 细节向普通白帽子公开
2016-01-27: 细节向实习白帽子公开
2016-02-08: 细节向公众公开
简要描述:
今天在华住酒店订了酒店,话说华住酒店app是不是也不少漏洞?说干就干(本文重点:破解http包的加密算法),貌似android端的app有30多万人安装,ios端肯定也不少,因为http包的加密算法肯定都是一样的
哇塞:华住酒店集团是中国国内第一家多品牌的上市连锁酒店管理集团,位列全球酒店13强。
详细说明:
《开胃小菜》
抓包,截获请求,发现请求各种加密了,完全看不懂啊,如何改包,实现各种恶意攻击(权限绕过、逻辑权限、设计缺陷)呢
原始http包:
首先能正常抓包,说明会存在中间人攻击的风险,
漏洞1(高危):不校验证书,或证书配置和校验有误
危害和利用:中间人攻击或截包,在破解加密算法(本文后面已经实现)的情况下可解密截获的包,获取大量敏感数据
下面反编译
轻松反编译,且代码未混淆,轻松静态分析和动态调试,
漏洞2(中危):代码未混淆,app未进行防反编译的处理(比如第三方加固等等)
危害和利用:静态分析代码和动态调试app,实现各种攻击
查看androidMainfest文件,
漏洞3(中危):android:debuggable和android:allowBackup未设置为false
危害:动态调试应用、未root状态下备份和恢复应用数据
利用:
备份:adb backup -nosystem -noshared -apk -f backup.ab com.htinns
恢复:adb restore backup.ab
漏洞4(低危):以下组件存在本地拒绝服务漏洞:
cn.jpush.android.ui.PushActivity
com.na517.wxapi.WXPayEntryActivity
com.htinns.UI.PushMessageReceiver
com.htinns.jpush.MyReceiver
危害和利用:crush应用,导致应用始终无法使用
打开ddms,发几个请求,发现logcat打印出了全部级别日志,其中日志中保护大量敏感信息(密码、账号、身份证)
漏洞5(中危):未合理配置logcat打印日志级别(测试环境打印可以全部级别的日志,而线上环境应该关闭v、d、甚至i级别的日志)
危害和利用:很多开发同学都知道默认Log.v(d、i、e、w)是写入/dev/log/main中的,于是我们可以pull出main文件,即可能会获取到该应用的敏感数据
打印全部级别日志及敏感数据:
尝试在androidMainfest文件中加入:android:debuggable="true",然后二次打包并签名,发现应用可正常运行,完全没问题
漏洞6(中危):可二次打包,前端和服务端均未做防二次打包的任何处理
危害和利用:恶意注入任意代码和更改配置,然后二次打包,钓鱼他人或实现自己的各种恶意攻击需求
《压轴大戏》
有了前面的漏洞铺垫,下面开始着重讲解如何一步步破解http包的加密算法
原始http包详细:
分析代码,定位到加密算法的逻辑代码:com.htinns.biz.HttpUtils.class
实现逻辑:
我精简总结下这四个参数的算法:
data = RC4Factory.encry_RC4_string(unSignData, KEY);
//时间戳保证每次请求包不一样
time = new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime());
sign = Base64.encodeToString(Utils.GetByteForMD5(unSign), 2);
APPSIGN = sendSign(sign)
注意:分析知道,除了sendSign()算法是用c或c++写的,放入了so库,其他重要算法都是用java写的,通过反编译后可直接获取
生成data中的RC4Factory.encry_RC4_string()的实现逻辑:
需要注意的是:里面的Base64不是采用的官方Base64算法,为自定义算法
自定义的Base64.encodeToString()实现逻辑:
生成sign中的Utils.GetByteForMD5()实现逻辑:
生成sign中Base64.encodeToString()实现逻辑不用说了,因为直接用的官方的android.util.Base64算法
而不同函数里面调用的其他代码逻辑均可在应用代码中获取
PS一句:开发同学搞笑有爱呀,只是将部分算法放入so库,是偷懒还是觉得放一个算法进入so库就万无一失?!
重点:现在主要详细讲解下如何破解放入so库中的sendSign()算法: public static native int[] getSign(String str);
简单来说就是传入sign(比如:ZDelvz4eSWImxQMVuZo8MA==),编码后获取一个整数数组
这里,有四种方式可以破解:
1.反编译so,分析汇编代码
2.动态调试so文件
3.分析大量sign和getSign(sign)的数据,猜测出实现算法
4.巧妙分析sign和getSign(sign)的数据,做一个算法破解字典
前两种要求内功比较深厚,鄙人级别不够,第三种太傻瓜式,需要很大运气成分,我们这里采用第四种方法,做破解字典
需要做破解字典,首先需要拿到大量组的sign和getSign(sign)的数据,官方apk在logcat未打印getSign(sign)的数据,这里我们采用代码注入后二次打包,打印出getSign(sign)的数据
红色框框内为我注入的代码,逻辑很简单:将int数组转成string,然后在logcat中打印出来
注入的代码:
通过发送大量请求,打印getSign(sign):
int数组:
我们选取其中11组sign和getSign(sign)的数据:
2hWXhMB404zG9HLrHM4paA==
[449293, 494595, 368417, 446475, 494595, 338131, 498647, 67754, 378616, 67754, 330687, 304730, 405824, 355682, 573682, 57259, 355682, 338131, 67754, 233541, 451215, 299125, 711991, 711991,
364155, 321719, 426313, 31110, 494595, 217203, 237685, 598924, 598924, 393061]
nPFYGYUPe0oOyqQlfsMJhw==
[598924, 421395, 222469, 409389, 304730, 409389, 319505, 421395, 120053, 378616, 321719, 249550, 52111, 396736, 662102, 403683, 326904, 393061, 338131, 706921, 494595, 131599, 711991, 711991, 364155, 321719, 426313, 31110, 494595, 217203, 237685, 598924, 598924, 393061]
qrCz3LSGqug2Q7LvdqOy3w==
[396736, 57259, 492145, 330687, 393492, 573682, 20772, 304730, 396736, 633844, 586550, 449293, 662102, 612137, 573682, 527361, 176612, 396736, 249550, 52111, 393492, 131599, 711991, 711991, 364155, 321719, 426313, 31110, 494595, 217203, 237685, 598924, 598924, 393061]
[396736, 57259, 492145, 330687, 393492, 573682, 20772, 304730, 396736, 633844, 586550, 449293, 662102, 612137, 573682, 527361, 176612, 396736, 249550, 52111, 393492, 131599, 711991, 711991, 364155, 321719, 426313, 31110, 494595, 217203, 237685, 598924, 598924, 393061]
pXp1AhyO5JgdpfNz2/yJiA==
[233541, 446475, 233541, 655175, 299125, 494595, 52111, 249550, 495424, 706921, 586550, 176612, 233541, 326904, 343583, 330687, 449293, 573894, 52111, 706921, 237685, 299125, 711991, 711991, 364155, 321719, 426313, 31110, 494595, 217203, 237685, 598924, 598924, 393061]
4B/E0/+RHqYtcobqqpATZw==
[67754, 498647, 573894, 462704, 378616, 573894, 727256, 688948, 355682, 396736, 409389, 217203, 364155, 321719, 605981, 396736, 396736, 233541, 299125, 411712, 323612, 131599, 711991, 711991, 364155, 321719, 426313, 31110, 494595, 217203, 237685, 598924, 598924, 393061]
jS/yMsZMLwj+k/5kSUpyFQ==
[470840, 20772, 573894, 52111, 338131, 393061, 323612, 338131, 573682, 131599, 470840, 727256, 281742, 573894, 495424, 281742, 20772, 319505, 233541, 52111, 222469, 662102, 711991, 711991, 364155, 321719, 426313, 31110, 494595, 217203, 237685, 598924, 598924, 393061]
U6xzuUiMLkIiLX9v4i40Lw==
[319505, 189632, 445269, 330687, 633844, 319505, 237685, 338131, 573682, 281742, 165016, 237685, 573682, 446475, 405824, 527361, 67754, 237685, 67754, 378616, 573682, 131599, 711991, 711991, 364155, 321719, 426313, 31110, 494595, 217203, 237685, 598924, 598924, 393061]
2OCNraZHgOeOVVbeCgKRtg==
[449293, 249550, 492145, 343583, 57259, 451215, 323612, 355682, 586550, 249550, 120053, 249550, 616713, 616713, 605981, 120053, 492145, 586550, 627761, 688948, 217203, 586550, 711991, 711991, 364155, 321719, 426313, 31110, 494595, 217203, 237685, 598924, 598924, 393061]
X9lMaJXumu/E0c7OFRRSWw==
[446475, 405824, 403683, 338131, 451215, 706921, 446475, 633844, 426313, 633844, 573894, 462704, 378616, 364155, 612137, 249550, 222469, 688948, 688948, 20772, 368417, 131599, 711991, 711991, 364155, 321719, 426313, 31110, 494595, 217203, 237685, 598924, 598924, 393061]
[446475, 405824, 403683, 338131, 451215, 706921, 446475, 633844, 426313, 633844, 573894, 462704, 378616, 364155, 612137, 249550, 222469, 688948, 688948, 20772, 368417, 131599, 711991, 711991, 364155, 321719, 426313, 31110, 494595, 217203, 237685, 598924, 598924, 393061]
mSHev1YvdWPRmXirI+1ZLQ==
[426313, 20772, 355682, 120053, 527361, 655175, 409389, 527361, 176612, 368417, 421395, 688948, 426313, 446475, 237685, 57259, 165016, 727256, 655175, 323612, 573682, 662102, 711991, 711991, 364155, 321719, 426313, 31110, 494595, 217203, 237685, 598924, 598924, 393061]
ZDelvz4eSWImxQMVuZo8MA==
[323612, 595327, 120053, 403683, 527361, 330687, 67754, 120053, 20772, 368417, 165016, 426313, 445269, 662102, 338131, 616713, 633844, 323612, 321719, 300769, 338131, 299125, 711991, 711991, 364155, 321719, 426313, 31110, 494595, 217203, 237685, 598924, 598924, 393061]
[323612, 595327, 120053, 403683, 527361, 330687, 67754, 120053, 20772, 368417, 165016, 426313, 445269, 662102, 338131, 616713, 633844, 323612, 321719, 300769, 338131, 299125, 711991, 711991, 364155, 321719, 426313, 31110, 494595, 217203, 237685, 598924, 598924, 393061]
分析可知:24个字符长度的sign通过so库后得到34个整数的数组,而多出来的10个总是不变的,于是,我们只需要破解前24个字符然后加上多出来的10个固定整数即可
整理出的破解字典(包括大小写的26个字母和/、+、=,共计55个可能字符):
/:573894;+:727256;=:711991;
0:378616;1:655175;2:449293;3:393492;4:67754;5:281742;6:189632;7:612137;8:300769;9:405824;
a:451215;b:605981;c:364155;d:176612;e:120053;f:326904;g:586550;h:494595;i:237685;j:470840;k:281742;l:403683;m:426313;n:598924;o:321719;p:233541;q:396736;r:57259;s:393061;t:217203;u:633844;v:527361;w:131599;x:445269;y:52111;z:330687;
A:299125;B:498647;C:492145;D:595327;E:462704;F:222469;G:304730;H:355682;I:165016;J:706921;K:627761;L:573682;M:338131;N:343583:O:249550;P:421395;Q:662102;R:688948;S:20772;T:411712;U:319505;V:616713;W:368417;X:446475;Y:409389;Z:323612;
现在初始工作全部搞定,哇哦!简直太完美了!咱们可以开始在android studio中写出http包的加密算法了:
studio中代码架构:
加密算法:
unSignData为原始正常的请求包,不同类型的请求不一样,我们可以在logcat中获取
比如注册发送验证码,url:http://app.h-world.com:5552//local/guest/GetMobileCheckNo/android/5@6/zh
unSignData>>{"platform":"android","os":"4.2.2","model":"X909","CHANNEL_ID":"4170168112385289278","Jpush_PUSH_TOKEN":"02005084453","PUSH_TOKEN":"615690410204829064","ver":"5.6","access_mode":"WIFI","devNo":"862374020867855","resultKey":"sdjkfj@#$#@$CC>LK:^&%$#$SFSFSFSF$#@$#@$","manufacturer":"OPPO","Jpush_CHANNEL_ID":"JPush","brand":"OPPO","MAC":"8c:0e:e3:f8:94:46","channel":"guanwang","checkType":"register","mobileNo":"15657585781"}
验证短信码:
unSignData>>{"platform":"android","os":"4.2.2","checkNo":"3481","model":"X909","CHANNEL_ID":"","Jpush_PUSH_TOKEN":"02005084453","PUSH_TOKEN":"","ver":"5.6","access_mode":"WIFI","devNo":"862374020867855","resultKey":"sdjkfj@#$#@$CC>LK:^&%$#$SFSFSFSF$#@$#@$","manufacturer":"OPPO","Jpush_CHANNEL_ID":"JPush","brand":"OPPO","szMobile":"15657585781","MAC":"8c:0e:e3:f8:94:46","channel":"guanwang"}
咱们随便拿一个unSignData来运行看看,成功破解!!跟截获的请求包一模一样! magnificent!
漏洞7(高危):所有重要算法未入so库或其他保护
危害和利用:现在我们可以任意改unSignData中的数据,然后生成http包中的四个参数,然后向服务器发请求了;同时可以截获别人的http包,逆向破解得到原始未加密的unSignData,获取账号、密码等等大量敏感信息
成功破解:
点到为止了!咱是白帽子,不再进行进一步的攻击利用,可以破解http包,肯定能做不少事
漏洞证明:
以上7类漏洞只是一部分,相信还有很多,比如,Web组件远程代码执行漏洞:未禁用危险接口addJavascriptInterface导出Java类及方法,未移除系统webkit内置的危险接口searchBoxJavaBridge_等,再比如,webview初始化时应该设置不保存密码,默认为true:webView.getSetting().setSavePassword(false);
建议厂商排查
修复方案:
只说加密算法的修复建议:所有重要算法入so库,建议关于http包优化设计方案,放弃加密方案
可参考我们公司移动端产品的方案:http包(request和response)双签名校验
版权声明:转载请注明来源 soFree@乌云
漏洞回应
厂商回应:
危害等级:高
漏洞Rank:18
确认时间:2015-12-28 14:23
厂商回复:
您好!感谢对华住酒店集团的关注,此问题己移交相关团队跟进处理。
最新状态:
暂无