内容纲要

静态漏扫资料1

1. Implicit intents

主程序调用了startActivityForResult隐式intent

处理intent的地方设置了setResult

主程序接收信息的方法为onActivityResult

private static final int PICK_CODE = 1337;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    startActivityForResult(new Intent(Intent.ACTION_PICK), PICK_CODE);
}

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode != Activity.RESULT_OK) {
        // Handle error
        return;
    }
    switch (requestCode) {
        case PICK_CODE: {
            Uri pickedUri = data.getData();
            processPickedUri(pickedUri);
            return;
        }
        // Handle other cases
    }
}

private void processPickedUri(Uri uri) {
    File cacheFile = new File(getExternalCacheDir(), "temp");
    copy(uri, cacheFile);

    // Do normal stuff
}

private void copy(Uri uri, File toFile) {
    try {
        InputStream inputStream = getContentResolver().openInputStream(uri); // openInputStream() handles both file, and content schemes
        OutputStream outputStream = new FileOutputStream(toFile);

        byte[] bytes = new byte[65536];
        while (true) {
            int read = inputStream.read(bytes);
            if (read == -1) {
                break;
            }
            outputStream.write(bytes, 0, read);
        }

        inputStream.close();
        outputStream.close();
    } catch (IOException e) {
        // Handle error
    }
}

1.发布了隐式intent

2.通过onActivityResult接收信息,可能会被攻击者利用

3.复制数据到公开存储

隐式显式

startActivityForResult

intent action部分介绍

intent action介绍

2. Exploiting URI attacks via file scheme

同上

setResult传递了file的uri

image-20220605230841014

3. Exploiting URI attacks via content scheme

对content provider进行攻击

对uri进行路径检查,path要写全

image-20220605231518762

4. sharing activities

android.intent.action.SEND

android.intent.action.SEND_MULTIPLE

加入这些的activity有一个接受uri的操作Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);

预防:查看uri路径是否是internal

image-20220606151509933

5. Exported providers

同3

6. Gaining access to arbitrary* content providers

上周新写的

7. Local web servers

NanoHTTPD

image-20220605235716695

静态漏扫资料2:WebView

8. url验证不足

检验代码

image-20220612220246628

攻击方法:

image-20220612220255581

只检查主机

image-20220612221542949

逻辑错误

image-20220612221855421攻击者可以通过HierarchicalUri和Java反射绕过

image-20220612224059362

注意

image-20220612224242545

解决方法:

image-20220612224156085

旧版本反斜杠问题

image-20220612224932812

攻击方法

image-20220612224943970

解决方法

最小版本25以上

检查异常

验证authority的值而非host的

image-20220612225007917

Universal XSS

image-20220613030521302

攻击方法

image-20220613030537686

JavaScript代码注入

Attacks on internal URL handlers //对内部URL处理程序的攻击

WebViewClient.shouldOverrideUrlLoading(...)

该方法给应用程序提供时机,让其控制当前的WebView是否继续加载相应的URL

如果应用程序没有提供WebViewClient,默认情况下WebView会询问系统选择合适的程序处理URL。如果提供了WebViewClient,返回值为true导致当前WebView中止加载URL,返回false导致WebView继续加载当前URL

继续加载给定URL的正确方法是简单地返回false,不需要调用WebView.loadUrl(String),然后返回true

shouldOverrideUrlLoading解释

示例代码

class CustomClient extends WebViewClient {
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        Uri uri = request.getUrl();
        String url = uri.toString();
        if (url.startsWith("intent://")) {
            try {
                Intent intent = Intent.parseUri(url, 0);
                view.getContext().startActivity(intent);
            } catch (URISyntaxException e) {
            }
            return true;
        }

        String page;
        if ((page = uri.getQueryParameter("page")) != null) {
            view.evaluateJavascript("loadPage('" + page + "')", null);
            return true;
        }
        return super.shouldOverrideUrlLoading(view, request);
    }
}

攻击代码

this.webView.setWebViewClient(new CustomClient());
this.webView.loadUrl(attackerControlledUrl);
//攻击者可以通过打开 https://legitimate.com/?page=’-alert(1)- 在加载的页面上实现 XSS。

应该是shouldOverrideUrlLoading安全性有问题,如果重载写的不安全则会出问题

Attack on JavaScrpit interfaces (未写)

同web执行任意代码,待更

