WebView简介
Hi,我是观宇战队Di@m1racl3,今天聊聊Android WebView漏洞。WebView是用来显示和渲染Web页面的UI组件,可和JavaScript互相通信,内部采用WebKit渲染引擎来展示Web网页的内容。WebView的功能很强大,但随之带来的安全问题也很多,在当下APP漏洞中,WebView漏洞占比非常大,各种类型的漏洞层出不穷,如WebView任意代码执行、应用克隆、Intent Scheme、launchAnyWhere、XSS以及Deeplink等漏洞。
漏洞原理
文件读取漏洞是由于Android应用程序对用户输入的文件名称没有进行安全校验而导致的一种安全漏洞,攻击者可以通过构造特殊路径访问Android系统中的文件。
影响范围
Android版本 < 11。
漏洞危害
利用该漏洞可以访问Android系统文件,导致敏感信息泄露。
漏洞分析
代码跟踪
由于WebView漏洞众多,在分析一款二维码识别APP时发现,该APP的扫描Activity中使用了file://协议,如下图所示。因此试着测试该APP是否存在WebView相关漏洞,通过测试,发现存在文件读取漏洞,现将详细分析过程记录如下。
该APP扫描二维码后,将扫描所得的数据通过intent传入BarcodeResultActivity,然后在BarcodeResultActivity中通过调用getSerializableExtra函数得到intent中传入的BarcodeData对象。BarcodeData对象的内容由5部分组成,分别为barcodeType、dataType、originText、analyzedText和pickupInfo,其中originText里存储的则是从二维码中扫描得到的数据。如下图所示:
获取到二维码内容之后,扫描界面会生成一个超链接,点击该链接,会启动BarcodeOriginTextActivity。
在此过程中,有一个字符串转换的过程,从而导致了该漏洞的产生。开发者将扫描二维码得到的字符串转换成了html格式的字符串,并且是一个使用了href函数的超链接,转换之后的html格式字符串如图所示:
最后通过WebView的loadDataWithBaseURL函数进行加载。同时该APP为了禁止在WebView中执行js代码,造成不必要的安全风险,已将setJavaScriptEnabled的值设置为false,但是最终却导致了文件读取漏洞的产生。
通过分析,发现漏洞出现在loadDataWithBaseURL函数中,APP在调用loadDataWithBaseURL函数加载html格式的超链接时导致了文件读取漏洞。
利用链分析
本地利用:
如果APP本身存在利用链,可以直接通过APP完成攻击,如本文所述的APP。对于APP中不存在该利用链的,可以利用Intent-base攻击达到攻击目的。如图所示:
如果应用自己存在攻击链,则可通过应用直接查看敏感文件,与文中提到的APP类似。如果APP不存在利用链,但WebView是导出的情况,则可以直接通过攻击APP发送精心构造的Intent来调用目标APP的WebView实现攻击。然后对于WebView非导出的情况,则需要选择一个中间组件进行中转来实现攻击,即Intent重定向攻击方法,将精心构造的Intent通过攻击APP发送到导出的组件,最终通过该导出组件将payload发送至WebView实达到攻击目的。
远程利用:
该漏洞同样存在远程利用方法,可以结合deeplink或者Intent Scheme URL漏洞来达到远程利用目的。同时如果APP开启了端口监听,可以分析端口协议,也可能存在远程攻击链,从而达到攻击目的,与百度虫洞漏洞类似。
如果使用Intent Scheme URL来实现攻击,则需要通过存在该漏洞的浏览器来辅助实现,同时目标APP的WebView为导出即可。而Deeplink也需要间接通过浏览器来实现,并且要求目标APP的AndroidManifest配置文件中配置了android:scheme,则可以达到远程攻击的目的。对于目标APP开放端口的情况,则需要分析端口开放协议,与百度虫洞漏洞类似,如果APP中存在攻击链,也可以实现远程攻击。
漏洞复现
为了验证分析的正确性,使用android studio编写demo进行验证,首先创建一个MainActivity,然后在layout文件中添加一个EditText和Button,EditText用于模拟传入二维码数据部分,Button用于启动WebView。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" android:padding="15dp" > <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/file_path" android:textSize="24sp" android:hint="请输入要访问的文件名" android:drawablePadding="5dp" android:maxLines="1" android:paddingLeft="15dp" android:layout_gravity="center_vertical" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:id="@+id/access" android:text="访问" android:textSize="24sp" /> </LinearLayout>
然后在MainActivity中添加如下代码,设置一个Button监听,在输入框输入完毕后,点击访问按钮,APP将启动BarcodeOriginTextActivity,并且从输入框中取出文件路径,通过Intent的putExtra函数以“EXTRA_ORIGIN_TEXT”标签将文件路径传入BarcodeOriginTextActivity。
EditText filepath=(EditText) findViewById(R.id.file_path); button=findViewById(R.id.access); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String content=filepath.getText().toString(); Intent intent=new Intent(MainActivity.this,BarcodeOriginTextActivity.class); intent.putExtra("EXTRA_ORIGIN_TEXT",content); startActivity(intent); } });
接着创建BarcodeOriginTextActivity,并在layout中添加一个WebView,用于显示利用文件读取漏洞读取Android系统文件的内容。
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
在BarcodeOriginTextActivity添加如下代码,如图6所示,将setJavaScriptEnabled设置为false,同时为了排除跨域漏洞导致路径穿越的可能性,这里将setAllowFileAccessFromFileURLs和setAllowUniversalAccessFromFileURLs也设置为false。调用getStringExtra函数,从Intent中取出MainActivity传入的文件路径,最后调用PathTraversal函数。
WebView webView=(WebView) findViewById(R.id.webview); WebSettings settings = webView.getSettings(); settings.setJavaScriptEnabled(false); settings.setAllowFileAccessFromFileURLs(false); settings.setAllowUniversalAccessFromFileURLs(false); Intent intent=getIntent(); String html="<a href="+intent.getStringExtra("EXTRA_ORIGIN_TEXT")+">Click</a>"; PathTraversal(webView,html);
PathTraversal函数代码如下,只调用了loadDataWithBaseURL函数,将文件内容读出并显示在WebView中。
public void PathTraversal(WebView webView,String content){ webView.loadDataWithBaseURL("", content, "text/html", "UTF-8",""); }
验证结果截图如下,在输入框中输入文件路径。
点击访问按钮,启动BarcodeOriginTextActivity。
点击Click超链接,即可访问手机里的hosts文件。
由验证结果可知,当setAllowFileAccessFromFileURLs和setAllowUniversalAccessFromFileURLs均为false的情况下,该漏洞依然可以利用成功。因此如果WebView的loadDataWithBaseURL函数使用不当,会导致文件读取漏洞的安全风险。
修复建议
1、使用Android WebView的loadDataWithBaseURL函数时,对加载的网页内容进行检查,防止类似安全风险的发生;
2、尽量限制Android WebView只允许“http://”或者“https://”协议;
3、对于该漏洞,谷歌反馈已在Android 11中修复了此问题,通过测试,在Android 11中已不存在,因此建议将系统升级到Android 11及以上。
观宇战队
新华三观宇战队,专注前沿防御技术研究,研究方向包括漏洞分析、攻击反制、病毒木马分析、APT分析等,长期招聘攻防研究员,简历投递:jiang.wenming@h3c.com(请注明来自FreeBuf)