https://blog.oversecured.com/Android-security-checklist-webview/#recommendations

静态漏扫资料3:

arbitrary code execution via third-party package contexts

危险代码

public static void searchModules(Context context) {
    for (PackageInfo info : context.getPackageManager().getInstalledPackages(0)) {
        String packageName = info.packageName;
        if(packageName.startsWith("com.victim.module.")) {
            processModule(context, packageName);
        }
        //...
    }
}

public static void processModule(Context context, String packageName) {
    Context appContext = context.createPackageContext(packageName, CONTEXT_INCLUDE_CODE | CONTEXT_IGNORE_SECURITY);
    ClassLoader classLoader = appContext.getClassLoader();
    try {
        Object interface = classLoader.loadClass("com.victim.MainInterface").getMethod("getInterface").invoke(null);
        //...

对调用的包仅进行了开头检查,使得攻击者可以伪造包与方法进行攻击

攻击代码

package com.victim;

public class MainInterface {
    public static Object getInterface() {
        try {
            Runtime.getRuntime().exec("...attacker..controlled..command...").waitFor();
        }
        catch (Throwable th) {
        }
        return null;
    }
}

解决方法:

加入签名验证

if(packageName.startsWith("com.victim.module.")&& packageManager.checkSignatures(packageName, context.getPackageName()) == PackageManager.SIGNATURE_MATCH) {

其他知识点:

image-20220630023607783

https://blog.oversecured.com/Android-arbitrary-code-execution-via-third-party-package-contexts/

incorrect using cryptography

加密密钥生成不安全,如使用random类,对种子进行了赋值;key未进行取值直接设为0.

//1
byte[] key = new byte[128];
Random random = new Random(100);
for (int i = 0; i < 128; i++) {
    key[i] = (byte) random.nextInt(256);
}
//2
byte[] key = new byte[128];
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

https://blog.oversecured.com/Use-cryptography-in-mobile-apps-the-right-way/

权限创建未声明等级

APP创建权限时忘记声明等级,默认为normal,会导致其他app无需验证拥有权限。

Android静态扫描整理

检查组件导出情况

  1. Activity

    在没有intent filter时,默认为false;

    在有intent filter时,默认为true。

  2. Broadcast

    在没有intent filter时,默认为false;

    在有intent filter时,默认为true。

  3. Service

​ 在没有intent filter时,默认为false;

​ 在有intent filter时,默认为true。

  1. Contetnt Provider

​ 当minSdkVersion或targetSdkVersion小于16时,默认为true;

​ 大于17时,默认为false。

其中需要注意的点:

即使导出为true的组件,查看权限,如果权限为signature(申请的应用需要相同的数字签名或者为系统应用),则基本可以认为无风险;如果normal或者dangerous有一定的风险。

阿里云OSS凭证泄露风险

原理

阿里云对象存储服务(Object Storage Service,简称OSS),是阿里云对外提供的海量、安全和高可靠的云存储服务。在阿里云官方文档中明确指出:“移动终端是一个不受信任的环境,把accessKeyId和accessKeySecret直接保存在终端用来加签请求,存在极高的风险。”,一些集成了阿里云OSS的Android平台APP在使用SDK的时候只是简单复制了阿里云OSS官方测试demo代码,并未根据官方建议对访问控制策略进行设置,直接将accessKeyId和accessKeySecre内置在移动应用程序。攻击者通过对APP进行脱壳逆分析可获得这组凭证后,利用OSS管理工具(ossutil)可以远程获取其云存储的数据,并拥有对该OSS的控制权

编写规则

对特征Lcom/alibaba/sdk/android/oss/common/auth/OSSPlainTextAKSKCredentialProvider;-><init>(Ljava/lang/String; Ljava/lang/String;)V进行匹配

Intent隐式调用劫持

原理

app创建Intent时隐式传递数据到其他component时,可能会被劫持读取到传送的数据

解决方案

intent传送数据时显示传递,调用intent.seClassName(), intent.setPackage(), intent.setClass(), intent.setComponent()......

编写规则

注意需要排除LocalBroadManager,用来注册和发送intent,但只会在自己的app种传播数据,所以不需要担心劫持。

  1. 匹配启动intent:
{"Activity": ["startActivity"], "Service": ["startService", "bindService"],"BroadcastReceiver": ["sendBroadcast", "sendBroadcastAsUser", "sendOrderedBroadcast", "sendOrderedBroadcastAsUser"]}
  1. 排除显示指定:
"Landroid/content/Intent;->setComponent" 
"Landroid/content/Intent;->setPackage" 
"Landroid/content/Intent;->setClass"
  1. 查看是否为LocalBroadManager

  2. 查看参数中是否有字符串

 Intent()
 Intent(String action)
  Intent(Context context, Class cls)
  其他:Intent(Intent o)等
【2】Intent.setAction(String action)
【3】Intent.setClass(Context context, Class cls)
【4】Intent.setClassName(String packageName, String className)
【5】Intent.setClassName(Context context, String className)
【6】Intent.setComponent(ComponentName component)
【7】Intent.setPackage(String packageName)

可知,隐式特点为字符串,其他的显示方法可通过方法名排除

所以对smali中含(Ljava/lang/String; Landroid/net/Uri;)V, (Ljava/lang/String;)V的方法进行记录

Content Provider目录遍历漏洞

原理

当Provider被导出且覆写了openFile方法时,没有对Content Query Uri进行有效判断或过滤,攻击者可以利用openFile()接口进行文件目录遍历以达到访问任意可读文件的目的。

解决方案

将不必要导出的Content Provider设置为不导出,去除没有必要的openFile()接口,过滤限制跨域访问,对访问的目标文件的路径进行有效判断,设置权限来进行内部应用通过Content Provider的数据共享。

编写规则

匹配:

"openAssetFile", "openFile", "openTypedAssetFile"

去除grantUriPermission

检查是否有对路径检查的相关方法

文件全局读/写漏洞

原理

APP在创建文件时,将文件设置了全局的可读/写权限(MODE_WORLD_READABLE/MODE_WORLD_WRITEABLE)。攻击者恶意写文件内容,破坏APP的完整性,或者是攻击者恶意读取文件内容,获取敏感信息。

解决方案

创建文件时,将访问权限设置为MODE_PRIVATE

编写规则

匹配:

"SharedPreference" : "->getSharedPreferences",
"File" : "->openFileOutput",
"Database" : "->openOrCreateDatabase"

排除设置了private的情况。

Janus

该漏洞可以让攻击者绕过安卓系统的signature scheme V1签名机制,进而直接对App进行篡改。而且由于安卓系统的其他安全机制也是建立在签名和校验基础之上,该漏洞相当于绕过了安卓系统的整个安全机制。

系统解压的时候,没有先判断头部,而是直接从末尾读取进行解压;运行APK时,ART是直接通过头部判断文件类型的。由于两者使用不同的策略执行文件,解压文件从末尾开始执行,判断的签名不会改变(因为索引定位到的还是原来的文件),但是运行却是按照DEX文件去运行。校验机制存在缺失,可以绕过。

编写规则

对签名做检查,只有v1则报

本地拒绝服务

原理

Android应用使用Intent机制在组件之间传递数据,如果应用在使用getIntent(),getAction,intent.getXXXExtra()获取到空、异常或畸形数据却没有进行异常捕获,应用就会发生Crash,从而拒绝服务。

编写规则

找到导出组件

找到含有getIntent(),getAction,getExtra的方法,如果该方法有try,则安全,反之,可能不安全,查看该类是否在导出组件列表内

Webview组件远程代码执行

原理

Android API level 16 以及之前的版本存在远程代码执行安全漏洞,该漏洞源于程序没有正确限制使用WebView.addJavascriptInterface方法,远程攻击者可通过使用Java Reflection API利用该漏洞执行任意Java对象的方法,简单的说就是通过addJavascriptInterface给WebView加入一个JavaScript桥接接口,JavaScript通过调用这个接口可以直接操作本地的JAVA接口。

对于使用了Webview API:addJavaScriptInterface()的Webview,会向网页中的js导出一个Object。在JS中,可以利用这个Object和本地App的Java代码通信。由于Java支持反射,导致在JS代码中,可以利用这个导出的Object来反射调用本地代码,从而导致了任意代码执行。即JavaScript的网页可以利用App具有的权限执行任意代码。
image-20220814001921752

image-20220814001950655

image-20220814002002226

匹配规则

对api小于等于16的进行Landroid/webkit/WebView;->addJavascriptInterface匹配。

Webview隐藏风险接口未移除

原理

编写规则